/******************************************************************************* * Copyright (c) 2015-2017 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.batch.internal.core.validation; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IType; import org.eclipse.jface.text.IRegion; import org.eclipse.wst.sse.core.StructuredModelManager; import org.eclipse.wst.sse.core.internal.provisional.IModelManager; import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; 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.validation.internal.provisional.core.IValidator; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMAttr; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; import org.jboss.tools.batch.core.BatchArtifactType; import org.jboss.tools.batch.core.BatchConstants; import org.jboss.tools.batch.core.BatchCorePlugin; import org.jboss.tools.batch.core.IBatchArtifact; import org.jboss.tools.batch.core.IBatchProject; import org.jboss.tools.batch.internal.core.impl.BatchProject; import org.jboss.tools.batch.internal.core.impl.BatchProjectFactory; import org.jboss.tools.batch.internal.core.preferences.BatchSeverityPreferences; import org.jboss.tools.common.EclipseUtil; import org.jboss.tools.common.java.ParametedType; import org.jboss.tools.common.text.ITextSourceReference; import org.jboss.tools.common.validation.ContextValidationHelper; import org.jboss.tools.common.validation.EditorValidationContext; import org.jboss.tools.common.validation.IPreferenceInfo; import org.jboss.tools.common.validation.IProjectValidationContext; import org.jboss.tools.common.validation.IStringValidator; import org.jboss.tools.common.validation.ITypedReporter; import org.jboss.tools.common.validation.IValidatingProjectSet; import org.jboss.tools.common.validation.IValidatingProjectTree; import org.jboss.tools.common.validation.PreferenceInfoManager; import org.jboss.tools.common.validation.ValidatorManager; import org.jboss.tools.common.validation.internal.ProjectValidationContext; import org.jboss.tools.common.validation.internal.SimpleValidatingProjectTree; import org.jboss.tools.common.validation.internal.ValidatingProjectSet; import org.jboss.tools.common.xml.XMLUtilities; import org.jboss.tools.jst.web.kb.IKbProject; import org.jboss.tools.jst.web.kb.KbProjectFactory; import org.jboss.tools.jst.web.kb.WebKbPlugin; import org.jboss.tools.jst.web.kb.internal.KbBuilder; import org.jboss.tools.jst.web.kb.internal.validation.KBValidator; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; /** * * @author Viacheslav Kabanovich * @author Jeff Maury * */ public class BatchValidator extends KBValidator implements BatchConstants, IStringValidator { public static final String ID = "org.jboss.tools.batch.validator.BatchValidator"; //$NON-NLS-1$ public static String SHORT_ID = "batch-verification"; //$NON-NLS-1$ public static final String PREFERENCE_PAGE_ID = "org.jboss.tools.batch.ui.preferences.BatchValidationPreferencePage"; //$NON-NLS-1$ public static final String PROPERTY_PAGE_ID = "org.jboss.tools.batch.ui.propertyPages.BatchValidationPreferencePage"; //$NON-NLS-1$ public static final int BATCHLET_IS_NOT_FOUND_ID = 1; public static final int JOB_LISTENER_IS_NOT_FOUND_ID = 2; public static final int STEP_LISTENER_IS_NOT_FOUND_ID = 3; public static final int DECIDER_IS_NOT_FOUND_ID = 4; public static final int CHECKPOINT_ALGORITHM_IS_NOT_FOUND_ID = 5; public static final int ITEM_READER_IS_NOT_FOUND_ID = 6; public static final int ITEM_WRITER_IS_NOT_FOUND_ID = 7; public static final int ITEM_PROCESSOR_IS_NOT_FOUND_ID = 8; public static final int MAPPER_IS_NOT_FOUND_ID = 9; public static final int ANALYZER_IS_NOT_FOUND_ID = 10; public static final int COLLECTOR_IS_NOT_FOUND_ID = 11; public static final int REDUCER_IS_NOT_FOUND_ID = 12; String projectName; Map<IProject, IProjectValidationContext> contexts = new HashMap<IProject, IProjectValidationContext>(); public BatchValidator() {} @Override protected String getPreference(IProject project, String preferenceKey) { return BatchSeverityPreferences.getInstance().getProjectPreference(project, preferenceKey); } @Override public int getMaxNumberOfMarkersPerFile(IProject project) { return BatchSeverityPreferences.getMaxNumberOfProblemMarkersPerFile(project); } @Override public void init(IProject project, ContextValidationHelper validationHelper, IProjectValidationContext context, IValidator manager, IReporter reporter) { super.init(project, validationHelper, context, manager, reporter); setAsYouTypeValidation(false); projectName = project.getName(); contexts.clear(); } @Override public String getId() { return ID; } @Override public String getBuilderId() { return KbBuilder.BUILDER_ID; } @Override public IValidatingProjectTree getValidatingProjects(IProject project) { IProjectValidationContext rootContext = contexts.get(project); if(rootContext == null) { IKbProject kb = KbProjectFactory.getKbProject(project, true); if(kb != null) { rootContext = kb.getValidationContext(); } else { rootContext = new ProjectValidationContext(); } contexts.put(project, rootContext); } Set<IProject> projects = new HashSet<IProject>(); projects.add(project); IValidatingProjectSet projectSet = new ValidatingProjectSet(project, projects, rootContext); return new SimpleValidatingProjectTree(projectSet); } @Override public boolean shouldValidate(IProject project) { return shouldValidate(project, false); } @Override public boolean shouldValidateAsYouType(IProject project) { return shouldValidate(project, true); } public boolean shouldValidate(IProject project, boolean asYouType) { try { return project.isAccessible() && BatchCorePlugin.getBatchProject(project, true) != null && isEnabled(project) && (asYouType || validateBuilderOrder(project)); } catch (CoreException e) { BatchCorePlugin.pluginLog().logError(e); } return false; } /** * This method is present for completeness sake. Currently, Batch validat * @param project * @return * @throws CoreException */ private boolean validateBuilderOrder(IProject project) throws CoreException { return true; } @Override public IStatus validate(Set<IFile> changedFiles, IProject project, ContextValidationHelper validationHelper, IProjectValidationContext context, ValidatorManager manager, IReporter reporter) throws ValidationException { init(project, validationHelper, context, manager, reporter); IBatchProject batchProject = BatchProjectFactory.getBatchProject(project, true); Set<IPath> resourcesToClean = new HashSet<IPath>(); // Resource which we should remove from validation context for (IFile file: changedFiles) { resourcesToClean.add(file.getFullPath()); } changedFiles = collectFiles(project, changedFiles, context); for(IFile file: changedFiles) { removeAllMessagesFromResource(file); resourcesToClean.add(file.getFullPath()); } getValidationContext().removeLinkedCoreResources(SHORT_ID, resourcesToClean); Set<IFile> batchJobs = batchProject.getDeclaredBatchJobs(); for (IFile file: changedFiles) { if(batchJobs.contains(file)) { validateJobFile(batchProject, file); } //TODO Java } cleanSavedMarkers(); return OK_STATUS; } @Override public IStatus validateAll(IProject project, ContextValidationHelper validationHelper, IProjectValidationContext context, ValidatorManager manager, IReporter reporter) throws ValidationException { init(project, validationHelper, context, manager, reporter); displaySubtask(BatchValidationMessages.VALIDATING_PROJECT, new String[]{projectName}); IBatchProject batchProject = BatchProjectFactory.getBatchProject(project, true); if(batchProject != null) { Set<IFile> batchJobs = batchProject.getDeclaredBatchJobs(); for (IFile file: batchJobs) { validateJobFile(batchProject, file); } //TODO Java } cleanSavedMarkers(); return OK_STATUS; } @Override public void validate(IValidator validatorManager, IProject rootProject, Collection<IRegion> dirtyRegions, IValidationContext helper, IReporter reporter, EditorValidationContext validationContext, IProjectValidationContext projectContext, IFile file) { ContextValidationHelper validationHelper = new ContextValidationHelper(); validationHelper.setProject(rootProject); validationHelper.setValidationContextManager(validationContext); init(rootProject, validationHelper, projectContext, validatorManager, reporter); setAsYouTypeValidation(true); asYouTypeTimestamp++; this.document = validationContext.getDocument(); IBatchProject batchProject = BatchCorePlugin.getBatchProject(file.getProject(), true); if(batchProject != null && batchProject.getDeclaredBatchJobs().contains(file)) { validateJobFile(batchProject, file); } // TODO other kinds of file if(reporter instanceof ITypedReporter) { ((ITypedReporter)reporter).addTypeForFile(getProblemType()); } disableProblemAnnotations(new IRegion() { @Override public int getOffset() { return 0; } @Override public int getLength() { return document.getLength(); } }, reporter); } private void validateJobFile(IBatchProject batchProject, IFile file) { IModelManager manager = StructuredModelManager.getModelManager(); if(manager != null) { IStructuredModel model = null; try { model = file != null ? manager.getModelForRead(file) : manager.getExistingModelForRead(document); if (model instanceof IDOMModel) { IDOMModel domModel = (IDOMModel) model; IDOMDocument document = domModel.getDocument(); if(document != null) { Element element = document.getDocumentElement(); if(element != null && TAG_JOB.equals(element.getNodeName())) { validateJobElement(batchProject, file, element); } } } } catch (CoreException e) { WebKbPlugin.getDefault().logError(e); } catch (IOException e) { WebKbPlugin.getDefault().logError(e); } finally { if (model != null) { model.releaseFromRead(); } } } } IMarker addProblem(String message, String preferenceKey, Element element, String attr, IFile file, int quickfixId) { SimpleReference ref = new SimpleReference(element, attr, file); if(quickfixId == -1) { return addProblem(message, preferenceKey, new String[]{element.getAttribute(attr).trim()}, ref.getLength(), ref.getStartPosition(), file); } else { return addProblem(message, preferenceKey, new String[]{element.getAttribute(attr).trim()}, ref.getLength(), ref.getStartPosition(), file, quickfixId); } } private void validateJobElement(IBatchProject batchProject, IFile file, Element job) { ContextProperties cp = new ContextProperties(null, job, file); String restartable = job.getAttribute(ATTR_RESTARTABLE); if(restartable != null && restartable.trim().length() > 0) { if(!"true".equals(restartable) && !"false".equals(restartable) && !restartable.startsWith("#{")) { addProblem(BatchValidationMessages.JOB_RESTARTABLE_IS_NOT_BOOLEAN, BatchSeverityPreferences.INVALID_JOB_RESTARTABLE, job, ATTR_RESTARTABLE, file, -1); } } Element listeners = XMLUtilities.getUniqueChild(job, TAG_LISTENERS); if(listeners != null) { for (Element listener: XMLUtilities.getChildren(listeners, TAG_LISTENER)) { validateRefAndProperties(batchProject, file, cp, listener, BatchArtifactType.JOB_LISTENER, BatchValidationMessages.JOB_LISTENER_IS_NOT_FOUND, BatchValidationMessages.JOB_LISTENER_IS_EXPECTED, JOB_LISTENER_IS_NOT_FOUND_ID); } } //Job as flow has children decision, flow, split, step. validateFlowElement(batchProject, file, cp, job, null); cp.complete(null); } static String[] EXECUTION_ELEMENTS = {TAG_DECISION, TAG_FLOW, TAG_SPLIT, TAG_STEP}; private void validateFlowElement(IBatchProject batchProject, IFile file, ContextProperties cp, Element flow, JobTransitionsValidator jobTransitions) { TransitionsValidator transitionValidator = null; if(jobTransitions == null) { transitionValidator = jobTransitions = new JobTransitionsValidator(this); } else { transitionValidator = new TransitionsValidator(this, jobTransitions); } for (String tag: EXECUTION_ELEMENTS) { for (Element decision: XMLUtilities.getChildren(flow, tag)) { transitionValidator.addFlowElement(decision); } } transitionValidator.validate(file); for (Element decision: XMLUtilities.getChildren(flow, TAG_DECISION)) { validateDecisionElement(batchProject, file, cp, decision); } for (Element flow1: XMLUtilities.getChildren(flow, TAG_FLOW)) { validateFlowElement(batchProject, file, cp, flow1, jobTransitions); } for (Element split: XMLUtilities.getChildren(flow, TAG_SPLIT)) { validateFlowElement(batchProject, file, cp, split, jobTransitions); // for (Element flow1: XMLUtilities.getChildren(split, TAG_FLOW)) { // validateFlowElement(batchProject, file, cp, flow1, jobTransitions); // } } for (Element step: XMLUtilities.getChildren(flow, TAG_STEP)) { validateStepElement(batchProject, file, cp, step); } } private void validateStepElement(IBatchProject batchProject, IFile file, ContextProperties cp, Element step) { ContextProperties cp1 = new ContextProperties(cp, step, file); Element batchlet = XMLUtilities.getUniqueChild(step, TAG_BATCHLET); Element chunk = XMLUtilities.getUniqueChild(step, TAG_CHUNK); if(batchlet != null) { validateBatchletElement(batchProject, file, cp1, batchlet); } else if(chunk != null) { validateChunkElement(batchProject, file, cp1, chunk); } Element partition = XMLUtilities.getUniqueChild(step, TAG_PARTITION); if(partition != null) { validatePartitionElement(batchProject, file, cp1, partition); } Element listeners = XMLUtilities.getUniqueChild(step, TAG_LISTENERS); if(listeners != null) { for (Element listener: XMLUtilities.getChildren(listeners, TAG_LISTENER)) { String ref = listener.getAttribute(ATTR_REF); if(ref != null && ref.trim().length() > 0) { Collection<IBatchArtifact> as = batchProject.getArtifacts(ref.trim()); if(as.isEmpty()) { addProblem(BatchValidationMessages.STEP_LISTENER_IS_NOT_FOUND, BatchSeverityPreferences.UNKNOWN_ARTIFACT_NAME, listener, ATTR_REF, file, STEP_LISTENER_IS_NOT_FOUND_ID); } else { IBatchArtifact a = as.iterator().next(); boolean isCorrectType = (chunk != null) ? a.getArtifactType().getTag().equals(TAG_STEP) : a.getArtifactType().equals(BatchArtifactType.STEP_LISTENER); if(!isCorrectType) { addProblem(BatchValidationMessages.STEP_LISTENER_IS_EXPECTED, BatchSeverityPreferences.WRONG_ARTIFACT_TYPE, listener, ATTR_REF, file, -1); } validateProperties(batchProject, file, cp1, listener, a); } } else if (listener.hasAttribute(ATTR_REF)) { addProblem(BatchValidationMessages.STEP_LISTENER_IS_EXPECTED, BatchSeverityPreferences.EMPTY_REFERENCE, listener, ATTR_REF, file, -1); } } } cp1.complete(null); } private void validatePartitionElement(IBatchProject batchProject, IFile file, ContextProperties cp, Element partition) { validateChildRefAndProperties(batchProject, file, cp, partition, BatchArtifactType.PARTITION_MAPPER, BatchValidationMessages.MAPPER_IS_NOT_FOUND, BatchValidationMessages.MAPPER_IS_EXPECTED, MAPPER_IS_NOT_FOUND_ID); validateChildRefAndProperties(batchProject, file, cp, partition, BatchArtifactType.PARTITION_ANALYZER, BatchValidationMessages.ANALYZER_IS_NOT_FOUND, BatchValidationMessages.ANALYZER_IS_EXPECTED, ANALYZER_IS_NOT_FOUND_ID); validateChildRefAndProperties(batchProject, file, cp, partition, BatchArtifactType.PARTITION_COLLECTOR, BatchValidationMessages.COLLECTOR_IS_NOT_FOUND, BatchValidationMessages.COLLECTOR_IS_EXPECTED, COLLECTOR_IS_NOT_FOUND_ID); validateChildRefAndProperties(batchProject, file, cp, partition, BatchArtifactType.PARTITION_REDUCER, BatchValidationMessages.REDUCER_IS_NOT_FOUND, BatchValidationMessages.REDUCER_IS_EXPECTED, REDUCER_IS_NOT_FOUND_ID); } private void validateDecisionElement(IBatchProject batchProject, IFile file, ContextProperties cp, Element decision) { validateRefAndProperties(batchProject, file, cp, decision, BatchArtifactType.DECIDER, BatchValidationMessages.DECIDER_IS_NOT_FOUND, BatchValidationMessages.DECIDER_IS_EXPECTED, DECIDER_IS_NOT_FOUND_ID); } private void validateBatchletElement(IBatchProject batchProject, IFile file, ContextProperties cp, Element batchlet) { validateRefAndProperties(batchProject, file, cp, batchlet, BatchArtifactType.BATCHLET, BatchValidationMessages.BATCHLET_IS_NOT_FOUND, BatchValidationMessages.BATCHLET_IS_EXPECTED, BATCHLET_IS_NOT_FOUND_ID); } private void validateChunkElement(IBatchProject batchProject, IFile file, ContextProperties cp, Element chunk) { //Reader validateChildRefAndProperties(batchProject, file, cp, chunk, BatchArtifactType.ITEM_READER, BatchValidationMessages.READER_IS_NOT_FOUND, BatchValidationMessages.READER_IS_EXPECTED, ITEM_READER_IS_NOT_FOUND_ID); //Writer validateChildRefAndProperties(batchProject, file, cp, chunk, BatchArtifactType.ITEM_WRITER, BatchValidationMessages.WRITER_IS_NOT_FOUND, BatchValidationMessages.WRITER_IS_EXPECTED, ITEM_WRITER_IS_NOT_FOUND_ID); //Processor validateChildRefAndProperties(batchProject, file, cp, chunk, BatchArtifactType.ITEM_PROCESSOR, BatchValidationMessages.PROCESSOR_IS_NOT_FOUND, BatchValidationMessages.PROCESSOR_IS_EXPECTED, ITEM_PROCESSOR_IS_NOT_FOUND_ID); //Checkpoint algorithm validateChildRefAndProperties(batchProject, file, cp, chunk, BatchArtifactType.CHECKPOINT_ALGORITHM, BatchValidationMessages.CHECKPOINT_ALGORITHM_IS_NOT_FOUND, BatchValidationMessages.CHECKPOINT_ALGORITHM_IS_EXPECTED, CHECKPOINT_ALGORITHM_IS_NOT_FOUND_ID); validateExceptions(batchProject, file, chunk, TAG_SKIPPABLE_EXCEPTION_CLASSES); validateExceptions(batchProject, file, chunk, TAG_RETRYABLE_EXCEPTION_CLASSES); validateExceptions(batchProject, file, chunk, TAG_NO_ROLLBACK_EXCEPTION_CLASSES); } private void validateChildRefAndProperties(IBatchProject batchProject, IFile file, ContextProperties cp, Element element, BatchArtifactType type, String notFoundMessage, String wrongTypeMessage, int quickQixId) { Element child = XMLUtilities.getUniqueChild(element, type.getTag()); if(child != null) { validateRefAndProperties(batchProject, file, cp, child, type, notFoundMessage, wrongTypeMessage, quickQixId); } } private void validateRefAndProperties(IBatchProject batchProject, IFile file, ContextProperties cp, Element element, BatchArtifactType type, String notFoundMessage, String wrongTypeMessage, int quickQixId) { String ref = element.getAttribute(ATTR_REF); if(ref != null && ref.trim().length() > 0) { Collection<IBatchArtifact> as = batchProject.getArtifacts(ref.trim()); if(as.isEmpty()) { addProblem(notFoundMessage, BatchSeverityPreferences.UNKNOWN_ARTIFACT_NAME, element, ATTR_REF, file, quickQixId); } else { IBatchArtifact a = as.iterator().next(); if(!a.getArtifactType().equals(type)) { addProblem(wrongTypeMessage, BatchSeverityPreferences.WRONG_ARTIFACT_TYPE, element, ATTR_REF, file, quickQixId); } validateProperties(batchProject, file, cp, element, a); if(!isAsYouTypeValidation()) { getValidationContext().addLinkedCoreResource(SHORT_ID, a.getType().getResource().getFullPath().toString(), file.getFullPath(), true); } } if(!isAsYouTypeValidation()) { getValidationContext().addLinkedCoreResource(SHORT_ID, ref, file.getFullPath(), true); } } else if(element.hasAttribute(ATTR_REF)) { //If attribute is missing, WTP validation creates error that "ref" is required. //If attribute is set to empty value, we have to add message. addProblem(wrongTypeMessage, BatchSeverityPreferences.EMPTY_REFERENCE, element, ATTR_REF, file, quickQixId); } } static String JOB_PROPERTY_CALL_START = "#{jobProperties['"; static String JOB_PROPERTY_CALL_END = "'"; private void validateProperties(IBatchProject batchProject, IFile file, ContextProperties cp, Element parent, IBatchArtifact a) { new ContextProperties(cp, parent, file).complete(a); } @Override public boolean isEnabled(IProject project) { return BatchSeverityPreferences.isValidationEnabled(project); } private void validateExceptions(IBatchProject batchProject, IFile file, Element element, String tagName) { Element child = XMLUtilities.getUniqueChild(element, tagName); if(child != null) { for (String tagName1: new String[]{TAG_INCLUDE, TAG_EXCLUDE}) { Element[] es = XMLUtilities.getChildren(child, tagName1); for (Element e: es) { String className = e.getAttribute(ATTR_CLASS).trim(); IType type = ((BatchProject)batchProject).getType(className); if(type == null) { addProblem(BatchValidationMessages.EXCEPTION_CLASS_IS_NOT_FOUND, BatchSeverityPreferences.UNKNOWN_EXCEPTION_CLASS, e, ATTR_CLASS, file, -1); } else { ParametedType pt = ((BatchProject)batchProject).getTypeFactory().newParametedType(type); boolean isException = false; while(pt != null && !(isException = "java.lang.Exception".equals(pt.getType().getFullyQualifiedName()))) { pt = pt.getSuperType(); } if(!isException) { addProblem(BatchValidationMessages.EXCEPTION_CLASS_DOES_NOT_EXTEND_JAVA_LANG_EXCEPTION, BatchSeverityPreferences.WRONG_EXCEPTION_CLASS, e, ATTR_CLASS, file, -1); } } } } } } private Set<IFile> collectFiles(IProject project, Set<IFile> changedFiles, IProjectValidationContext context) { Set<IFile> files = new HashSet<IFile>(); if(context == null) { files.addAll(changedFiles); return files; } IBatchProject batchProject = BatchProjectFactory.getBatchProject(project, true); Set<IFile> direct = new HashSet<IFile>(); Set<IFile> dependent = new HashSet<IFile>(); for (IFile f: changedFiles) { if(f != null && f.exists() && f.getProject() == project) { Set<IPath> paths = context.getCoreResourcesByVariableName(SHORT_ID, f.getFullPath().toOSString(), true); String name = f.getName(); if(name.toLowerCase().endsWith(".java")) { try { ICompilationUnit unit = EclipseUtil.getCompilationUnit(f); if(unit != null) { IType[] ts = unit.getTypes(); for (IType t: ts) { String type = t.getFullyQualifiedName(); Set<IPath> paths1 = context.getCoreResourcesByVariableName(SHORT_ID, type, true); if(paths1 != null) { if(paths != null) { paths.addAll(paths1); } else { paths = paths1; } } } Collection<IBatchArtifact> as = batchProject.getArtifacts(f); if(!as.isEmpty()) { for (IBatchArtifact a: as) { String n = a.getName(); Set<IPath> paths1 = context.getCoreResourcesByVariableName(SHORT_ID, n, true); if(paths1 != null) { if(paths != null) { paths.addAll(paths1); } else { paths = paths1; } } } } } } catch (CoreException e) { BatchCorePlugin.pluginLog().logError(e); } } else if(name.toLowerCase().endsWith(".xml")) { //$NON-NLS-1$ if(!direct.contains(f) && !dependent.contains(f)) { files.add(f); } direct.add(f); dependent.remove(f); } if(paths != null) { for (IPath path: paths) { IFile f1 = project.getParent().getFile(path); if(f1.exists()) { if(direct.contains(f1) || dependent.contains(f1)) continue; dependent.add(f1); files.add(f1); } } } } } return files; } @Override public void registerPreferenceInfo() { PreferenceInfoManager.register(getProblemType(), new BatchPreferenceInfo()); } class BatchPreferenceInfo implements IPreferenceInfo { @Override public String getPreferencePageId() { return PREFERENCE_PAGE_ID; } @Override public String getPropertyPageId() { return PROPERTY_PAGE_ID; } @Override public String getPluginId() { return BatchCorePlugin.PLUGIN_ID; } } class ContextProperties implements BatchConstants { ContextProperties parent; Map<String, SimpleReference> declared = new HashMap<String, SimpleReference>(); Set<String> referenced = new HashSet<String>(); public ContextProperties(ContextProperties parent, Element element, IFile file) { this.parent = parent; Element properties = XMLUtilities.getUniqueChild(element, TAG_PROPERTIES); if(properties != null) { Element[] es = XMLUtilities.getChildren(properties, TAG_PROPERTY); for (Element property: es) { String name = property.getAttribute(ATTR_NAME).trim(); declared.put(name, new SimpleReference(property, ATTR_NAME, file)); } for (Element property: es) { lookForPropertyReferences(property, file); } } } void lookForPropertyReferences(Element e, IFile file) { NamedNodeMap as = e.getAttributes(); for (int k = 0; k < as.getLength(); k++) { Node n = as.item(k); if(n instanceof Attr) { String value = ((Attr)n).getValue(); if(value.trim().length() > 0) { SimpleReference v = new SimpleReference(e, n.getNodeName(), file); int i = 0; while(i < value.length()) { int i1 = value.indexOf(JOB_PROPERTY_CALL_START, i); if(i1 < 0) break; i1 += JOB_PROPERTY_CALL_START.length(); int i2 = value.indexOf(JOB_PROPERTY_CALL_END, i1); if(i2 < 0) break; String name = value.substring(i1, i2); if(!requestProperty(name)) { SimpleReference v1 = new SimpleReference(v.start + i1 + 1, name.length(), file); addProblem(BatchValidationMessages.UNKNOWN_PROPERTY, BatchSeverityPreferences.UNKNOWN_PROPERTY, new String[]{name}, v1.getLength(), v1.getStartPosition(), file/*, quickFixId*/); } i = i2; } } } } } boolean requestProperty(String name) { if(declared.containsKey(name)) { referenced.add(name); return true; } return parent != null && parent.requestProperty(name); } public void complete(IBatchArtifact a) { for (String name: declared.keySet()) { if(!referenced.contains(name) && (a == null || a.getProperty(name) == null)) { SimpleReference ref = declared.get(name); if(a == null) { addProblem(BatchValidationMessages.PROPERTY_IS_NOT_USED_1, BatchSeverityPreferences.UNUSED_PROPERTY, new String[]{name}, ref.getLength(), ref.getStartPosition(), ref.getResource()/*, quickFixId*/); } else { addProblem(BatchValidationMessages.PROPERTY_IS_NOT_USED, BatchSeverityPreferences.UNUSED_PROPERTY, new String[]{name, a.getName()}, ref.getLength(), ref.getStartPosition(), ref.getResource()/*, quickFixId*/); } } } } } private static final String BUNDLE_NAME = "org.jboss.tools.batch.internal.core.validation.messages"; @Override protected String getMessageBundleName() { return BUNDLE_NAME; } public static class TypeToValidationMessage { static Map<BatchArtifactType, String> notFoundMessages = new HashMap<BatchArtifactType, String>(); static Map<BatchArtifactType, String>wrongTypeMessages = new HashMap<BatchArtifactType, String>(); static { notFoundMessages.put(BatchArtifactType.JOB_LISTENER, BatchValidationMessages.JOB_LISTENER_IS_NOT_FOUND); wrongTypeMessages.put(BatchArtifactType.JOB_LISTENER, BatchValidationMessages.JOB_LISTENER_IS_EXPECTED); notFoundMessages.put(BatchArtifactType.PARTITION_MAPPER, BatchValidationMessages.MAPPER_IS_NOT_FOUND); wrongTypeMessages.put(BatchArtifactType.PARTITION_MAPPER, BatchValidationMessages.MAPPER_IS_EXPECTED); notFoundMessages.put(BatchArtifactType.PARTITION_ANALYZER, BatchValidationMessages.ANALYZER_IS_NOT_FOUND); wrongTypeMessages.put(BatchArtifactType.PARTITION_ANALYZER, BatchValidationMessages.ANALYZER_IS_EXPECTED); notFoundMessages.put(BatchArtifactType.PARTITION_COLLECTOR, BatchValidationMessages.COLLECTOR_IS_NOT_FOUND); wrongTypeMessages.put(BatchArtifactType.PARTITION_COLLECTOR, BatchValidationMessages.COLLECTOR_IS_EXPECTED); notFoundMessages.put(BatchArtifactType.PARTITION_REDUCER, BatchValidationMessages.REDUCER_IS_NOT_FOUND); wrongTypeMessages.put(BatchArtifactType.PARTITION_REDUCER, BatchValidationMessages.REDUCER_IS_EXPECTED); notFoundMessages.put(BatchArtifactType.DECIDER, BatchValidationMessages.DECIDER_IS_NOT_FOUND); wrongTypeMessages.put(BatchArtifactType.DECIDER, BatchValidationMessages.DECIDER_IS_EXPECTED); notFoundMessages.put(BatchArtifactType.BATCHLET, BatchValidationMessages.BATCHLET_IS_NOT_FOUND); wrongTypeMessages.put(BatchArtifactType.BATCHLET, BatchValidationMessages.BATCHLET_IS_EXPECTED); notFoundMessages.put(BatchArtifactType.ITEM_READER, BatchValidationMessages.READER_IS_NOT_FOUND); wrongTypeMessages.put(BatchArtifactType.ITEM_READER, BatchValidationMessages.READER_IS_EXPECTED); notFoundMessages.put(BatchArtifactType.ITEM_WRITER, BatchValidationMessages.WRITER_IS_NOT_FOUND); wrongTypeMessages.put(BatchArtifactType.ITEM_WRITER, BatchValidationMessages.WRITER_IS_EXPECTED); notFoundMessages.put(BatchArtifactType.ITEM_PROCESSOR, BatchValidationMessages.PROCESSOR_IS_NOT_FOUND); wrongTypeMessages.put(BatchArtifactType.ITEM_PROCESSOR, BatchValidationMessages.PROCESSOR_IS_EXPECTED); notFoundMessages.put(BatchArtifactType.CHECKPOINT_ALGORITHM, BatchValidationMessages.CHECKPOINT_ALGORITHM_IS_NOT_FOUND); wrongTypeMessages.put(BatchArtifactType.CHECKPOINT_ALGORITHM, BatchValidationMessages.CHECKPOINT_ALGORITHM_IS_EXPECTED); notFoundMessages.put(BatchArtifactType.STEP_LISTENER, BatchValidationMessages.STEP_LISTENER_IS_NOT_FOUND); wrongTypeMessages.put(BatchArtifactType.STEP_LISTENER, BatchValidationMessages.STEP_LISTENER_IS_EXPECTED); } public static String getNotFoundMessage(BatchArtifactType type) { return notFoundMessages.get(type); } public static String getWrongTypeMessage(BatchArtifactType type) { return wrongTypeMessages.get(type); } } } class SimpleReference implements ITextSourceReference { int start; int length; IFile resource; public SimpleReference(Element element, String attr, IFile resource) { Attr a = element.getAttributeNode(attr); if(a instanceof IDOMAttr) { IDOMAttr da = (IDOMAttr)a; start = da.getValueRegionStartOffset(); length = ((IDOMAttr) a).getValueRegionText().length(); } this.resource = resource; } public SimpleReference(int start, int length, IFile resource) { this.start = start; this.length = length; this.resource = resource; } @Override public int getStartPosition() { return start; } @Override public int getLength() { return length; } @Override public IFile getResource() { return resource; } }