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: package org.apache.lenya.cms.cocoon.source;
019:
020: import java.io.IOException;
021: import java.net.MalformedURLException;
022: import java.util.ArrayList;
023: import java.util.Arrays;
024: import java.util.List;
025: import java.util.Map;
026:
027: import org.apache.avalon.framework.context.Context;
028: import org.apache.avalon.framework.context.ContextException;
029: import org.apache.avalon.framework.context.Contextualizable;
030: import org.apache.avalon.framework.logger.AbstractLogEnabled;
031: import org.apache.avalon.framework.service.ServiceException;
032: import org.apache.avalon.framework.service.ServiceManager;
033: import org.apache.avalon.framework.service.Serviceable;
034: import org.apache.cocoon.components.ContextHelper;
035: import org.apache.cocoon.environment.Request;
036: import org.apache.excalibur.source.Source;
037: import org.apache.excalibur.source.SourceFactory;
038: import org.apache.excalibur.source.SourceUtil;
039: import org.apache.excalibur.source.URIAbsolutizer;
040: import org.apache.lenya.cms.module.ModuleManager;
041: import org.apache.lenya.cms.publication.DocumentFactory;
042: import org.apache.lenya.cms.publication.DocumentUtil;
043: import org.apache.lenya.cms.publication.Publication;
044: import org.apache.lenya.cms.publication.PublicationManager;
045: import org.apache.lenya.cms.publication.URLInformation;
046: import org.apache.lenya.cms.publication.templating.AllExistingSourceResolver;
047: import org.apache.lenya.cms.publication.templating.PublicationTemplateManager;
048:
049: /**
050: * Aggregate all existing fallback URIs by merging their XML content under
051: * the document element of the first encountered source.
052: */
053: public class AggregatingFallbackSourceFactory extends
054: AbstractLogEnabled implements SourceFactory, Serviceable,
055: Contextualizable, URIAbsolutizer {
056:
057: public Source getSource(final String location, Map parameters)
058: throws IOException, MalformedURLException {
059:
060: // Remove the protocol and the first '//'
061: int pos = location.indexOf("://");
062:
063: if (pos == -1) {
064: throw new RuntimeException("The location [" + location
065: + "] does not contain the string '://'");
066: }
067:
068: String path = location.substring(pos + 3);
069: String publicationId = null;
070:
071: // allow for template-fallback://{pubid}//{path} for the sake of the
072: // cocoon use-store
073: if (path.indexOf("//") > 1) {
074: pos = path.indexOf("//");
075: publicationId = path.substring(0, pos);
076: path = path.substring(pos + 2, path.length());
077: }
078:
079: if (path.length() == 0) {
080: throw new RuntimeException(
081: "The path after the protocol must not be empty!");
082: }
083:
084: if (getLogger().isDebugEnabled()) {
085: getLogger().debug("Location: [" + location + "]");
086: getLogger().debug("Path: [" + path + "]");
087: }
088:
089: PublicationTemplateManager templateManager = null;
090: try {
091: templateManager = (PublicationTemplateManager) this .manager
092: .lookup(PublicationTemplateManager.ROLE);
093:
094: Request request = ContextHelper.getRequest(this .context);
095:
096: if (publicationId == null) {
097: String webappUrl = request.getRequestURI().substring(
098: request.getContextPath().length());
099:
100: URLInformation info = new URLInformation(webappUrl);
101: publicationId = info.getPublicationId();
102: }
103:
104: DocumentFactory factory = DocumentUtil.getDocumentFactory(
105: this .manager, request);
106:
107: String[] uris;
108:
109: if (factory.existsPublication(publicationId)) {
110: Publication pub = factory.getPublication(publicationId);
111: AllExistingSourceResolver resolver = new AllExistingSourceResolver();
112: templateManager.visit(pub, path, resolver);
113: uris = resolver.getUris();
114: } else {
115: uris = new String[0];
116: }
117:
118: List allUris = new ArrayList();
119: allUris.addAll(Arrays.asList(uris));
120:
121: String contextSourceUri = null;
122: if (path.startsWith("lenya/modules/")) {
123: ModuleManager moduleMgr = null;
124: try {
125: moduleMgr = (ModuleManager) this .manager
126: .lookup(ModuleManager.ROLE);
127: final String moduleShortcut = path.split("/")[2];
128: String baseUri = moduleMgr
129: .getBaseURI(moduleShortcut);
130: final String modulePath = path
131: .substring(("lenya/modules/" + moduleShortcut)
132: .length());
133: contextSourceUri = baseUri + modulePath;
134: } finally {
135: if (moduleMgr != null) {
136: this .manager.release(moduleMgr);
137: }
138: }
139: } else {
140: contextSourceUri = "context://" + path;
141: }
142: if (org.apache.lenya.cms.cocoon.source.SourceUtil.exists(
143: contextSourceUri, this .manager)) {
144: allUris.add(contextSourceUri);
145: }
146:
147: String[] aggregateUris = (String[]) allUris
148: .toArray(new String[allUris.size()]);
149: return new AggregatingSource(location, aggregateUris,
150: this .manager);
151:
152: } catch (Exception e) {
153: throw new RuntimeException("Resolving path [" + location
154: + "] failed: ", e);
155: } finally {
156: if (templateManager != null) {
157: this .manager.release(templateManager);
158: }
159: }
160: }
161:
162: public void release(Source source) {
163: }
164:
165: private ServiceManager manager;
166:
167: public void service(ServiceManager manager) throws ServiceException {
168: this .manager = manager;
169: }
170:
171: private Context context;
172:
173: public void contextualize(Context context) throws ContextException {
174: this .context = context;
175: }
176:
177: public String absolutize(String baseURI, String location) {
178: return SourceUtil.absolutize(baseURI, location, true);
179: }
180:
181: }
|