/*-
* Copyright (C) 2011-2014 by Iwao AVE!
* This program is made available under the terms of the MIT License.
*/
package org.eclipselabs.stlipse.jspeditor;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.validation.AbstractValidator;
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.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.IDOMElement;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.eclipselabs.stlipse.Activator;
import org.eclipselabs.stlipse.cache.BeanClassCache;
import org.eclipselabs.stlipse.cache.BeanPropertyCache;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* @author Iwao AVE!
*/
@SuppressWarnings("restriction")
public class JspValidator extends AbstractValidator implements IValidator
{
public static final String MARKER_ID = "org.eclipselabs.stlipse.stripesJspProblem";
public static final String MISSING_ACTION_BEAN = "missingActionBean";
public static final String NO_WRITABLE_PROPERTY = "noWritableProperty";
public static final String NO_EVENT_HANDLER = "noEventhandler";
public void cleanup(IReporter reporter)
{
// Nothing to do.
}
public void validate(IValidationContext helper, IReporter reporter)
throws ValidationException
{
String[] uris = helper.getURIs();
if (uris != null)
{
for (int i = 0; i < uris.length && !reporter.isCancelled(); i++)
{
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(uris[i]));
validateFile(file, reporter);
}
}
}
public ValidationResult validate(final IResource resource, int kind, ValidationState state,
IProgressMonitor monitor)
{
if (resource.getType() != IResource.FILE)
return null;
ValidationResult result = new ValidationResult();
final IReporter reporter = result.getReporter(monitor);
validateFile((IFile)resource, reporter);
return result;
}
/**
* @param file
* @param reporter
*/
private void validateFile(IFile file, IReporter reporter)
{
IStructuredModel model = null;
try
{
file.deleteMarkers(MARKER_ID, false, IResource.DEPTH_ZERO);
model = StructuredModelManager.getModelManager().getModelForRead(file);
IDOMModel domModel = (IDOMModel)model;
IDOMDocument domDoc = domModel.getDocument();
NodeList nodes = domDoc.getChildNodes();
for (int k = 0; k < nodes.getLength(); k++)
{
Node child = nodes.item(k);
if (child instanceof IDOMElement)
{
validateElement((IDOMElement)child, file, domDoc.getStructuredDocument(), reporter);
}
}
}
catch (Exception e)
{
Activator.log(Status.WARNING, "Error occurred during validation.", e);
}
finally
{
if (model != null)
{
model.releaseFromRead();
}
}
}
private void validateElement(IDOMElement element, IFile file, IStructuredDocument doc,
IReporter reporter) throws JavaModelException
{
if (element == null)
return;
IJavaProject project = JavaCore.create(file.getProject());
String tagName = element.getNodeName();
NamedNodeMap attrs = element.getAttributes();
for (int i = 0; i < attrs.getLength(); i++)
{
IDOMAttr attr = (IDOMAttr)attrs.item(i);
String attributeName = attr.getName();
String attrValue = attr.getValue().trim();
if (containsElExpression(attrValue))
{
// ignore EL expressions
}
else if ("beanclass".equals(attributeName))
{
validateBeanclass(project, file, doc, attr, attrValue);
}
else if (StripesTagUtil.isSuggestableFormTag(tagName, attributeName)
&& !"label".equals(StripesTagUtil.getStripesTagSuffix(tagName)))
{
String beanclass = StripesTagUtil.getParentBeanclass(element, "form");
validateField(project, file, doc, element, attr, beanclass, attrValue);
}
else if (StripesTagUtil.isParamTag(tagName, attributeName))
{
String beanclass = StripesTagUtil.getParentBeanclass(element, "url", "link");
validateField(project, file, doc, element, attr, beanclass, attrValue);
}
else if (StripesTagUtil.isSubmitTag(tagName, attributeName))
{
String beanclass = StripesTagUtil.getParentBeanclass(element, "form");
validateEvent(project, file, doc, element, attr, beanclass, attrValue, true);
}
else if (StripesTagUtil.isEventAttribute(tagName, attributeName))
{
String beanclass = StripesTagUtil.getBeanclassAttribute(element);
validateEvent(project, file, doc, element, attr, beanclass, attrValue, false);
}
}
NodeList nodes = element.getChildNodes();
for (int j = 0; j < nodes.getLength(); j++)
{
Node child = nodes.item(j);
if (child instanceof IDOMElement)
{
validateElement((IDOMElement)child, file, doc, reporter);
}
}
}
private void validateField(IJavaProject project, IFile file, IStructuredDocument doc,
IDOMElement element, IDOMAttr attr, String beanclass, String property)
{
if (isBeanclassValidatable(beanclass))
{
Map<String, String> fields = BeanPropertyCache.searchFields(project, beanclass, property,
false, -1, true);
if (fields.size() == 0)
{
addMarker(file, doc, attr, NO_WRITABLE_PROPERTY, IMarker.SEVERITY_WARNING,
IMarker.PRIORITY_NORMAL, "Writable property '" + property + "' not found in "
+ beanclass);
}
}
}
private void validateEvent(IJavaProject project, IFile file, IStructuredDocument doc,
IDOMElement element, IDOMAttr attr, String beanclass, String event,
boolean validIfDefaultHandlerExists)
{
if (isBeanclassValidatable(beanclass))
{
List<String> events = BeanPropertyCache.searchEventHandler(project, beanclass, event,
true, validIfDefaultHandlerExists);
if (events.size() == 0)
{
addMarker(file, doc, attr, NO_EVENT_HANDLER, IMarker.SEVERITY_WARNING,
IMarker.PRIORITY_NORMAL, "Event handler '" + event + "' not found in " + beanclass);
}
}
}
private void validateBeanclass(IJavaProject project, IFile file, IStructuredDocument doc,
IDOMAttr attr, String beanclass) throws JavaModelException
{
if (isBeanclassValidatable(beanclass)
&& !BeanClassCache.actionBeanExists(project, beanclass))
{
addMarker(file, doc, attr, MISSING_ACTION_BEAN, IMarker.SEVERITY_ERROR,
IMarker.PRIORITY_HIGH, "ActionBean '" + beanclass + "' not found.");
}
}
private boolean isBeanclassValidatable(String beanclass)
{
return beanclass != null && beanclass.indexOf('$') == -1;
}
private boolean containsElExpression(String str)
{
boolean inIndexedProperty = false;
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
if (!inIndexedProperty && c == '$')
return true;
else if (!inIndexedProperty && c == '[')
inIndexedProperty = true;
else if (c == ']')
inIndexedProperty = false;
}
return false;
}
private void addMarker(IFile file, IStructuredDocument doc, IDOMAttr attr,
String problemType, int severity, int priority, String message)
{
try
{
int start = attr.getValueRegionStartOffset();
int length = attr.getValueRegionText().length();
int lineNo = doc.getLineOfOffset(start);
IMarker marker = file.createMarker(MARKER_ID);
marker.setAttribute(IMarker.SEVERITY, severity);
marker.setAttribute(IMarker.PRIORITY, priority);
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.LINE_NUMBER, lineNo);
if (start != 0)
{
marker.setAttribute(IMarker.CHAR_START, start);
marker.setAttribute(IMarker.CHAR_END, start + length);
}
// Adds custom attributes.
marker.setAttribute("problemType", problemType);
marker.setAttribute("errorValue", attr.getValue());
}
catch (CoreException e)
{
Activator.log(Status.ERROR, "Failed to create a custom marker.", e);
}
}
}