Author: cziegeler Date: Mon May 2 06:32:24 2005 New Revision: 165628 URL: http://svn.apache.org/viewcvs?rev=165628&view=rev Log: Protocols can be defined on a per sitemap configuration
Modified: cocoon/trunk/src/java/org/apache/cocoon/components/source/CocoonSourceResolver.java Modified: cocoon/trunk/src/java/org/apache/cocoon/components/source/CocoonSourceResolver.java URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/components/source/CocoonSourceResolver.java?rev=165628&r1=165627&r2=165628&view=diff ============================================================================== --- cocoon/trunk/src/java/org/apache/cocoon/components/source/CocoonSourceResolver.java (original) +++ cocoon/trunk/src/java/org/apache/cocoon/components/source/CocoonSourceResolver.java Mon May 2 06:32:24 2005 @@ -16,35 +16,82 @@ package org.apache.cocoon.components.source; +import java.io.File; import java.io.IOException; import java.net.MalformedURLException; +import java.net.URL; import java.util.Map; +import org.apache.avalon.framework.CascadingRuntimeException; +import org.apache.avalon.framework.activity.Disposable; +import org.apache.avalon.framework.context.Context; +import org.apache.avalon.framework.context.ContextException; +import org.apache.avalon.framework.context.Contextualizable; +import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; +import org.apache.avalon.framework.service.Serviceable; import org.apache.cocoon.Processor; import org.apache.cocoon.environment.SourceResolver; import org.apache.cocoon.environment.internal.EnvironmentHelper; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.SourceException; -import org.apache.excalibur.source.impl.SourceResolverImpl; +import org.apache.excalibur.source.SourceFactory; +import org.apache.excalibur.source.URIAbsolutizer; /** * This is the default implementation of the [EMAIL PROTECTED] SourceResolver} for - * Cocoon. + * Cocoon. The implementation is based on the original source resolver implementation + * from the Excalibur project. * @since 2.2 * * @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a> - * @version CVS $Id: CocoonSourceResolver.java,v 1.1 2004/05/25 07:28:26 cziegeler Exp $ + * @version CVS $Id$ */ public class CocoonSourceResolver -extends SourceResolverImpl -implements SourceResolver { +extends AbstractLogEnabled +implements SourceResolver, Contextualizable, Serviceable, Disposable { /** A (optional) custom source resolver */ protected org.apache.excalibur.source.SourceResolver customResolver; - - /* (non-Javadoc) + + /** The service manager */ + protected ServiceManager manager; + + /** The base URL */ + protected URL baseURL; + + /** The component context */ + protected Context context; + + /** + * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context) + */ + public void contextualize( Context context ) + throws ContextException { + this.context = context; + try { + if( context.get( "context-root" ) instanceof URL ) { + this.baseURL = (URL)context.get( "context-root" ); + } else { + this.baseURL = ( (File)context.get( "context-root" ) ).toURL(); + } + } catch( ContextException ce ) { + // set the base URL to the current directory + try { + this.baseURL = new File( System.getProperty( "user.dir" ) ).toURL(); + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( "SourceResolver: Using base URL: " + this.baseURL ); + } + } catch( MalformedURLException mue ) { + throw new ContextException( "Malformed URL for user.dir, and no container.rootDir exists", mue ); + } + } catch( MalformedURLException mue ) { + throw new ContextException( "Malformed URL for container.rootDir", mue ); + } + } + + /** * @see org.apache.excalibur.source.SourceResolver#resolveURI(java.lang.String, java.lang.String, java.util.Map) */ public Source resolveURI(String location, String baseURI, Map parameters) @@ -58,11 +105,80 @@ if ( this.customResolver != null ) { return this.customResolver.resolveURI(location, baseURI, parameters); } else { - return super.resolveURI(location, baseURI, parameters); + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( "Resolving '" + location + "' with base '" + baseURI + "' in context '" + this.baseURL + "'" ); + } + if( location == null ) { + throw new MalformedURLException( "Invalid System ID" ); + } + if( null != baseURI && org.apache.excalibur.source.SourceUtil.indexOfSchemeColon(baseURI) == -1 ) { + throw new MalformedURLException( "BaseURI is not valid, it must contain a protocol: " + baseURI ); + } + + if( baseURI == null ) { + baseURI = this.baseURL.toExternalForm(); + } + + String systemID = location; + // special handling for windows file paths + if( location.length() > 1 && location.charAt( 1 ) == ':' ) { + systemID = "file:/" + location; + } else if( location.length() > 2 && location.charAt(0) == '/' && location.charAt(2) == ':' ) { + systemID = "file:" + location; + } + + // determine protocol (scheme): first try to get the one of the systemID, if that fails, take the one of the baseURI + String protocol; + int protocolPos = org.apache.excalibur.source.SourceUtil.indexOfSchemeColon(systemID); + if( protocolPos != -1 ) { + protocol = systemID.substring( 0, protocolPos ); + } else { + protocolPos = org.apache.excalibur.source.SourceUtil.indexOfSchemeColon(baseURI); + if( protocolPos != -1 ) { + protocol = baseURI.substring( 0, protocolPos ); + } else { + protocol = "*"; + } + } + + final ServiceManager m = this.getServiceManager(); + + Source source = null; + // search for a SourceFactory implementing the protocol + SourceFactory factory = null; + try { + factory = this.getSourceFactory( m, protocol ); + systemID = this.absolutize( factory, baseURI, systemID ); + if( getLogger().isDebugEnabled() ) { + getLogger().debug( "Resolved to systemID : " + systemID ); + } + source = factory.getSource( systemID, parameters ); + } catch( final ServiceException ce ) { + // no selector available, use fallback + } finally { + m.release( factory ); + } + + if( null == source ) { + try { + factory = this.getSourceFactory( m, "*"); + systemID = this.absolutize( factory, baseURI, systemID ); + if( getLogger().isDebugEnabled() ) { + getLogger().debug( "Resolved to systemID : " + systemID ); + } + source = factory.getSource( systemID, parameters ); + } catch (ServiceException se ) { + throw new SourceException( "Unable to select source factory for " + systemID, se ); + } finally { + m.release(factory); + } + } + + return source; } } - /* (non-Javadoc) + /** * @see org.apache.excalibur.source.SourceResolver#resolveURI(java.lang.String) */ public Source resolveURI(String location) @@ -76,33 +192,84 @@ * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager) */ public void service(ServiceManager manager) throws ServiceException { - super.service(manager); - if ( manager.hasService(org.apache.excalibur.source.SourceResolver.ROLE+"/Cocoon")) { + this.manager = manager; + if ( this.manager.hasService(org.apache.excalibur.source.SourceResolver.ROLE+"/Cocoon")) { this.customResolver = (org.apache.excalibur.source.SourceResolver) - manager.lookup(org.apache.excalibur.source.SourceResolver.ROLE+"/Cocoon"); + this.manager.lookup(org.apache.excalibur.source.SourceResolver.ROLE+"/Cocoon"); } } - /* (non-Javadoc) + /** * @see org.apache.avalon.framework.activity.Disposable#dispose() */ public void dispose() { - if ( this.m_manager != null ) { - this.m_manager.release( this.customResolver ); + if ( this.manager != null ) { + this.manager.release( this.customResolver ); this.customResolver = null; + this.manager = null; } - super.dispose(); } - /* (non-Javadoc) + /** + * Get the service manager. + */ + protected ServiceManager getServiceManager() { + ServiceManager m = EnvironmentHelper.getSitemapServiceManager(); + if ( m == null ) { + m = this.manager; + } + return m; + } + + /** + * Get the SourceFactory + */ + protected SourceFactory getSourceFactory(ServiceManager m, String scheme) + throws ServiceException { + return (SourceFactory)m.lookup(SourceFactory.ROLE + '/' + scheme); + } + + /** * @see org.apache.excalibur.source.SourceResolver#release(org.apache.excalibur.source.Source) */ public void release(Source source) { + if( source == null ) return; + if ( this.customResolver != null ) { this.customResolver.release( source ); } else { - super.release(source); + final ServiceManager m = this.getServiceManager(); + + // search for a SourceFactory implementing the protocol + final String scheme = source.getScheme(); + SourceFactory factory = null; + + try { + factory = this.getSourceFactory(m, scheme); + factory.release(source); + } catch (ServiceException se ) { + try { + factory = this.getSourceFactory(m, "*"); + factory.release(source); + } catch (ServiceException sse ) { + throw new CascadingRuntimeException( "Unable to select source factory for " + source.getURI(), se ); + } + } finally { + m.release( factory ); + } + } + } + + /** + * Makes an absolute URI based on a baseURI and a relative URI. + */ + protected String absolutize( SourceFactory factory, String baseURI, String systemID ) { + if( factory instanceof URIAbsolutizer ) { + systemID = ((URIAbsolutizer)factory).absolutize(baseURI, systemID); + } else { + systemID = org.apache.excalibur.source.SourceUtil.absolutize(baseURI, systemID); } + return systemID; } }