Skip to content

Package: PreSetValidationServiceImpl$DynamicLoosePatternEValidator

PreSetValidationServiceImpl$DynamicLoosePatternEValidator

nameinstructionbranchcomplexitylinemethod
PreSetValidationServiceImpl.DynamicLoosePatternEValidator(PreSetValidationServiceImpl, EObjectValidator, EDataType)
M: 0 C: 11
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
validateSchemaConstraints(EDataType, Object, DiagnosticChain, Map)
M: 0 C: 27
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 5
100%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2017 EclipseSource Muenchen GmbH and others.
3: *
4: * All rights reserved. This program and the accompanying materials
5: * are made available under the terms of the Eclipse Public License 2.0
6: * which accompanies this distribution, and is available at
7: * https://www.eclipse.org/legal/epl-2.0/
8: *
9: * SPDX-License-Identifier: EPL-2.0
10: *
11: * Contributors:
12: * Edgar Mueller - initial API and implementation
13: ******************************************************************************/
14: package org.eclipse.emfforms.internal.common.prevalidation;
15:
16: import java.util.LinkedHashMap;
17: import java.util.LinkedHashSet;
18: import java.util.List;
19: import java.util.Map;
20: import java.util.Set;
21: import java.util.regex.Pattern;
22:
23: import org.eclipse.emf.common.util.BasicDiagnostic;
24: import org.eclipse.emf.common.util.Diagnostic;
25: import org.eclipse.emf.common.util.DiagnosticChain;
26: import org.eclipse.emf.common.util.Enumerator;
27: import org.eclipse.emf.ecore.EClassifier;
28: import org.eclipse.emf.ecore.EDataType;
29: import org.eclipse.emf.ecore.EEnum;
30: import org.eclipse.emf.ecore.EEnumLiteral;
31: import org.eclipse.emf.ecore.ENamedElement;
32: import org.eclipse.emf.ecore.EStructuralFeature;
33: import org.eclipse.emf.ecore.EValidator;
34: import org.eclipse.emf.ecore.EcorePackage;
35: import org.eclipse.emf.ecore.util.Diagnostician;
36: import org.eclipse.emf.ecore.util.EObjectValidator;
37: import org.eclipse.emf.ecore.util.EObjectValidator.DynamicEDataTypeValidator;
38: import org.eclipse.emf.ecore.util.EcoreUtil;
39: import org.eclipse.emf.ecore.util.ExtendedMetaData;
40: import org.eclipse.emfforms.common.Optional;
41: import org.eclipse.emfforms.spi.common.validation.IFeatureConstraint;
42: import org.eclipse.emfforms.spi.common.validation.PreSetValidationService;
43: import org.osgi.framework.BundleContext;
44: import org.osgi.service.component.annotations.Activate;
45: import org.osgi.service.component.annotations.Component;
46: import org.osgi.service.component.annotations.Deactivate;
47:
48: /**
49: * Implementation of the {@link PreSetValidationService}.
50: *
51: * @author emueller
52: *
53: */
54: @Component(name = "PreSetValidationServiceImpl", service = PreSetValidationService.class)
55: public class PreSetValidationServiceImpl implements PreSetValidationService {
56:
57:         private static final String LOOSE_PATTERN_KEY = "loosePattern"; //$NON-NLS-1$
58:         private static final String LOOSE_MIN_LENGTH = "looseMinLength"; //$NON-NLS-1$
59:         private static final String MULTI_LITERAL_SEP = "|"; //$NON-NLS-1$
60:         private static final String ESCAPED_MULTI_LITERAL_SEP = "\\|"; //$NON-NLS-1$
61:
62:         private Map<ENamedElement, Set<IFeatureConstraint>> constraints = new LinkedHashMap<>();
63:
64:         @Override
65:         public Diagnostic validate(final EStructuralFeature eStructuralFeature, Object value) {
66:                 return validate(eStructuralFeature, value, null);
67:         }
68:
69:         @Override
70:         public Diagnostic validate(final EStructuralFeature eStructuralFeature, Object value, Map<Object, Object> context) {
71:                 return validate((eDataType, innerValue, diagnostics, innerContext) -> {
72:                         EValidator validator = EValidator.Registry.INSTANCE
73:                                 .getEValidator(eStructuralFeature.getEType().getEPackage());
74:                         if (validator == null) {
75:                                 validator = new EObjectValidator();
76:                         }
77:                         return validator.validate(eDataType, innerValue, diagnostics, innerContext);
78:                 },
79:                         eStructuralFeature,
80:                         value,
81:                         context);
82:         }
83:
84:         /**
85:          * {@inheritDoc}
86:          *
87:          * @see org.eclipse.emfforms.spi.common.validation.PreSetValidationService#validateLoose(org.eclipse.emf.ecore.EStructuralFeature,
88:          * java.lang.Object)
89:          */
90:         @Override
91:         public Diagnostic validateLoose(EStructuralFeature eStructuralFeature, Object value) {
92:                 final EClassifier eType = eStructuralFeature.getEType();
93:
94:                 if (!(eType instanceof EDataType) || ((EDataType) eType).getEPackage() == EcorePackage.eINSTANCE) {
95:                         return new BasicDiagnostic();
96:                 }
97:
98:                 return validate(
99:                         new DynamicLoosePatternEValidator(new LooseEValidator(), (EDataType) eType),
100:                         eStructuralFeature,
101:                         value,
102:                         null);
103:         }
104:
105:         @SuppressWarnings("unchecked")
106:         private Diagnostic validate(PreSetValidator validator, EStructuralFeature eStructuralFeature, Object value,
107:                 Map<Object, Object> context) {
108:                 final EClassifier eType = eStructuralFeature.getEType();
109:
110:                 BasicDiagnostic diagnostics = new BasicDiagnostic();
111:
112:                 if (eType instanceof EDataType && ((EDataType) eType).getEPackage() != EcorePackage.eINSTANCE) {
113:
114:                         final EDataType eDataType = (EDataType) eType;
115:                         diagnostics = Diagnostician.INSTANCE.createDefaultDiagnostic(eDataType, value);
116:
117:                         boolean skipValidator = false;
118:
119:                         // try to validate given value as enum literal
120:                         if (eDataType instanceof EEnum && value instanceof String) {
121:                                 if (validateEEnum((EEnum) eDataType, (String) value)) {
122:                                         skipValidator = true;
123:                                 }
124:                         } else if (eDataType instanceof EEnum && value instanceof List<?>) {
125:                                 try {
126:                                         if (validateEEnum((EEnum) eDataType, (List<Enumerator>) value)) {
127:                                                 skipValidator = true;
128:                                         }
129:                                 } catch (final ClassCastException ex) {
130:                                         // ignore and continue with regular validation
131:                                 }
132:                         }
133:
134:                         if (validator != null && !skipValidator) {
135:                                 validator.validate(eDataType, value, diagnostics, context);
136:                         }
137:
138:                 }
139:
140:                 executeValidators(diagnostics, constraints.get(eType),
141:                         eStructuralFeature, value, context);
142:
143:                 executeValidators(diagnostics, constraints.get(eStructuralFeature),
144:                         eStructuralFeature, value, context);
145:
146:                 return diagnostics;
147:         }
148:
149:         private static boolean validateEEnum(final EEnum eEnum, final String valueString) {
150:                 if (valueString.contains(MULTI_LITERAL_SEP)) {
151:                         boolean isValid = true;
152:                         final String[] literals = valueString.split(ESCAPED_MULTI_LITERAL_SEP);
153:                         for (final String literal : literals) {
154:                                 isValid &= validateLiteral(eEnum, literal.trim());
155:                         }
156:                         return isValid;
157:                 }
158:                 return validateLiteral(eEnum, valueString);
159:         }
160:
161:         private static boolean validateEEnum(final EEnum eEnum, final List<Enumerator> enumerators) {
162:                 boolean isValid = true;
163:                 for (final Enumerator enumerator : enumerators) {
164:                         isValid &= validateLiteral(eEnum, enumerator.getLiteral());
165:                 }
166:                 return isValid;
167:         }
168:
169:         private static Optional<String> findLooseConstraint(EDataType eDataType, String looseConstrainKey) {
170:                 return Optional
171:                         .ofNullable(EcoreUtil.getAnnotation(eDataType, ExtendedMetaData.ANNOTATION_URI, looseConstrainKey));
172:         }
173:
174:         private static boolean validateLiteral(EEnum eEnum, String literal) {
175:                 for (final EEnumLiteral enumLiteral : eEnum.getELiterals()) {
176:                         if (literal.equals(enumLiteral.getLiteral())) {
177:                                 return true;
178:                         }
179:                 }
180:
181:                 return false;
182:         }
183:
184:         private static void executeValidators(BasicDiagnostic diagnostics, Set<IFeatureConstraint> constraints,
185:                 EStructuralFeature eStructuralFeature, Object value, Map<Object, Object> context) {
186:
187:                 if (constraints == null) {
188:                         return;
189:                 }
190:
191:                 for (final IFeatureConstraint constraint : constraints) {
192:                         final Diagnostic result = constraint.validate(eStructuralFeature, value, context);
193:                         if (result.getSeverity() != Diagnostic.OK) {
194:                                 diagnostics.add(result);
195:                         }
196:                 }
197:
198:         }
199:
200:         @Override
201:         public void addConstraintValidator(ENamedElement element, IFeatureConstraint constraint) {
202:                 constraints.computeIfAbsent(element, e -> new LinkedHashSet<>()).add(constraint);
203:         }
204:
205:         /**
206:          * Called by the framework when the component gets activated.
207:          *
208:          * @param bundleContext The {@link BundleContext}
209:          */
210:         @Activate
211:         protected void activate(BundleContext bundleContext) {
212:                 constraints = new LinkedHashMap<>();
213:         }
214:
215:         /**
216:          * Called by the framework when the component gets deactivated.
217:          *
218:          * @param bundleContext The {@link BundleContext}
219:          */
220:         @Deactivate
221:         protected void deactivate(BundleContext bundleContext) {
222:                 constraints = null;
223:         }
224:
225:         /**
226:          * An {@link EObjectValidator} that considers loose constraints of any annotation details entry.
227:          *
228:          */
229:         class LooseEValidator extends EObjectValidator implements PreSetValidator {
230:                 /**
231:                  * {@inheritDoc}
232:                  *
233:                  * @see org.eclipse.emf.ecore.util.EObjectValidator#validatePattern(org.eclipse.emf.ecore.EDataType,
234:                  * java.lang.Object, org.eclipse.emf.ecore.EValidator.PatternMatcher[][],
235:                  * org.eclipse.emf.common.util.DiagnosticChain, java.util.Map)
236:                  */
237:                 @Override
238:                 protected boolean validatePattern(EDataType eDataType, Object value, PatternMatcher[][] patterns,
239:                         DiagnosticChain diagnostics, Map<Object, Object> context) {
240:
241:                         final Optional<String> loosePattern = findLooseConstraint(eDataType, LOOSE_PATTERN_KEY);
242:
243:                         if (loosePattern.isPresent()) {
244:                                 return super.validatePattern(eDataType, value, new PatternMatcher[][] { {
245:                                         v -> Pattern.matches(loosePattern.get(), v)
246:                                 } }, diagnostics, context);
247:                         }
248:
249:                         return super.validatePattern(eDataType, value, patterns, diagnostics, context);
250:                 }
251:         }
252:
253:         /**
254:          * An {@link DynamicEDataTypeValidator} that considers loose constraints of any annotation details entry.
255:          *
256:          */
257:         class DynamicLoosePatternEValidator extends DynamicEDataTypeValidator implements PreSetValidator {
258:
259:                 /**
260:                  * Constructor.
261:                  *
262:                  * @param eObjectValidator an instance of an {@link EObjectValidator}
263:                  * @param eDataType the {@link EDataType} to be validated
264:                  */
265:                 DynamicLoosePatternEValidator(EObjectValidator eObjectValidator, EDataType eDataType) {
266:                         eObjectValidator.super(eDataType);
267:                 }
268:
269:                 /**
270:                  * {@inheritDoc}
271:                  *
272:                  * @see org.eclipse.emf.ecore.util.EObjectValidator.DynamicEDataTypeValidator#validateSchemaConstraints(org.eclipse.emf.ecore.EDataType,
273:                  * java.lang.Object, org.eclipse.emf.common.util.DiagnosticChain, java.util.Map)
274:                  */
275:                 @Override
276:                 protected boolean validateSchemaConstraints(EDataType eDataType, Object value, DiagnosticChain diagnostics,
277:                         Map<Object, Object> context) {
278:
279:                         final Optional<String> looseMinLength = findLooseConstraint(eDataType, LOOSE_MIN_LENGTH);
280:
281:•                        if (looseMinLength.isPresent()) {
282:                                 effectiveMinLength = Integer.parseInt(looseMinLength.get());
283:                                 super.validateSchemaConstraints(eDataType, value, diagnostics, context);
284:                         }
285:
286:                         return super.validateSchemaConstraints(eDataType, value, diagnostics, context);
287:                 }
288:         }
289: }