blob: d0a9169702d22b525df84fda8637dc61c4b8b5fc [file] [log] [blame]
/*
* Copyright 2002-2005 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.
*/
package org.apache.cocoon.core.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.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.logger.Logger;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.components.source.impl.ContextSourceFactory;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceResolver;
import org.apache.excalibur.source.impl.ResourceSourceFactory;
import org.apache.excalibur.source.impl.URLSourceFactory;
/**
* A minimalist <code>SourceResolver</code> that handles a fixed restricted number of protocols. It is
* used as a bootstrap resolver to load roles and imported files in a service manager.
* <p>
* The supported protocols schemes are:
* <ul>
* <li><code>resource</code> to load resources in the classpath,</li>
* <li><code>context</code> to load resources from the context, defined by the <code>context-root</code>
* entry in the Avalon {@link Context} (either a {@link File} or an {@link URL}), or if not
* present, from the <code>user.dir</code> system property,</li>
* <li>all standard JDK schemes (http, file, etc).
* </ul>
* Relative URIs are resolved relatively to the context root, i.e. similarily to "<code>context:</code>".
*
* @version $Id$
* @since 2.2
*/
public final class SimpleSourceResolver extends AbstractLogEnabled
implements ThreadSafe, Contextualizable, SourceResolver {
// The base URI, initialized in contextualize()
private String contextBase;
// The three factories we use (no need for a selector nor a Map)
private ResourceSourceFactory resourceFactory = new ResourceSourceFactory();
private URLSourceFactory urlFactory = new URLSourceFactory();
private ContextSourceFactory contextFactory = new ContextSourceFactory();
/* (non-Javadoc)
* @see org.apache.avalon.framework.logger.LogEnabled#enableLogging(org.apache.avalon.framework.logger.Logger)
*/
public void enableLogging(Logger logger) {
super.enableLogging(logger);
this.resourceFactory.enableLogging(logger);
this.urlFactory.enableLogging(logger);
this.contextFactory.enableLogging(logger);
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
*/
public void contextualize(Context context) throws ContextException {
this.contextFactory.contextualize(context);
try {
this.contextFactory.service(new SimpleServiceManager(this));
} catch (ServiceException se) {
throw new ContextException("Unable to service context factory.", se);
}
try {
// Similar to Excalibur's SourceResolverImpl, and consistent with ContextHelper.CONTEXT_ROOT_URL
if( context.get("context-root") instanceof URL) {
contextBase = ((URL)context.get("context-root")).toExternalForm();
} else {
contextBase = ((File)context.get("context-root")).toURL().toExternalForm();
}
} catch(ContextException ce) {
// set the base URL to the current directory
try {
contextBase = new File(System.getProperty("user.dir")).toURL().toExternalForm();
} catch( MalformedURLException mue) {
throw new ContextException( "Malformed URL for user.dir, and no context-root exists", mue);
}
} catch( MalformedURLException mue) {
throw new ContextException("Malformed URL for context-root", mue);
}
if (getLogger().isDebugEnabled()) {
getLogger().debug("Base URL set to " + this.contextBase);
}
}
/* (non-Javadoc)
* @see org.apache.excalibur.source.SourceResolver#resolveURI(java.lang.String)
*/
public Source resolveURI(String uri) throws MalformedURLException, IOException {
return resolveURI(uri, contextBase, null);
}
/* (non-Javadoc)
* @see org.apache.excalibur.source.SourceResolver#resolveURI(java.lang.String, java.lang.String, java.util.Map)
*/
public Source resolveURI(String uri, String base, Map params) throws MalformedURLException, IOException {
if (uri.startsWith("resource://")) {
return resourceFactory.getSource(uri, null);
} else if (uri.startsWith("context://")) {
return this.contextFactory.getSource(uri, params);
} else {
// special handling for windows and unix file paths
if( uri.length() > 1 && uri.charAt( 1 ) == ':' ) {
uri = "file:/" + uri;
base = null;
} else if( uri.length() > 2 && uri.charAt(0) == '/' && uri.charAt(2) == ':' ) {
uri = "file:" + uri;
base = null;
}
URL url;
if ( base == null ) {
url = new URL(uri);
} else {
URL baseURL = new URL(base);
url = new URL(baseURL, uri);
}
return this.urlFactory.getSource(url.toExternalForm(), params);
}
}
/* (non-Javadoc)
* @see org.apache.excalibur.source.SourceResolver#release(org.apache.excalibur.source.Source)
*/
public void release(Source source) {
if ( source != null ) {
if ( "context".equals(source.getScheme()) ) {
this.contextFactory.release(source);
} else if ( "resource".equals(source.getScheme()) ) {
this.resourceFactory.release(source);
} else {
this.urlFactory.release(source);
}
}
}
public static final class SimpleServiceManager implements ServiceManager {
private final SourceResolver resolver;
public SimpleServiceManager(SourceResolver resolver) {
this.resolver = resolver;
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.service.ServiceManager#hasService(java.lang.String)
*/
public boolean hasService(String role) {
return SourceResolver.ROLE.equals(role);
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.service.ServiceManager#lookup(java.lang.String)
*/
public Object lookup(String role) throws ServiceException {
if ( !SourceResolver.ROLE.equals(role) ) {
throw new ServiceException("SimpleServiceManager", "Unable to lookup component with role: " + role);
}
return this.resolver;
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.service.ServiceManager#release(java.lang.Object)
*/
public void release(Object component) {
// nothing to do
}
}
}