| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.sling.ide.eclipse.internal.validation; |
| |
| import java.io.InputStream; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.Collection; |
| import java.util.Iterator; |
| |
| import org.apache.sling.ide.eclipse.core.internal.Activator; |
| import org.apache.sling.ide.log.Logger; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.wst.validation.ValidationResult; |
| import org.eclipse.wst.validation.ValidationState; |
| import org.eclipse.wst.validation.internal.core.ValidationException; |
| import org.eclipse.wst.validation.internal.provisional.core.IReporter; |
| import org.eclipse.wst.validation.internal.provisional.core.IValidationContext; |
| import org.eclipse.wst.xml.core.internal.validation.core.AbstractNestedValidator; |
| import org.eclipse.wst.xml.core.internal.validation.core.NestedValidatorContext; |
| import org.eclipse.wst.xml.core.internal.validation.eclipse.Validator; |
| |
| @SuppressWarnings("restriction") |
| /** Almost the standard xml validator from WST with the following deviations - missing grammar is never marked - also .content.xml is |
| * validated (the default XML validator skips all files starting with ".") */ |
| public class IgnoreMissingGrammarXmlValidator extends Validator { |
| |
| private final String GET_FILE = "getFile"; //$NON-NLS-1$ |
| private final String GET_PROJECT_FILES = "getAllFiles"; //$NON-NLS-1$ |
| private final String GET_INPUTSTREAM = "inputStream"; //$NON-NLS-1$ |
| |
| @Override |
| protected void setupValidation(NestedValidatorContext context) { |
| super.setupValidation(context); |
| // always ignore missing grammar constraints being referenced in the XML |
| indicateNoGrammar = 0; |
| } |
| |
| /** Perform the validation using version 2 of the validation framework. Copied from {@link AbstractNestedValidator#validate(IResource, |
| * int, ValidationState, IProgressMonitor). Cannot use original one as that skips resources starting with "." */ |
| @Override |
| public ValidationResult validate(IResource resource, int kind, ValidationState state, IProgressMonitor monitor) { |
| ValidationResult result = new ValidationResult(); |
| IFile file = null; |
| if (resource instanceof IFile) |
| file = (IFile) resource; |
| if (file != null && shouldValidate(file)) { |
| IReporter reporter = result.getReporter(monitor); |
| |
| NestedValidatorContext nestedcontext = getNestedContext(state, false); |
| boolean teardownRequired = false; |
| if (nestedcontext == null) { |
| // validationstart was not called, so manually setup and tear down |
| nestedcontext = getNestedContext(state, true); |
| nestedcontext.setProject(file.getProject()); |
| setupValidation(nestedcontext); |
| teardownRequired = true; |
| } else { |
| nestedcontext.setProject(file.getProject()); |
| } |
| doValidate(file, null, result, reporter, nestedcontext); |
| |
| if (teardownRequired) |
| teardownValidation(nestedcontext); |
| } |
| return result; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.wst.validation.internal.provisional.core.IValidatorJob#validateInJob(org.eclipse.wst.validation.internal.provisional.core |
| * .IValidationContext, org.eclipse.wst.validation.internal.provisional.core.IReporter) |
| * |
| * Copied from {@link AbstractNestedValidator#validateInJob(IValidationContext context, IReporter reporter). Cannot use original one as |
| * that skips resources starting with "." |
| */ |
| @Override |
| public IStatus validateInJob(IValidationContext context, IReporter reporter) throws ValidationException { |
| NestedValidatorContext nestedcontext = new NestedValidatorContext(); |
| setupValidation(nestedcontext); |
| String[] fileURIs = context.getURIs(); |
| if (fileURIs != null && fileURIs.length > 0) { |
| int numFiles = fileURIs.length; |
| for (int i = 0; i < numFiles && !reporter.isCancelled(); i++) { |
| String fileName = fileURIs[i]; |
| if (fileName != null) { |
| Object[] parms = { fileName }; |
| |
| IFile file = (IFile) context.loadModel(GET_FILE, parms); |
| if (file != null && shouldValidate(file)) { |
| nestedcontext.setProject(file.getProject()); |
| // The helper may not have a file stored in it but may have an InputStream if being |
| // called from a source other than the validation framework such as an editor. |
| if (context.loadModel(GET_INPUTSTREAM) instanceof InputStream) { |
| doValidate(file, (InputStream) context.loadModel(GET_INPUTSTREAM), null, reporter, nestedcontext); // do we need |
| // the |
| // fileName? |
| // what is int |
| // ruleGroup? |
| } else { |
| doValidate(file, null, null, reporter, nestedcontext); |
| } |
| } |
| } |
| } |
| } |
| // TODO: Is this needed? Shouldn't the framework pass the complete list? |
| // Should I know that I'm validating a project as opposed to files? |
| else { |
| Object[] parms = { getValidatorID() }; |
| Collection files = (Collection) context.loadModel(GET_PROJECT_FILES, parms); |
| // files can be null if they're outside of the workspace |
| if (files != null) { |
| Iterator iter = files.iterator(); |
| while (iter.hasNext() && !reporter.isCancelled()) { |
| IFile file = (IFile) iter.next(); |
| if (shouldValidate(file)) { |
| doValidate(file, null, null, reporter, nestedcontext); |
| } |
| } |
| } |
| } |
| |
| teardownValidation(nestedcontext); |
| if (reporter.isCancelled()) |
| return Status.CANCEL_STATUS; |
| return Status.OK_STATUS; |
| } |
| |
| /** Call the original private method named validate with the same parameters from {@link AbstractNestedValidator} through reflection. |
| * |
| * @param file |
| * @param inputstream |
| * @param result |
| * @param reporter |
| * @param context */ |
| private void doValidate(IFile file, InputStream inputstream, ValidationResult result, IReporter reporter, |
| NestedValidatorContext context) { |
| try { |
| Method method = AbstractNestedValidator.class.getDeclaredMethod("validate", IFile.class, InputStream.class, |
| ValidationResult.class, |
| IReporter.class, NestedValidatorContext.class); |
| method.setAccessible(true); |
| method.invoke(this, file, inputstream, result, reporter, context); |
| } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException |
| | SecurityException e) { |
| Logger logger = Activator.getDefault().getPluginLogger(); |
| logger.error("Failed calling validate method on AbstractNestedValidator, probably WTP version is incompatible.", e); |
| } |
| } |
| |
| /** Determine if a given file should be validated. Mostly copied from {@link AbstractNestedValidator#shouldValidate(...)} but will not |
| * skip {@code .content.xml} files. |
| * |
| * @param file The file that may be validated. |
| * @return True if the file should be validated, false otherwise. */ |
| private static boolean shouldValidate(IFile file) { |
| IResource resource = file; |
| do { |
| if (resource.isDerived() || resource.isTeamPrivateMember() || |
| !resource.isAccessible() || (resource.getName().charAt(0) == '.' && !".content.xml".equals(resource.getName()))) { |
| return false; |
| } |
| resource = resource.getParent(); |
| } while ((resource.getType() & IResource.PROJECT) == 0); |
| |
| return true; |
| } |
| |
| } |