/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2004-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.data.complex.config; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import org.apache.xml.resolver.Catalog; import org.eclipse.xsd.XSDSchema; import org.geotools.xml.SchemaLocationResolver; /** * Wrapper to perform OASIS catalogue lookup when resolving a schema location. * * @author Ben Caradoc-Davies, CSIRO Exploration and Mining * @version $Id$ * @source $URL$ * @since 2.6 */ public class CatalogSchemaLocationResolverWrapper extends SchemaLocationResolver { private final Catalog catalog; /* * This sucks. This should be XSDSchemaLocationResolver, but because XSD.schemaLocationResolver * returns SchemaLocationResolver not the interface, we are forced to use the concrete type. So * much for dependency injection. */ private SchemaLocationResolver resolver; /** * @param catalog * catalog to search, or null if none * @param resolver * fallback resolver to use if not found in catalog */ public CatalogSchemaLocationResolverWrapper(final Catalog catalog, final SchemaLocationResolver resolver) { super(null); this.catalog = catalog; this.resolver = resolver; } /** * @param schema * the schema being resolved * @param uri * the namespace being resolved. If its an empty string (i.e. the location refers * to an include, and thus the uri to the same one than the schema), the schema * one is used. * @param location * the xsd location, either of <code>schema</code>, an import or an include, * for which to try resolving it as a relative path of the <code>schema</code> * location. * @return * */ @Override public String resolveSchemaLocation(final XSDSchema schema, final String uri, final String location) { /* * The old 2.4.x branch Configuration only did file handling. The new Configuration resolves * any "http:" URI to itself. This prevents using the OASIS catalogue for fallback, and is * arguably a bug. To workaround this, we try the catalogue first, if we have one. */ String schemaLocation = CatalogUtilities.resolveSchemaLocation(catalog, location); if (schemaLocation != null) { return canonicalLocation(schemaLocation); } else { return canonicalLocation(resolver.resolveSchemaLocation(schema, uri, location)); } } /** * Return true if the resolver can find the schema. * * @see org.geotools.xml.SchemaLocationResolver#canHandle(org.eclipse.xsd.XSDSchema, * java.lang.String, java.lang.String) */ @Override public boolean canHandle(XSDSchema schema, String uri, String location) { return resolveSchemaLocation(schema, uri, location) != null; } @Override public String toString() { return resolver.toString(); } /** * Convert the schema file location URI to canonical form. * * <p> * * Canonicalisation is necessary to prevent infinite recursion when loading some schema families * with relative import paths. You know who you are. * * @param schemaLocation * a file URI string, for example "file:/whatever/./something.xsd" * @return canonical form of the file path, for example "file:/whatever/something.xsd" */ static String canonicalLocation(String schemaLocation) { if (schemaLocation != null) { try { URI uri = new URI(schemaLocation); if (uri.getScheme().equals("file")) { File file = new File(uri.getPath()); if (file.exists()) { return file.getCanonicalFile().toURI().toString(); } } } catch (URISyntaxException e) { // ignore } catch (IOException e) { // ignore } } return schemaLocation; } }