blob: 299a59709fd3fa423f6d45a8ccf6d1b8cb0c2536 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.wsdl.validation.internal.xml;
import java.io.File;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.xerces.jaxp.SAXParserFactoryImpl;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.helpers.DefaultHandler;
/**
* XMLCatalog This class can be used to register, obtain and delete an instance
* of an XML catalog. Method definitions are provided for the catalog to set a
* location in the catalog and resolve an entity from the catalog.
*/
public class XMLCatalog implements IXMLCatalog
{
private final static String _APACHE_FEATURE_CONTINUE_AFTER_FATAL_ERROR = "http://apache.org/xml/features/continue-after-fatal-error";
private final static String _APACHE_FEATURE_NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes";
private final static String _APACHE_FEATURE_NAMESPACES = "http://xml.org/sax/features/namespaces";
private final static String _APACHE_FEATURE_VALIDATION = "http://xml.org/sax/features/validation";
private final static String _APACHE_FEATURE_VALIDATION_SCHEMA = "http://apache.org/xml/features/validation/schema";
private static IXMLCatalog instance = null;
private static String extxmlcatalogclass = null;
private static ClassLoader extclassLoader = null;
private static IXMLCatalog extXMLCatalogInstance = null;
private static List schemadirs = new ArrayList();
private static List entities = new ArrayList();
/**
* A hashtable to hold the XML catalog entries.
*/
protected Map catalog = new Hashtable();
/**
* Return an instance of the XML catalog. Assigns all registered schemas to
* the XML catalog.
*
* @return The instance of the XML catalog.
*/
public static IXMLCatalog getInstance()
{
if (instance == null)
{
instance = new XMLCatalog();
// Add the registered entities to the catalog.
Iterator entityIter = entities.iterator();
while (entityIter.hasNext())
{
XMLCatalogEntityHolder entity = (XMLCatalogEntityHolder) entityIter.next();
instance.addEntryToCatalog(entity.getPublicId(), entity.getSystemId());
}
// Add the schemas in the schema directories to the catalog.
if (schemadirs.size() > 0)
{
SAXParser saxParser = null;
try
{
SAXParserFactory parserfactory = new SAXParserFactoryImpl();
parserfactory.setFeature(_APACHE_FEATURE_NAMESPACE_PREFIXES, true);
parserfactory.setFeature(_APACHE_FEATURE_NAMESPACES, true);
saxParser = parserfactory.newSAXParser();
}
catch (FactoryConfigurationError e)
{
}
catch (SAXNotRecognizedException e)
{
}
catch (ParserConfigurationException e)
{
}
catch (SAXNotSupportedException e)
{
}
catch (SAXException e)
{
}
Iterator schemadirIter = schemadirs.iterator();
SchemaNamespaceHandler handler = ((XMLCatalog) instance).new SchemaNamespaceHandler();
while (schemadirIter.hasNext())
{
String schemadir = (String) schemadirIter.next();
registerSchemasForDir(instance, schemadir, saxParser, handler);
}
}
}
return instance;
}
/**
* Register the schemas in the given directory and all subdirectories with the
* XML catalog.
*
* @param catalog
* The catalog to register the schemas with.
* @param schemadir
* The schema directory to search for schema files.
* @param parser
* The SAXParser to use to parse the schemas for their
* targetNamespace.
* @param handler
* The handler to use to get the targetNamespace.
*/
private static void registerSchemasForDir(IXMLCatalog catalog, String schemadir, SAXParser parser,
SchemaNamespaceHandler handler)
{
// Remove file: and file:/ from beginning of file location if they are present.
if(schemadir.startsWith("file:/"))
{
schemadir = schemadir.substring(6);
}
else if(schemadir.startsWith("file:"))
{
schemadir = schemadir.substring(5);
}
File dir = new File(schemadir);
if (dir.isDirectory())
{
File[] files = dir.listFiles();
int numfiles = files.length;
for (int i = 0; i < numfiles; i++)
{
File tempfile = files[i];
String tempfilepath = tempfile.getAbsolutePath();
if (tempfile.isDirectory())
{
registerSchemasForDir(catalog, tempfilepath, parser, handler);
} else
{
handler.reset();
try
{
parser.parse(tempfilepath, handler);
}
catch (Exception e)
{
// TODO: log error.
}
String targetNamespace = handler.getTargetNamespace();
if (targetNamespace != null)
{
catalog.addEntryToCatalog(targetNamespace, tempfilepath);
}
}
}
}
}
/**
* Get the instance of the extension XML catalog. Returns the instance if one
* is registered and can be created, null otherwise.
*
* @return The instance of the extension XML catalog if one is registered,
* null otherwise.
*/
public static IXMLCatalog getExtensionCatalogInstance()
{
if (extXMLCatalogInstance == null)
{
if (extxmlcatalogclass != null && extclassLoader != null)
{
try
{
Class catalogClass = extclassLoader != null ? extclassLoader.loadClass(extxmlcatalogclass) : Class
.forName(extxmlcatalogclass);
extXMLCatalogInstance = (IXMLCatalog) catalogClass.newInstance();
}
catch (Exception e)
{
//TODO: Log error
}
}
}
return extXMLCatalogInstance;
}
/**
* Set the class of the XML catalog to be used.
*
* @param xmlcatalog
* The class of the XML catalog to be used.
* @param classloader
* The classloader to use to load the catalog.
*/
public static void setExtensionXMLCatalog(String xmlcatalog, ClassLoader classloader)
{
extxmlcatalogclass = xmlcatalog;
extclassLoader = classloader;
}
/**
* Resets the instance of the XML catalog to null. For deleting the catalog if
* necessary.
*/
public static void reset()
{
instance = null;
extxmlcatalogclass = null;
extclassLoader = null;
extXMLCatalogInstance = null;
entities = new ArrayList();
schemadirs = new ArrayList();
}
/**
* Add a schema directory to be checked for schemas to register in the
* catalog.
*
* @param schemadir
* The directory to check for schemas.
*/
public static void addSchemaDir(String schemadir)
{
schemadirs.add(schemadir);
}
/**
* Add an entity to the catalog.
*
* @param entity
* The entity to add to the catalog.
*/
public static void addEntity(XMLCatalogEntityHolder entity)
{
entities.add(entity);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.wsdl.validate.internal.xml.IXMLCatalog#addEntryToCatalog(java.lang.String,
* java.lang.String)
*/
public void addEntryToCatalog(String publicId, String systemId)
{
catalog.put(publicId, systemId);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.wsdl.validate.internal.xml.IXMLCatalog#resolveEntityLocation(java.lang.String,
* java.lang.String)
*/
public String resolveEntityLocation(String publicId, String systemId)
{
String resolvedlocation = null;
// First try to resolve using the ext catalog.
IXMLCatalog extcatalog = getExtensionCatalogInstance();
if (extcatalog != null)
{
resolvedlocation = extcatalog.resolveEntityLocation(publicId, systemId);
}
if (resolvedlocation == null)
{
// if there's no system id use the public id
if (systemId == null || systemId.equals(""))
{
systemId = publicId;
}
resolvedlocation = (String) catalog.get(systemId);
}
return resolvedlocation;
}
/**
* A handler used in parsing to get the targetNamespace string of a schema.
*/
protected class SchemaNamespaceHandler extends DefaultHandler
{
private final String TARGET_NAMESPACE = "targetNamespace";
private final String SCHEMA = "schema";
private String targetNamespace = null;
/**
* @see org.xml.sax.ContentHandler#startElement(java.lang.String,
* java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
public void startElement(String uri, String localname, String arg2, Attributes attributes) throws SAXException
{
if (localname.equals(SCHEMA))
{
int numAtts = attributes.getLength();
for (int i = 0; i < numAtts; i++)
{
String attname = attributes.getQName(i);
if (attname.equals(TARGET_NAMESPACE))
{
targetNamespace = attributes.getValue(i);
}
}
}
super.startElement(uri, localname, arg2, attributes);
}
/**
* Return the targetNamespace found by parsing the file.
*
* @return The targetNamespace found by parsing the file.
*/
public String getTargetNamespace()
{
return targetNamespace;
}
/**
* Reset the state of the handler so it can be reused.
*/
public void reset()
{
targetNamespace = null;
}
}
}