blob: e9e9b610d976da41c20f23cd6c786c4581680f40 [file] [log] [blame]
david_williamscfdb2cd2004-11-11 08:37:49 +00001/*******************************************************************************
nitindb7573d32008-02-07 07:30:45 +00002 * Copyright (c) 2001, 2008 IBM Corporation and others.
david_williamscfdb2cd2004-11-11 08:37:49 +00003 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
amywuecebb042007-04-10 20:07:35 +00007 *
david_williamscfdb2cd2004-11-11 08:37:49 +00008 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Jens Lukowski/Innoopract - initial renaming/restructuring
11 *
12 *******************************************************************************/
13package org.eclipse.wst.sse.ui.internal.reconcile.validator;
14
15import java.util.ArrayList;
16import java.util.Arrays;
17import java.util.HashMap;
pavery46c93e72005-02-08 16:07:33 +000018import java.util.HashSet;
david_williamscfdb2cd2004-11-11 08:37:49 +000019import java.util.Iterator;
20import java.util.List;
pavery46c93e72005-02-08 16:07:33 +000021import java.util.Set;
david_williamscfdb2cd2004-11-11 08:37:49 +000022
amywu7d8efb02006-04-13 04:08:07 +000023import org.eclipse.core.resources.IFile;
amywu7d8efb02006-04-13 04:08:07 +000024import org.eclipse.core.resources.ResourcesPlugin;
25import org.eclipse.core.runtime.IPath;
26import org.eclipse.core.runtime.Path;
pavery46c93e72005-02-08 16:07:33 +000027import org.eclipse.core.runtime.Platform;
28import org.eclipse.core.runtime.content.IContentType;
29import org.eclipse.core.runtime.content.IContentTypeManager;
david_williamscfdb2cd2004-11-11 08:37:49 +000030import org.eclipse.jface.text.IDocument;
31import org.eclipse.jface.text.ITypedRegion;
32import org.eclipse.jface.text.reconciler.DirtyRegion;
33import org.eclipse.jface.text.reconciler.IReconcileResult;
34import org.eclipse.jface.text.reconciler.IReconcileStep;
nitindf8e77632005-09-07 23:49:25 +000035import org.eclipse.jface.text.source.ISourceViewer;
amywu7d8efb02006-04-13 04:08:07 +000036import org.eclipse.wst.sse.core.StructuredModelManager;
37import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
paveryb0763c02005-10-17 15:55:28 +000038import org.eclipse.wst.sse.ui.internal.IReleasable;
david_williamscfdb2cd2004-11-11 08:37:49 +000039import org.eclipse.wst.sse.ui.internal.reconcile.DocumentAdapter;
pavery1f1588d2006-02-15 20:44:54 +000040import org.eclipse.wst.sse.ui.internal.reconcile.ReconcileAnnotationKey;
paverydc8b3062005-10-24 20:43:42 +000041import org.eclipse.wst.sse.ui.internal.reconcile.StructuredTextReconcilingStrategy;
david_williamscfdb2cd2004-11-11 08:37:49 +000042import org.eclipse.wst.sse.ui.internal.reconcile.TemporaryAnnotation;
nitindb7573d32008-02-07 07:30:45 +000043import org.eclipse.wst.validation.ValidationFramework;
44import org.eclipse.wst.validation.Validator;
david_williams49d24fb2005-04-08 21:16:59 +000045import org.eclipse.wst.validation.internal.provisional.core.IValidator;
david_williamscfdb2cd2004-11-11 08:37:49 +000046
47
48/**
paveryf918eb22005-03-29 18:26:53 +000049 * Special validator strategy. Runs validator steps contributed via the
nitindb0445972006-02-16 22:19:20 +000050 * <code>org.eclipse.wst.sse.ui.extensions.sourcevalidation</code> extension
51 * point
david_williamscfdb2cd2004-11-11 08:37:49 +000052 *
53 * @author pavery
54 */
paverydc8b3062005-10-24 20:43:42 +000055public class ValidatorStrategy extends StructuredTextReconcilingStrategy {
nitindb0445972006-02-16 22:19:20 +000056
57 private String[] fContentTypeIds = null;
david_williamscfdb2cd2004-11-11 08:37:49 +000058 private List fMetaData = null;
nitindb0445972006-02-16 22:19:20 +000059 /** validator id (as declared in ext point) -> ReconcileStepForValidator * */
60 private HashMap fVidToVStepMap = null;
61
62 /*
63 * List of ValidatorMetaDatas of total scope validators that have been run
64 * since beginProcessing() was called.
65 */
66 private List fTotalScopeValidatorsAlreadyRun;
david_williamscfdb2cd2004-11-11 08:37:49 +000067
nitindf8e77632005-09-07 23:49:25 +000068 public ValidatorStrategy(ISourceViewer sourceViewer, String contentType) {
69 super(sourceViewer);
david_williamscfdb2cd2004-11-11 08:37:49 +000070 fMetaData = new ArrayList();
pavery46c93e72005-02-08 16:07:33 +000071 fContentTypeIds = calculateParentContentTypeIds(contentType);
pavery55ae4472005-02-16 23:00:16 +000072 fVidToVStepMap = new HashMap();
david_williamscfdb2cd2004-11-11 08:37:49 +000073 }
74
nitindb0445972006-02-16 22:19:20 +000075 public void addValidatorMetaData(ValidatorMetaData vmd) {
david_williamscfdb2cd2004-11-11 08:37:49 +000076 fMetaData.add(vmd);
77 }
78
nitindb0445972006-02-16 22:19:20 +000079 public void beginProcessing() {
80 if (fTotalScopeValidatorsAlreadyRun == null)
81 fTotalScopeValidatorsAlreadyRun = new ArrayList();
nitindf3f10872007-09-03 06:36:56 +000082 else
83 fTotalScopeValidatorsAlreadyRun.clear();
nitindb0445972006-02-16 22:19:20 +000084 }
85
86 /**
87 * The content type passed in should be the most specific one. TODO: This
88 * exact method is also in ValidatorMetaData. Should be in a common place.
89 *
90 * @param contentType
91 * @return
92 */
93 private String[] calculateParentContentTypeIds(String contentTypeId) {
94
95 Set parentTypes = new HashSet();
96
97 IContentTypeManager ctManager = Platform.getContentTypeManager();
98 IContentType ct = ctManager.getContentType(contentTypeId);
99 String id = contentTypeId;
100
101 while (ct != null && id != null) {
102
103 parentTypes.add(id);
104 ct = ctManager.getContentType(id);
105 if (ct != null) {
106 IContentType baseType = ct.getBaseType();
107 id = (baseType != null) ? baseType.getId() : null;
108 }
109 }
110 return (String[]) parentTypes.toArray(new String[parentTypes.size()]);
111 }
112
pavery3f791842006-02-15 21:32:25 +0000113 protected boolean canHandlePartition(String partitionType) {
david_williamscfdb2cd2004-11-11 08:37:49 +0000114 ValidatorMetaData vmd = null;
115 for (int i = 0; i < fMetaData.size(); i++) {
116 vmd = (ValidatorMetaData) fMetaData.get(i);
nitindb0445972006-02-16 22:19:20 +0000117 if (vmd.canHandlePartitionType(getContentTypeIds(), partitionType))
david_williamscfdb2cd2004-11-11 08:37:49 +0000118 return true;
119 }
120 return false;
121 }
nitindb0445972006-02-16 22:19:20 +0000122
123 protected boolean containsStep(IReconcileStep step) {
124 return fVidToVStepMap.containsValue(step);
125 }
david_williamscfdb2cd2004-11-11 08:37:49 +0000126
127 /**
david_williams4ad020f2005-04-18 08:00:30 +0000128 * @see org.eclipse.wst.sse.ui.internal.provisional.reconcile.AbstractStructuredTextReconcilingStrategy#createReconcileSteps()
david_williamscfdb2cd2004-11-11 08:37:49 +0000129 */
130 public void createReconcileSteps() {
131 // do nothing, steps are created
132 }
nitindb0445972006-02-16 22:19:20 +0000133
134 public void endProcessing() {
135 fTotalScopeValidatorsAlreadyRun.clear();
136 }
137
pavery1f1588d2006-02-15 20:44:54 +0000138 /**
139 * All content types on which this ValidatorStrategy can run
nitindb0445972006-02-16 22:19:20 +0000140 *
pavery1f1588d2006-02-15 20:44:54 +0000141 * @return
142 */
pavery46c93e72005-02-08 16:07:33 +0000143 public String[] getContentTypeIds() {
144 return fContentTypeIds;
david_williamscfdb2cd2004-11-11 08:37:49 +0000145 }
146
paverydfec4172005-11-09 21:42:30 +0000147 /**
nitindb0445972006-02-16 22:19:20 +0000148 * @param tr
149 * Partition of the region to reconcile.
150 * @param dr
151 * Dirty region representation of the typed region
paverydfec4172005-11-09 21:42:30 +0000152 */
pavery46c93e72005-02-08 16:07:33 +0000153 public void reconcile(ITypedRegion tr, DirtyRegion dr) {
nitindb7573d32008-02-07 07:30:45 +0000154 /*
155 * Abort if no workspace file is known (new validation framework does
156 * not support that scenario) or no validators have been specified
157 */
158 if (isCanceled() || fMetaData.isEmpty())
paverybaf7e522005-07-07 20:44:14 +0000159 return;
nitindb0445972006-02-16 22:19:20 +0000160
paverydfec4172005-11-09 21:42:30 +0000161 IDocument doc = getDocument();
david_williamscfdb2cd2004-11-11 08:37:49 +0000162 // for external files, this can be null
nitindb0445972006-02-16 22:19:20 +0000163 if (doc == null)
paverydfec4172005-11-09 21:42:30 +0000164 return;
nitindb0445972006-02-16 22:19:20 +0000165
paverydfec4172005-11-09 21:42:30 +0000166 String partitionType = tr.getType();
david_williamscfdb2cd2004-11-11 08:37:49 +0000167
nitindb0445972006-02-16 22:19:20 +0000168 ValidatorMetaData vmd = null;
169 List annotationsToAdd = new ArrayList();
david_williams5ce6d6c2006-05-28 23:58:12 +0000170 List stepsRanOnThisDirtyRegion = new ArrayList(1);
nitindb7573d32008-02-07 07:30:45 +0000171
172 /*
173 * Keep track of the disabled validators by source id for the V2
174 * validators.
175 */
176 Set disabledValsBySourceId = new HashSet(20);
177
178 /*
179 * Keep track of the disabled validators by class id for the v1
180 * validators.
181 */
182 Set disabledValsByClass = new HashSet(20);
183 if (getFile() != null) {
184 for (Iterator it = ValidationFramework.getDefault().getDisabledValidatorsFor(getFile()).iterator(); it.hasNext();) {
185 Validator v = (Validator) it.next();
186 IValidator iv = v.asIValidator();
187 if (iv != null && v.getSourceId() != null)
188 disabledValsBySourceId.add(v.getSourceId());
189 Validator.V1 v1 = v.asV1Validator();
190 if (v1 != null)
191 disabledValsByClass.add(v1.getId());
192 }
193 }
194
nitindb0445972006-02-16 22:19:20 +0000195 /*
196 * Loop through all of the relevant validator meta data to find
197 * supporting validators for this partition type. Don't check
198 * this.canHandlePartition() before-hand since it just loops through
199 * and calls vmd.canHandlePartitionType()...which we're already doing
200 * here anyway to find the right vmd.
201 */
202 for (int i = 0; i < fMetaData.size() && !isCanceled(); i++) {
203 vmd = (ValidatorMetaData) fMetaData.get(i);
204 if (vmd.canHandlePartitionType(getContentTypeIds(), partitionType)) {
amywu7d8efb02006-04-13 04:08:07 +0000205 /*
206 * Check if validator is enabled according to validation
207 * preferences before attempting to create/use it
208 */
nitindb7573d32008-02-07 07:30:45 +0000209 if (!disabledValsBySourceId.contains(vmd.getValidatorId()) && !disabledValsByClass.contains(vmd.getValidatorClass())) {
amywu7d8efb02006-04-13 04:08:07 +0000210 int validatorScope = vmd.getValidatorScope();
211 ReconcileStepForValidator validatorStep = null;
212 // get step for partition type
213 Object o = fVidToVStepMap.get(vmd.getValidatorId());
214 if (o != null) {
215 validatorStep = (ReconcileStepForValidator) o;
216 }
217 else {
218 // if doesn't exist, create one
219 IValidator validator = vmd.createValidator();
david_williamscfdb2cd2004-11-11 08:37:49 +0000220
amywu7d8efb02006-04-13 04:08:07 +0000221 validatorStep = new ReconcileStepForValidator(validator, validatorScope);
222 validatorStep.setInputModel(new DocumentAdapter(doc));
nitindb0445972006-02-16 22:19:20 +0000223
amywu7d8efb02006-04-13 04:08:07 +0000224 fVidToVStepMap.put(vmd.getValidatorId(), validatorStep);
225 }
nitindb0445972006-02-16 22:19:20 +0000226
amywu7d8efb02006-04-13 04:08:07 +0000227 if (!fTotalScopeValidatorsAlreadyRun.contains(vmd)) {
228 annotationsToAdd.addAll(Arrays.asList(validatorStep.reconcile(dr, dr)));
david_williams5ce6d6c2006-05-28 23:58:12 +0000229 stepsRanOnThisDirtyRegion.add(validatorStep);
nitindb0445972006-02-16 22:19:20 +0000230
amywu7d8efb02006-04-13 04:08:07 +0000231 if (validatorScope == ReconcileAnnotationKey.TOTAL) {
232 // mark this validator as "run"
233 fTotalScopeValidatorsAlreadyRun.add(vmd);
234 }
nitindb0445972006-02-16 22:19:20 +0000235 }
david_williamscfdb2cd2004-11-11 08:37:49 +0000236 }
237 }
nitindb0445972006-02-16 22:19:20 +0000238 }
239
david_williams5ce6d6c2006-05-28 23:58:12 +0000240 TemporaryAnnotation[] annotationsToRemove = getAnnotationsToRemove(dr, stepsRanOnThisDirtyRegion);
nitindb0445972006-02-16 22:19:20 +0000241 if (annotationsToRemove.length + annotationsToAdd.size() > 0)
242 smartProcess(annotationsToRemove, (IReconcileResult[]) annotationsToAdd.toArray(new IReconcileResult[annotationsToAdd.size()]));
243 }
244
245 public void release() {
246 super.release();
247 Iterator it = fVidToVStepMap.values().iterator();
248 IReconcileStep step = null;
249 while (it.hasNext()) {
250 step = (IReconcileStep) it.next();
251 if (step instanceof IReleasable)
252 ((IReleasable) step).release();
david_williamscfdb2cd2004-11-11 08:37:49 +0000253 }
254 }
255
nitindb0445972006-02-16 22:19:20 +0000256 /**
david_williamscfdb2cd2004-11-11 08:37:49 +0000257 * @see org.eclipse.wst.sse.ui.internal.reconcile.AbstractStructuredTextReconcilingStrategy#setDocument(org.eclipse.jface.text.IDocument)
258 */
259 public void setDocument(IDocument document) {
nitindb0445972006-02-16 22:19:20 +0000260
david_williamscfdb2cd2004-11-11 08:37:49 +0000261 super.setDocument(document);
nitindb0445972006-02-16 22:19:20 +0000262
pavery55ae4472005-02-16 23:00:16 +0000263 // validator steps are in "fVIdToVStepMap" (as opposed to fFirstStep >
david_williamscfdb2cd2004-11-11 08:37:49 +0000264 // next step etc...)
pavery55ae4472005-02-16 23:00:16 +0000265 Iterator it = fVidToVStepMap.values().iterator();
david_williamscfdb2cd2004-11-11 08:37:49 +0000266 IReconcileStep step = null;
267 while (it.hasNext()) {
268 step = (IReconcileStep) it.next();
269 step.setInputModel(new DocumentAdapter(document));
270 }
271 }
amywu7d8efb02006-04-13 04:08:07 +0000272
273 /**
amywu7d8efb02006-04-13 04:08:07 +0000274 * Gets IFile from current document
275 *
nitind6f360012006-05-02 18:48:59 +0000276 * @return IFile the IFile, null if no such file exists
amywu7d8efb02006-04-13 04:08:07 +0000277 */
278 private IFile getFile() {
279 IStructuredModel model = null;
280 IFile file = null;
281 try {
282 model = StructuredModelManager.getModelManager().getExistingModelForRead(getDocument());
283 if (model != null) {
284 String baseLocation = model.getBaseLocation();
285 // The baseLocation may be a path on disk or relative to the
286 // workspace root. Don't translate on-disk paths to
287 // in-workspace resources.
288 IPath basePath = new Path(baseLocation);
nitind6f360012006-05-02 18:48:59 +0000289 if (basePath.segmentCount() > 1) {
amywu7d8efb02006-04-13 04:08:07 +0000290 file = ResourcesPlugin.getWorkspace().getRoot().getFile(basePath);
nitind6f360012006-05-02 18:48:59 +0000291 /*
292 * If the IFile doesn't exist, make sure it's not
293 * returned
294 */
295 if (!file.exists())
296 file = null;
amywu7d8efb02006-04-13 04:08:07 +0000297 }
298 }
299 }
300 finally {
301 if (model != null) {
302 model.releaseFromRead();
303 }
304 }
305 return file;
306 }
david_williamscfdb2cd2004-11-11 08:37:49 +0000307}