package org.codehaus.mojo.xml; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.UndeclaredThrowableException; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.URIResolver; import javax.xml.transform.sax.SAXSource; import org.apache.maven.plugin.MojoExecutionException; import org.apache.xml.resolver.CatalogManager; import org.apache.xml.resolver.tools.CatalogResolver; import org.codehaus.plexus.resource.ResourceManager; import org.codehaus.plexus.resource.loader.ResourceNotFoundException; import org.w3c.dom.ls.LSInput; import org.w3c.dom.ls.LSResourceResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.ext.EntityResolver2; /** * An implementation of {@link org.xml.sax.EntityResolver}, * {@link URIResolver}, and {@link LSResourceResolver}, * based on the Apache catalog resolver. */ public class Resolver implements EntityResolver2, URIResolver, LSResourceResolver { private final ResourceManager locator; private final File baseDir; private final CatalogResolver resolver; private boolean validating; /** Creates a new instance. * @param pFiles A set of files with catalog definitions to load * @throws MojoExecutionException An error occurred while loading the resolvers catalogs. */ Resolver( File pBaseDir, List pFiles, List pUrls, ResourceManager pLocator, boolean pLogging ) throws MojoExecutionException { baseDir = pBaseDir; locator = pLocator; CatalogManager manager = new CatalogManager(); manager.setIgnoreMissingProperties( true ); if ( pLogging ) { System.err.println("Setting resolver verbosity to maximum."); manager.setVerbosity( Integer.MAX_VALUE ); } resolver = new CatalogResolver( manager ); for ( int i = 0; i < pFiles.size(); i++ ) { File file = (File) pFiles.get( i ); try { resolver.getCatalog().parseCatalog( file.getPath() ); } catch ( IOException e ) { throw new MojoExecutionException( "Failed to parse catalog file: " + file.getPath() + ": " + e.getMessage(), e ); } } for ( int i = 0; i < pUrls.size(); i++ ) { URL url = (URL) pUrls.get( i ); try { resolver.getCatalog().parseCatalog( url ); } catch ( IOException e ) { throw new MojoExecutionException( "Failed to parse catalog URL: " + url + ": " + e.getMessage(), e ); } } } /** * Implementation of {@link org.xml.sax.EntityResolver#resolveEntity(String, String)}. */ public InputSource resolveEntity( String pPublicId, String pSystemId ) throws SAXException, IOException { final InputSource source = resolver.resolveEntity( pPublicId, pSystemId ); if ( source != null ) { return source; } URL url = resolve( pSystemId ); if ( url != null ) { return asInputSource( url ); } return null; } private InputSource asInputSource( URL url ) throws IOException { InputSource isource = new InputSource( url.openStream() ); isource.setSystemId( url.toExternalForm() ); return isource; } /** * Implementation of {@link URIResolver#resolve(String, String)}. */ public Source resolve( String pHref, String pBase ) throws TransformerException { final Source source = resolver.resolve( pHref, pBase ); if ( source != null ) { return source; } URL url = resolve( pHref ); if ( url != null ) { try { return asSaxSource( asInputSource( url ) ); } catch ( IOException e ) { throw new TransformerException( e ); } catch ( SAXException e ) { throw new TransformerException( e ); } catch ( ParserConfigurationException e ) { throw new TransformerException( e ); } } return null; } private Source asSaxSource( InputSource isource ) throws SAXException, ParserConfigurationException { SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setValidating( validating ); spf.setNamespaceAware( true ); XMLReader xmlReader = spf.newSAXParser().getXMLReader(); xmlReader.setEntityResolver( this ); return new SAXSource( xmlReader, isource ); } private final LSInput newLSInput( InputSource pSource ) { final LSInputImpl lsInput = new LSInputImpl(); lsInput.setByteStream( pSource.getByteStream() ); lsInput.setCharacterStream( pSource.getCharacterStream() ); lsInput.setPublicId( lsInput.getPublicId() ); lsInput.setSystemId( pSource.getSystemId() ); lsInput.setEncoding( pSource.getEncoding() ); return lsInput; } /** * Implementation of {@link LSResourceResolver#resolveResource(String, String, String, String, String)}. */ public LSInput resolveResource( String pType, String pNamespaceURI, String pPublicId, String pSystemId, String pBaseURI ) { if ( pPublicId != null ) { final InputSource isource = resolver.resolveEntity( pPublicId, pSystemId ); if ( isource != null ) { return newLSInput( isource ); } } InputSource isource = resolver.resolveEntity( pNamespaceURI, pSystemId ); if ( isource != null ) { return newLSInput( isource ); } URL url = resolve( pSystemId ); if ( url != null ) { try { isource = asInputSource( url ); } catch ( IOException e ) { throw new UndeclaredThrowableException( e ); } } return isource == null ? null : newLSInput( isource ); } /** * Sets, whether the Resolver should create validating parsers. */ public void setValidating ( boolean pValidating ) { validating = pValidating; } /** * Returns, whether the Resolver should create validating parsers. */ public boolean isValidating ( ) { return validating; } private URL resolveAsResource( String pResource ) { return Thread.currentThread().getContextClassLoader().getResource( pResource ); } private URL resolveAsFile( String pResource ) { File f = new File( baseDir, pResource ); if ( !f.isFile() ) { f = new File( pResource ); if ( !f.isFile() ) { return null; } } try { return f.toURI().toURL(); } catch ( MalformedURLException e ) { return null; } } private URL resolveAsURL( String pResource ) { InputStream stream = null; try { final URL url = new URL( pResource ); stream = url.openStream(); stream.close(); stream = null; return url; } catch ( IOException e ) { return null; } finally { if ( stream != null ) { try { stream.close(); } catch ( Throwable t ) { // Ignore me } } } } /** * Attempts to resolve the given URI. */ public URL resolve( String pResource ) { if ( pResource == null ) { return null; } if ( pResource.startsWith( "resource:" ) ) { String res = pResource.substring( "resource:".length() ); return resolveAsResource( res ); } URL url = resolveAsResource( pResource ); if ( url == null ) { url = resolveAsURL( pResource ); if ( url == null ) { url = resolveAsFile( pResource ); } } try { return locator.getResource( pResource ).getURL(); } catch ( ResourceNotFoundException e ) { return null; } catch ( IOException e ) { return null; } } /** * Implementation of {@link EntityResolver2#getExternalSubset(String, String)} */ public InputSource getExternalSubset( String name, String baseURI ) throws SAXException, IOException { return null; } /** * Implementation of {@link EntityResolver2#resolveEntity(String, String, String, String)} */ public InputSource resolveEntity( String pName, String pPublicId, String pBaseURI, String pSystemId ) throws SAXException, IOException { final InputSource source = resolver.resolveEntity( pPublicId, pSystemId ); if ( source != null ) { return source; } URL url = resolve( pSystemId ); if ( url != null ) { return asInputSource( url ); } return null; } }