package org.zend.php.zendserver.deployment.core.internal.validation;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.zend.php.zendserver.deployment.core.DeploymentCore;
import org.zend.php.zendserver.deployment.core.IncrementalDeploymentBuilder;
import org.zend.php.zendserver.deployment.core.descriptor.DescriptorContainerManager;
import org.zend.php.zendserver.deployment.core.descriptor.IDescriptorContainer;
public class DescriptorValidator {
private static final String DESCRIPTOR_SCHEMA = "deployment.xsd"; //$NON-NLS-1$
public void validate(IFile file) {
if (file != null && file.exists()) {
validateXSD(file);
validateSemantics(file);
}
}
protected void validateXSD(IFile file) {
SchemaFactory factory =
SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); //$NON-NLS-1$
Source schemaSource = new StreamSource(getClass().getResourceAsStream(DESCRIPTOR_SCHEMA));
Schema schema = null;
javax.xml.validation.Validator validator = null;
Source source = null;
try {
schema = factory.newSchema(schemaSource);
validator = schema.newValidator();
source = new StreamSource(file.getContents());
} catch (SAXException e) {
DeploymentCore.log(e);
return;
} catch (CoreException e) {
DeploymentCore.log(e);
return;
}
IDocument doc = null;
try {
doc = getIDocument(file);
} catch (Throwable e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return;
}
try {
validator.validate(source);
}
catch (SAXException ex) {
int line = 0;
int start = 0;
int end = 0;
if (ex instanceof SAXParseException) {
SAXParseException parseEx = (SAXParseException) ex;
line = parseEx.getLineNumber() - 1;
try {
start = doc.getLineOffset(line) + parseEx.getColumnNumber() - 1;
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // TODO calculate offset from start of the doc, not from start of line
end = start; // TODO find next whitespace
}
int severity = ValidationStatus.ERROR; // TODO validation error level should be configurable?
String message = ex.getMessage();
reportProblem(file, new ValidationStatus(line, start, end, severity, message));
} catch (IOException e) {
DeploymentCore.log(e);
}
}
private IDocument getIDocument(IFile file) throws Throwable {
InputStream is = file.getContents();
StringBuilder sb = new StringBuilder();
byte[] buf = new byte[4096];
int count;
while ((count = is.read(buf)) > 0) {
sb.append(new String(buf, 0, count));
}
return new Document(sb.toString());
}
private void validateSemantics(IFile file) {
IDescriptorContainer model = DescriptorContainerManager.getService()
.openDescriptorContainer(file);
IDocument doc = null;
try {
doc = getIDocument(file);
} catch (Throwable e) {
DeploymentCore.log(e);
return;
}
DescriptorSemanticValidator validator = new DescriptorSemanticValidator();
validator.setFile(file);
ValidationStatus[] statuses = validator.validate(model.getDescriptorModel(), doc);
reportProblems(file, statuses);
}
public static void reportProblems(IFile file, ValidationStatus[] statuses) {
List<ValidationStatus> existing = new ArrayList<ValidationStatus>();
IMarker[] markers = null;
try {
markers = file.findMarkers(IncrementalDeploymentBuilder.PROBLEM_MARKER, true, IResource.DEPTH_ZERO);
for (IMarker marker : markers) {
existing.add(markerToStatus(marker));
}
} catch (CoreException e) {
DeploymentCore.log(e);
}
// find which errors are new, already exist, or need to be removed
List<ValidationStatus> toReport = new ArrayList<ValidationStatus>(Arrays.asList(statuses));
toReport.removeAll(existing); // remove all existing statuses from the new ones list to get a list of those to report
existing.removeAll(Arrays.asList(statuses)); // remove all re-reported statuses to get a list of obsolete statuses
// add new statuses
for (ValidationStatus status : toReport) {
reportProblem(file, status);
}
// remove obsolete statuses
for (ValidationStatus status : existing) {
try {
status.getMarker().delete();
} catch (CoreException e) {
DeploymentCore.log(e);
}
}
}
public static ValidationStatus markerToStatus(IMarker marker) {
int line = marker.getAttribute(IMarker.LINE_NUMBER, 0);
int start = marker.getAttribute(IMarker.CHAR_START, 0);
int end = marker.getAttribute(IMarker.CHAR_END, 0);
String message = marker.getAttribute(IMarker.MESSAGE, null);
int severity = marker.getAttribute(IMarker.SEVERITY, 0);
int featureId = marker.getAttribute(IncrementalDeploymentBuilder.FEATURE_ID, -1);
int objectId = marker.getAttribute(IncrementalDeploymentBuilder.OBJECT_ID, -1);
int no = marker.getAttribute(IncrementalDeploymentBuilder.OBJECT_NUMBER, -1);
ValidationStatus status = new ValidationStatus(objectId, no, featureId, line, start, end, severity, message);
status.setMarker(marker);
return status;
}
public static IMarker reportProblem(IFile file, ValidationStatus status) {
IMarker marker;
try {
marker = file.createMarker(IncrementalDeploymentBuilder.PROBLEM_MARKER);
marker.setAttribute(IMarker.LINE_NUMBER, status.getLine());
marker.setAttribute(IMarker.CHAR_START, status.getStart());
marker.setAttribute(IMarker.CHAR_END, status.getEnd());
marker.setAttribute(IMarker.MESSAGE, status.getMessage());
//marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_NORMAL);
marker.setAttribute(IMarker.SEVERITY, status.getSeverity());
if (status.getFeatureId() != -1) {
marker.setAttribute(IncrementalDeploymentBuilder.FEATURE_ID, status.getFeatureId());
}
if (status.getObjectNo() != -1) {
marker.setAttribute(IncrementalDeploymentBuilder.OBJECT_NUMBER, status.getObjectNo());
}
if (status.getObjectId() != -1) {
marker.setAttribute(IncrementalDeploymentBuilder.OBJECT_ID, status.getObjectId());
}
return marker;
} catch (CoreException e) {
DeploymentCore.log(e);
}
return null;
}
}