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: */
018:
019: package org.apache.lenya.cms.cocoon.components.modules.input;
020:
021: import java.io.File;
022: import java.util.ArrayList;
023: import java.util.Collections;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Map;
027:
028: import org.apache.avalon.framework.configuration.Configuration;
029: import org.apache.avalon.framework.configuration.ConfigurationException;
030: import org.apache.excalibur.source.Source;
031: import org.apache.excalibur.source.SourceResolver;
032: import org.apache.excalibur.source.SourceUtil;
033:
034: /**
035: * <p>
036: * This module checks if a file exists in a publiation, and if not, it chooses the core file. The
037: * attribute name must a path relatively to the <code>webapps/lenya/lenya</code> directory.
038: * </p>
039: * <p>
040: * Example: <code>{fallback:xslt/style.xsl}</code> looks if
041: * <code>lenya/pubs/(publication-id)/lenya/xslt/style.xsl</code> exists, and if not, it uses
042: * <code>lenya/xslt/style.xsl</code>.
043: *
044: * @version $Id: FallbackModule.java 473861 2006-11-12 03:51:14Z gregor $
045: */
046: public class FallbackModule extends AbstractPageEnvelopeModule {
047:
048: private String[] baseUris;
049:
050: /**
051: * <code>PATH_PREFIX</code> The path prefix from the webapp
052: */
053: public static final String PATH_PREFIX = "lenya/";
054:
055: protected static final String ELEMENT_PATH = "directory";
056:
057: protected static final String ATTRIBUTE_SRC = "src";
058:
059: /**
060: * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
061: */
062: public void configure(Configuration conf)
063: throws ConfigurationException {
064: super .configure(conf);
065:
066: Configuration[] pathConfigs = conf.getChildren(ELEMENT_PATH);
067: List baseUriList = new ArrayList();
068:
069: SourceResolver resolver = null;
070: try {
071: resolver = (SourceResolver) this .manager
072: .lookup(SourceResolver.ROLE);
073: Source source = null;
074: for (int i = 0; i < pathConfigs.length; i++) {
075: String uri = pathConfigs[i].getAttribute(ATTRIBUTE_SRC);
076: try {
077: source = resolver.resolveURI(uri);
078: if (source.exists()) {
079: File file = SourceUtil.getFile(source);
080: if (file.isDirectory()) {
081: baseUriList.add(uri);
082: } else {
083: getLogger().warn(
084: "Omitting path [" + uri
085: + "] (not a directory).");
086: }
087: } else {
088: getLogger().warn(
089: "Omitting path [" + uri
090: + "] (does not exist).");
091: }
092: } catch (Exception e) {
093: getLogger()
094: .error(
095: "Could not resolve path [" + uri
096: + "]: ", e);
097: throw e;
098: } finally {
099: if (source != null) {
100: resolver.release(source);
101: }
102: }
103: }
104: } catch (Exception e) {
105: throw new ConfigurationException("Configuring failed: ", e);
106: } finally {
107: if (resolver != null) {
108: this .manager.release(resolver);
109: }
110: }
111:
112: this .baseUris = (String[]) baseUriList
113: .toArray(new String[baseUriList.size()]);
114: }
115:
116: /**
117: * @see org.apache.cocoon.components.modules.input.InputModule#getAttribute(java.lang.String,
118: * org.apache.avalon.framework.configuration.Configuration, java.util.Map)
119: */
120: public Object getAttribute(String name, Configuration modeConf,
121: Map objectModel) throws ConfigurationException {
122:
123: if (getLogger().isDebugEnabled()) {
124: getLogger().debug("Resolving file for path [" + name + "]");
125: }
126:
127: String resolvedUri = resolveURI(name, objectModel);
128: return resolvedUri;
129: }
130:
131: /**
132: * Resolves the URI for a certain path.
133: * @param path The path.
134: * @param objectModel The object model.
135: * @return A string.
136: * @throws ConfigurationException if an error occurs.
137: */
138: protected String resolveURI(final String path, Map objectModel)
139: throws ConfigurationException {
140: String resolvedUri = null;
141: String checkedUris = "\n";
142:
143: SourceResolver resolver = null;
144: try {
145: resolver = (SourceResolver) this .manager
146: .lookup(SourceResolver.ROLE);
147:
148: String[] _baseUris = getBaseURIs(objectModel, path);
149: Source source = null;
150: int i = 0;
151: while (resolvedUri == null && i < _baseUris.length) {
152: String uri = _baseUris[i] + "/" + path;
153:
154: checkedUris += uri + "\n";
155:
156: if (getLogger().isDebugEnabled()) {
157: getLogger().debug(
158: "Trying to resolve URI [" + uri + "]");
159: }
160:
161: try {
162: source = resolver.resolveURI(uri);
163: if (source.exists()) {
164: resolvedUri = uri;
165: } else {
166: if (getLogger().isDebugEnabled()) {
167: getLogger().debug(
168: "Skipping URI [" + uri
169: + "] (does not exist).");
170: }
171: }
172: } catch (Exception e) {
173: getLogger().error(
174: "Could not resolve URI [" + uri + "]: ", e);
175: throw e;
176: } finally {
177: if (source != null) {
178: resolver.release(source);
179: }
180: }
181: i++;
182: }
183:
184: } catch (Exception e) {
185: throw new ConfigurationException("Resolving attribute ["
186: + path + "] failed: ", e);
187: } finally {
188: if (resolver != null) {
189: this .manager.release(resolver);
190: }
191: }
192:
193: if (resolvedUri == null) {
194: /*
195: throw new ConfigurationException("Could not resolve file for path [" + path + "]."
196: + "\nChecked URIs:" + checkedUris);
197: */
198: resolvedUri = this .baseUris[this .baseUris.length - 1] + "/"
199: + path;
200: if (getLogger().isDebugEnabled()) {
201: getLogger().debug(
202: "No URI resolved, choosing last defined URI: ["
203: + resolvedUri + "]");
204: }
205: } else {
206: if (getLogger().isDebugEnabled()) {
207: getLogger()
208: .debug("Resolved URI: [" + resolvedUri + "]");
209: }
210: }
211: return resolvedUri;
212: }
213:
214: /**
215: * Returns the base directory URIs in the order they should be traversed.
216: * @param objectModel The object model.
217: * @param attributeName The name of the module attribute.
218: * @return An array of strings.
219: * @throws ConfigurationException if an error occurs.
220: */
221: protected String[] getBaseURIs(Map objectModel, String attributeName)
222: throws ConfigurationException {
223: return this .baseUris;
224: }
225:
226: /**
227: * @see org.apache.cocoon.components.modules.input.InputModule#getAttributeNames(org.apache.avalon.framework.configuration.Configuration,
228: * java.util.Map)
229: */
230: public Iterator getAttributeNames(Configuration modeConf,
231: Map objectModel) throws ConfigurationException {
232: return Collections.EMPTY_SET.iterator();
233: }
234:
235: /**
236: * @see org.apache.cocoon.components.modules.input.InputModule#getAttributeValues(java.lang.String,
237: * org.apache.avalon.framework.configuration.Configuration, java.util.Map)
238: */
239: public Object[] getAttributeValues(String name,
240: Configuration modeConf, Map objectModel)
241: throws ConfigurationException {
242: Object[] objects = { getAttribute(name, modeConf, objectModel) };
243:
244: return objects;
245: }
246:
247: }
|