001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.util;
018:
019: import java.io.File;
020: import java.io.IOException;
021: import java.net.MalformedURLException;
022: import java.net.URL;
023: import java.util.Map;
024:
025: import org.apache.avalon.framework.context.Context;
026: import org.apache.avalon.framework.context.ContextException;
027: import org.apache.avalon.framework.context.Contextualizable;
028: import org.apache.avalon.framework.logger.AbstractLogEnabled;
029: import org.apache.avalon.framework.logger.Logger;
030: import org.apache.avalon.framework.service.ServiceException;
031: import org.apache.avalon.framework.service.ServiceManager;
032: import org.apache.avalon.framework.thread.ThreadSafe;
033: import org.apache.cocoon.components.source.impl.ContextSourceFactory;
034: import org.apache.excalibur.source.Source;
035: import org.apache.excalibur.source.SourceResolver;
036: import org.apache.excalibur.source.impl.ResourceSourceFactory;
037: import org.apache.excalibur.source.impl.URLSourceFactory;
038:
039: /**
040: * A minimalist <code>SourceResolver</code> that handles a fixed restricted number of protocols. It is
041: * used as a bootstrap resolver to load roles and imported files in a service manager.
042: * <p>
043: * The supported protocols schemes are:
044: * <ul>
045: * <li><code>resource</code> to load resources in the classpath,</li>
046: * <li><code>context</code> to load resources from the context, defined by the <code>context-root</code>
047: * entry in the Avalon {@link Context} (either a {@link File} or an {@link URL}), or if not
048: * present, from the <code>user.dir</code> system property,</li>
049: * <li>all standard JDK schemes (http, file, etc).
050: * </ul>
051: * Relative URIs are resolved relatively to the context root, i.e. similarily to "<code>context:</code>".
052: *
053: * @version $Id: SimpleSourceResolver.java 433543 2006-08-22 06:22:54Z crossley $
054: */
055: public final class SimpleSourceResolver extends AbstractLogEnabled
056: implements ThreadSafe, Contextualizable, SourceResolver {
057:
058: // The base URI, initialized in contextualize()
059: private String contextBase;
060:
061: // The three factories we use (no need for a selector nor a Map)
062: private ResourceSourceFactory resourceFactory = new ResourceSourceFactory();
063: private URLSourceFactory urlFactory = new URLSourceFactory();
064: private ContextSourceFactory contextFactory = new ContextSourceFactory();
065:
066: /* (non-Javadoc)
067: * @see org.apache.avalon.framework.logger.LogEnabled#enableLogging(org.apache.avalon.framework.logger.Logger)
068: */
069: public void enableLogging(Logger logger) {
070: super .enableLogging(logger);
071: this .resourceFactory.enableLogging(logger);
072: this .urlFactory.enableLogging(logger);
073: this .contextFactory.enableLogging(logger);
074: }
075:
076: /* (non-Javadoc)
077: * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
078: */
079: public void contextualize(Context context) throws ContextException {
080: this .contextFactory.contextualize(context);
081: try {
082: this .contextFactory.service(new SimpleServiceManager(this ));
083: } catch (ServiceException se) {
084: throw new ContextException(
085: "Unable to service context factory.", se);
086: }
087:
088: try {
089: // Similar to Excalibur's SourceResolverImpl, and consistent with ContextHelper.CONTEXT_ROOT_URL
090: if (context.get("context-root") instanceof URL) {
091: contextBase = ((URL) context.get("context-root"))
092: .toExternalForm();
093: } else {
094: contextBase = ((File) context.get("context-root"))
095: .toURL().toExternalForm();
096: }
097: } catch (ContextException ce) {
098: // set the base URL to the current directory
099: try {
100: contextBase = new File(System.getProperty("user.dir"))
101: .toURL().toExternalForm();
102: } catch (MalformedURLException mue) {
103: throw new ContextException(
104: "Malformed URL for user.dir, and no context-root exists",
105: mue);
106: }
107: } catch (MalformedURLException mue) {
108: throw new ContextException(
109: "Malformed URL for context-root", mue);
110: }
111:
112: if (getLogger().isDebugEnabled()) {
113: getLogger().debug("Base URL set to " + this .contextBase);
114: }
115: }
116:
117: /* (non-Javadoc)
118: * @see org.apache.excalibur.source.SourceResolver#resolveURI(java.lang.String)
119: */
120: public Source resolveURI(String uri) throws MalformedURLException,
121: IOException {
122: return resolveURI(uri, contextBase, null);
123: }
124:
125: /* (non-Javadoc)
126: * @see org.apache.excalibur.source.SourceResolver#resolveURI(java.lang.String, java.lang.String, java.util.Map)
127: */
128: public Source resolveURI(String uri, String base, Map params)
129: throws MalformedURLException, IOException {
130: if (uri.startsWith("resource://")) {
131: return resourceFactory.getSource(uri, null);
132: } else if (uri.startsWith("context://")) {
133: return this .contextFactory.getSource(uri, params);
134: } else {
135: // special handling for windows and unix file paths
136: if (uri.length() > 1 && uri.charAt(1) == ':') {
137: uri = "file:/" + uri;
138: base = null;
139: } else if (uri.length() > 2 && uri.charAt(0) == '/'
140: && uri.charAt(2) == ':') {
141: uri = "file:" + uri;
142: base = null;
143: }
144: URL url;
145: if (base == null) {
146: url = new URL(uri);
147: } else {
148: URL baseURL = new URL(base);
149: url = new URL(baseURL, uri);
150: }
151: return this .urlFactory.getSource(url.toExternalForm(),
152: params);
153: }
154: }
155:
156: /* (non-Javadoc)
157: * @see org.apache.excalibur.source.SourceResolver#release(org.apache.excalibur.source.Source)
158: */
159: public void release(Source source) {
160: if (source != null) {
161: if ("context".equals(source.getScheme())) {
162: this .contextFactory.release(source);
163: } else if ("resource".equals(source.getScheme())) {
164: this .resourceFactory.release(source);
165: } else {
166: this .urlFactory.release(source);
167: }
168: }
169: }
170:
171: public static final class SimpleServiceManager implements
172: ServiceManager {
173:
174: private final SourceResolver resolver;
175:
176: public SimpleServiceManager(SourceResolver resolver) {
177: this .resolver = resolver;
178: }
179:
180: /* (non-Javadoc)
181: * @see org.apache.avalon.framework.service.ServiceManager#hasService(java.lang.String)
182: */
183: public boolean hasService(String role) {
184: return SourceResolver.ROLE.equals(role);
185: }
186:
187: /* (non-Javadoc)
188: * @see org.apache.avalon.framework.service.ServiceManager#lookup(java.lang.String)
189: */
190: public Object lookup(String role) throws ServiceException {
191: if (!SourceResolver.ROLE.equals(role)) {
192: throw new ServiceException("SimpleServiceManager",
193: "Unable to lookup component with role: " + role);
194: }
195: return this .resolver;
196: }
197:
198: /* (non-Javadoc)
199: * @see org.apache.avalon.framework.service.ServiceManager#release(java.lang.Object)
200: */
201: public void release(Object component) {
202: // nothing to do
203: }
204: }
205: }
|