/*
* Copyright 2004 The Apache Software Foundation.
*
* Licensed 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.
*
* $Header:$
*/
package org.apache.beehive.netui.compiler.grammar;
import org.apache.beehive.netui.compiler.AnnotationGrammar;
import org.apache.beehive.netui.compiler.FlowControllerInfo;
import org.apache.beehive.netui.compiler.LocalFileEntityResolver;
import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationValue;
import org.xml.sax.SAXParseException;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import java.util.Map;
import java.util.Collections;
import java.util.HashMap;
import java.io.File;
import java.io.IOException;
public class ValidXmlFileType
extends WebappPathType
{
private String _schemaFileName;
private static Map _parseResults = Collections.synchronizedMap( new HashMap() );
public ValidXmlFileType( String schemaFileName, String requiredRuntimeVersion, AnnotationGrammar parentGrammar,
FlowControllerInfo fcInfo )
{
super( false, requiredRuntimeVersion, parentGrammar, fcInfo );
assert schemaFileName != null;
_schemaFileName = schemaFileName;
}
protected boolean checkAnyExtension()
{
return true;
}
protected boolean doFatalError()
{
return true;
}
protected boolean ignoreDirectories()
{
return false;
}
protected boolean allowFileInPageFlowSourceDir()
{
return true;
}
protected void runAdditionalChecks( File file, AnnotationValue value )
{
//
// We cache the results of parsing the file until the file is actually modified,
// so we don't end up continually re-parsing it.
//
ParseResults prevResults = ( ParseResults ) _parseResults.get( file.getPath() );
long lastModTime = file.lastModified();
if ( prevResults == null || lastModTime > prevResults.getFileModTime() )
{
try
{
LocalFileEntityResolver entityResolver = LocalFileEntityResolver.getInstance();
InputSource schemaInput = entityResolver.resolveLocalEntity(_schemaFileName);
assert schemaInput != null : "could not get schema resource for " + _schemaFileName;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(true);
factory.setAttribute( "http://java.sun.com/xml/jaxp/properties/schemaLanguage",
"http://www.w3.org/2001/XMLSchema");
factory.setAttribute( "http://java.sun.com/xml/jaxp/properties/schemaSource", schemaInput);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(LocalFileEntityResolver.getInstance());
Validator handler = new Validator(lastModTime, file, value);
builder.setErrorHandler(handler);
builder.parse(file);
if (handler.hadErrors()) {
return;
}
}
catch ( SAXParseException e )
{
addErrorDiagnostic( file, e, value );
_parseResults.put( file.getPath(), new ParseResults( lastModTime, e ) );
return;
}
catch ( Exception e )
{
_parseResults.put( file.getPath(), new ParseResults( lastModTime, e ) );
addError( value, "error.xml-read-error",
new Object[]{ file.getPath(), e.getClass().getName(), e.getMessage() } );
return;
}
_parseResults.put( file.getPath(), new ParseResults( lastModTime, null ) );
}
else
{
Exception e = prevResults.getException();
if (e instanceof SAXParseException) {
addErrorDiagnostic(file, (SAXParseException) e, value);
} else if (e != null) {
addError( value, "error.xml-read-error",
new Object[]{ file.getPath(), e.getClass().getName(), e.getMessage() } );
}
}
}
private void addErrorDiagnostic( File file, SAXParseException err, AnnotationValue value )
{
if ( err.getColumnNumber() != -1 && err.getLineNumber() != -1 )
{
Object[] args =
{
file.getPath(),
new Integer( err.getLineNumber() ),
new Integer( err.getColumnNumber() ),
err.getMessage()
};
addError( value, "error.xml-parse-error", args );
}
else if ( err.getLineNumber() != -1 )
{
Object[] args =
{
file.getPath(),
new Integer( err.getLineNumber() ),
err.getMessage()
};
addError( value, "error.xml-parse-error-nocolumn", args );
}
else
{
Object[] args =
{
file.getPath(),
err.getMessage()
};
addError( value, "error.xml-parse-error-nolinecolumn", args );
}
}
private static class ParseResults
{
private long _fileModTime;
private Exception _exception;
public ParseResults( long fileModTime, Exception exception )
{
_fileModTime = fileModTime;
_exception = exception;
}
public long getFileModTime()
{
return _fileModTime;
}
public void setFileModTime( long fileModTime )
{
_fileModTime = fileModTime;
}
public Exception getException()
{
return _exception;
}
public void setException( Exception exception )
{
_exception = exception;
}
}
private class Validator extends DefaultHandler {
private long _fileModTime;
private File _file;
private AnnotationValue _value;
private boolean _hadErrors = false;
public Validator(long fileModTime, File file, AnnotationValue value) {
_fileModTime = fileModTime;
_file = file;
_value = value;
}
public void error(SAXParseException ex)
throws SAXException {
ParseResults results = new ParseResults(_fileModTime, ex);
addErrorDiagnostic(_file, ex, _value );
_parseResults.put(_file.getPath(), results);
_hadErrors = true;
}
public void fatalError(SAXParseException ex)
throws SAXException {
error(ex);
}
public void warning(SAXParseException exception)
throws SAXException {
// TODO: add a compiler warning?
}
public boolean hadErrors() {
return _hadErrors;
}
public InputSource resolveEntity(String publicId, String systemId) throws IOException, SAXException {
return super.resolveEntity(publicId, systemId);
}
}
}