Skip to content

Package: ValidationBuilder

ValidationBuilder

nameinstructionbranchcomplexitylinemethod
ValidationBuilder()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
build(int, Map, IProgressMonitor)
M: 4 C: 20
83%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 2 C: 7
78%
M: 0 C: 1
100%
clean(IProgressMonitor)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
configureMarkers(Bazaar.Builder)
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
configureValidation(Bazaar.Builder)
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
createBazaarBuilder(Vendor)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
createContext(IFile)
M: 0 C: 27
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
fullBuild(IProgressMonitor)
M: 4 C: 10
71%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 1 C: 3
75%
M: 0 C: 1
100%
getContentType(IFile)
M: 3 C: 13
81%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 1 C: 4
80%
M: 0 C: 1
100%
incrementalBuild(IResourceDelta, IProgressMonitor)
M: 0 C: 8
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2019 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: * EclipseSource - initial API and implementation
13: * Christian W. Damus - bugs 544499, 545418
14: ******************************************************************************/
15: package org.eclipse.emfforms.ide.internal.builder;
16:
17: import java.util.Map;
18:
19: import org.eclipse.core.resources.IFile;
20: import org.eclipse.core.resources.IMarker;
21: import org.eclipse.core.resources.IProject;
22: import org.eclipse.core.resources.IResource;
23: import org.eclipse.core.resources.IResourceDelta;
24: import org.eclipse.core.resources.IResourceDeltaVisitor;
25: import org.eclipse.core.resources.IResourceVisitor;
26: import org.eclipse.core.resources.IncrementalProjectBuilder;
27: import org.eclipse.core.runtime.CoreException;
28: import org.eclipse.core.runtime.IProgressMonitor;
29: import org.eclipse.core.runtime.SubMonitor;
30: import org.eclipse.core.runtime.content.IContentDescription;
31: import org.eclipse.core.runtime.content.IContentType;
32: import org.eclipse.emf.common.ui.MarkerHelper;
33: import org.eclipse.emf.common.util.Diagnostic;
34: import org.eclipse.emfforms.bazaar.Bazaar;
35: import org.eclipse.emfforms.bazaar.BazaarContext;
36: import org.eclipse.emfforms.bazaar.Vendor;
37: import org.eclipse.emfforms.common.Optional;
38: import org.eclipse.emfforms.ide.builder.BuilderConstants;
39: import org.eclipse.emfforms.ide.builder.MarkerHelperProvider;
40: import org.eclipse.emfforms.ide.builder.ValidationDelegate;
41: import org.eclipse.emfforms.ide.builder.ValidationDelegateProvider;
42:
43: /**
44: * Incremental builder that triggers validation on view models in the workspace.
45: */
46: public class ValidationBuilder extends IncrementalProjectBuilder {
47:
48:         /** identifier of the builder, similar to plugin.xml value. */
49:         public static final String BUILDER_ID = "org.eclipse.emfforms.ide.builder.validationBuilder"; //$NON-NLS-1$
50:
51:         /** identifier of the marker, similar to plugin.xml value. */
52:         public static final String MARKER_ID = "org.eclipse.emfforms.ide.builder.ValidationProblem"; //$NON-NLS-1$
53:
54:         /**
55:          * Initializes me.
56:          */
57:         public ValidationBuilder() {
58:                 super();
59:         }
60:
61:         @Override
62:         protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor)
63:                 throws CoreException {
64:
65:•                if (kind == FULL_BUILD) {
66:                         fullBuild(monitor);
67:                 } else {
68:                         final IResourceDelta delta = getDelta(getProject());
69:•                        if (delta == null) {
70:                                 fullBuild(monitor);
71:                         } else {
72:                                 incrementalBuild(delta, monitor);
73:                         }
74:                 }
75:                 return null;
76:         }
77:
78:         /**
79:          * Create the core bazaar builder for a bazaar that has a default vendor.
80:          * The default vendor should lose all auctions in which it is not the only bidder.
81:          *
82:          * @param <T> the product type of the bazaar
83:          * @param defaultVendor the default vendor of the bazaar's product type
84:          * @return the bazaar builder
85:          */
86:         protected <T> Bazaar.Builder<T> createBazaarBuilder(Vendor<? extends T> defaultVendor) {
87:                 return Bazaar.Builder.<T> empty().add(defaultVendor);
88:         }
89:
90:         /**
91:          * Configure the validation delegate bazaar builder. Subclasses may extend or override
92:          * to add vendors or context functions.
93:          *
94:          * @param bazaarBuilder the validation delegate bazaar builder
95:          * @return the same {@code bazaarBuilder}
96:          */
97:         protected Bazaar.Builder<ValidationDelegate> configureValidation(Bazaar.Builder<ValidationDelegate> bazaarBuilder) {
98:                 bazaarBuilder.addAll(Activator.getDefault().getValidationDelegateProviders());
99:                 return bazaarBuilder;
100:         }
101:
102:         /**
103:          * Configure the marker helper bazaar builder. Subclasses may extend or override
104:          * to add vendors or context functions.
105:          *
106:          * @param bazaarBuilder the marker helper bazaar builder
107:          * @return the same {@code bazaarBuilder}
108:          */
109:         protected Bazaar.Builder<MarkerHelper> configureMarkers(Bazaar.Builder<MarkerHelper> bazaarBuilder) {
110:                 bazaarBuilder.addAll(Activator.getDefault().getMarkerHelperProviders());
111:                 return bazaarBuilder;
112:         }
113:
114:         @Override
115:         protected void clean(IProgressMonitor monitor) throws CoreException {
116:                 // delete markers set and files created
117:                 getProject().deleteMarkers(MARKER_ID, true, IResource.DEPTH_INFINITE);
118:         }
119:
120:         /**
121:          * Runs a full build on the project.
122:          *
123:          * @param monitor the progress monitor to track the build
124:          * @throws CoreException exception in case of issues
125:          */
126:         protected void fullBuild(final IProgressMonitor monitor) throws CoreException {
127:                 try {
128:                         getProject().accept(new ResourceValidationVisitor(monitor));
129:                 } catch (final CoreException e) {
130:                         Activator.log("Error running full build", e);//$NON-NLS-1$
131:                 }
132:         }
133:
134:         /**
135:          * Runs an incremental build on the project.
136:          *
137:          * @param delta the delta on the resource that triggers this incremental build
138:          * @param monitor the progress monitor to track the build
139:          * @throws CoreException exception in case of issues
140:          */
141:         protected void incrementalBuild(IResourceDelta delta,
142:                 IProgressMonitor monitor) throws CoreException {
143:                 // the visitor does the work.
144:                 delta.accept(new DeltaValidationVisitor(monitor));
145:         }
146:
147:         /**
148:          * Create the bazaar vendor injection context for a {@code file}.
149:          *
150:          * @param file a file to be validated
151:          * @return the injection context
152:          */
153:         protected BazaarContext createContext(IFile file) {
154:                 final BazaarContext.Builder result = BazaarContext.Builder.empty();
155:                 result.put(IFile.class, file);
156:
157:                 // We have to compute this a priori because if we try to do it on demand
158:                 // via a context function, then for any file that does not have a content
159:                 // type, we will end up injecting nulls instead of failing to resolve the
160:                 // injection, which is what we would prefer. Returning IInjector.NOT_A_VALUE
161:                 // from a context function always ultimately results in a null anyways
162:                 final IContentType contentType = getContentType(file);
163:•                if (contentType != null) {
164:                         result.put(IContentType.class, contentType);
165:                         result.put(BuilderConstants.CONTENT_TYPE, contentType.getId());
166:                 }
167:
168:                 return result.build();
169:         }
170:
171:         /**
172:          * Get the content-type of a {@code file}.
173:          *
174:          * @param file a file
175:          * @return the content type, or {@code null} if it cannot be determined for some reason
176:          */
177:         protected IContentType getContentType(IFile file) {
178:                 IContentType result;
179:                 try {
180:                         final IContentDescription contentDescription = file.getContentDescription();
181:•                        result = contentDescription == null ? null : contentDescription.getContentType();
182:                 } catch (final CoreException e) {
183:                         // Unavailable or out of sync? Not interesting to validate it
184:                         result = null;
185:                 }
186:
187:                 return result;
188:         }
189:
190:         //
191:         // Nested types
192:         //
193:
194:         /**
195:          * Resource visitor for full-build validation.
196:          */
197:         abstract class ValidationVisitor {
198:
199:                 private final IProgressMonitor monitor;
200:                 private final Bazaar<ValidationDelegate> delegateBazaar;
201:                 private final Bazaar<MarkerHelper> markerHelperBazaar;
202:
203:                 /**
204:                  * Constructor.
205:                  *
206:                  * @param monitor the progress monitor
207:                  */
208:                 ValidationVisitor(IProgressMonitor monitor) {
209:                         this.monitor = monitor;
210:
211:                         delegateBazaar = configureValidation(createBazaarBuilder(ValidationDelegateProvider.NULL))
212:                                 .build();
213:                         markerHelperBazaar = configureMarkers(createBazaarBuilder(MarkerHelperProvider.DEFAULT))
214:                                 .build();
215:                 }
216:
217:                 /**
218:                  * Validate a {@code file}.
219:                  *
220:                  * @param file the file validate
221:                  * @param context the bazaar context for injection to find a validation delegate
222:                  * @param monitor the progress monitor
223:                  */
224:                 void validate(IFile file, BazaarContext context, IProgressMonitor monitor) {
225:                         // We will always at least get the null instance
226:                         final ValidationDelegate delegate = delegateBazaar.createProduct(context);
227:
228:                         final SubMonitor sub = SubMonitor.convert(monitor, 1);
229:                         try {
230:                                 final Optional<Diagnostic> diagnostics = delegate.validate(file, sub.newChild(1));
231:
232:                                 // If there isn't an OK diagnostic, then nothing was validated, so don't
233:                                 // clear existing markers
234:                                 if (diagnostics.isPresent()) {
235:                                         final MarkerHelper markerHelper = markerHelperBazaar.createProduct(context);
236:                                         final Diagnostic diagnostic = diagnostics.get();
237:                                         markerHelper.deleteMarkers(file);
238:
239:                                         // create markers only if severity >= Warning
240:                                         if (diagnostic.getSeverity() >= IMarker.SEVERITY_WARNING) {
241:                                                 markerHelper.createMarkers(diagnostic);
242:                                         }
243:                                 }
244:                         } catch (final CoreException ex) {
245:                                 Activator.log("Errors while creating markers on file " + file, ex);//$NON-NLS-1$
246:                         } finally {
247:                                 sub.done();
248:                         }
249:                 }
250:
251:                 /**
252:                  * Get the progress monitor.
253:                  *
254:                  * @return the progress monitor
255:                  */
256:                 final IProgressMonitor getMonitor() {
257:                         return monitor;
258:                 }
259:
260:         }
261:
262:         /**
263:          * Resource delta visitor for incremental-build validation.
264:          */
265:         class DeltaValidationVisitor extends ValidationVisitor implements IResourceDeltaVisitor {
266:
267:                 /**
268:                  * Constructor.
269:                  *
270:                  * @param monitor the progress monitor
271:                  */
272:                 DeltaValidationVisitor(IProgressMonitor monitor) {
273:                         super(monitor);
274:                 }
275:
276:                 @Override
277:                 public boolean visit(IResourceDelta delta) throws CoreException {
278:                         switch (delta.getKind()) {
279:                         case IResourceDelta.ADDED:
280:                         case IResourceDelta.CHANGED:
281:                                 // handle added or changed resource
282:                                 final IResource resource = delta.getResource();
283:                                 switch (resource.getType()) {
284:                                 case IResource.FILE:
285:                                         final IFile file = (IFile) resource;
286:                                         final BazaarContext context = createContext(file);
287:                                         validate(file, context, getMonitor());
288:                                         break;
289:                                 default:
290:                                         // Nothing to do for other kinds of resource
291:                                 }
292:                                 break;
293:                         case IResourceDelta.REMOVED:
294:                                 // handle removed resource
295:                                 break;
296:                         default:
297:                                 break;
298:                         }
299:                         // return true to continue visiting children.
300:                         return true;
301:                 }
302:         }
303:
304:         /**
305:          * Resource visitor for full-build validation.
306:          */
307:         class ResourceValidationVisitor extends ValidationVisitor implements IResourceVisitor {
308:
309:                 /**
310:                  * Constructor.
311:                  *
312:                  * @param monitor the progress monitor
313:                  */
314:                 ResourceValidationVisitor(IProgressMonitor monitor) {
315:                         super(monitor);
316:                 }
317:
318:                 @Override
319:                 public boolean visit(IResource resource) {
320:                         boolean result;
321:
322:                         switch (resource.getType()) {
323:                         case IResource.FILE:
324:                                 final IFile file = (IFile) resource;
325:                                 final BazaarContext context = createContext(file);
326:                                 validate(file, context, getMonitor());
327:                                 result = false; // No children, anyways
328:                                 break;
329:                         default:
330:                                 // return true to continue visiting children.
331:                                 result = true;
332:                                 break;
333:                         }
334:
335:                         return result;
336:                 }
337:         }
338:
339: }