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.Map;
023:
024: import org.apache.avalon.framework.configuration.Configurable;
025: import org.apache.avalon.framework.configuration.Configuration;
026: import org.apache.avalon.framework.configuration.ConfigurationException;
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.avalon.framework.thread.ThreadSafe;
035: import org.apache.cocoon.components.ContextHelper;
036: import org.apache.cocoon.environment.ObjectModelHelper;
037: import org.apache.cocoon.environment.Request;
038: import org.apache.excalibur.source.Source;
039: import org.apache.excalibur.source.SourceException;
040: import org.apache.excalibur.source.SourceFactory;
041: import org.apache.lenya.cms.publication.Document;
042: import org.apache.lenya.cms.publication.DocumentBuildException;
043: import org.apache.lenya.cms.publication.DocumentFactory;
044: import org.apache.lenya.cms.publication.DocumentUtil;
045: import org.apache.lenya.cms.publication.Publication;
046: import org.apache.lenya.cms.publication.PublicationException;
047: import org.apache.lenya.cms.publication.PublicationUtil;
048: import org.apache.lenya.cms.publication.URLInformation;
049: import org.apache.lenya.cms.repository.RepositoryException;
050: import org.apache.lenya.cms.repository.RepositoryUtil;
051: import org.apache.lenya.cms.repository.Session;
052: import org.apache.lenya.util.ServletHelper;
053:
054: /**
055: * A factory for the "lenyadoc" scheme (virtual protocol), which is used to resolve any
056: * src="lenyadoc:<...>" attributes in sitemaps.
057: *
058: * <code>lenyadoc://<publication>/<area>/<language>/<uuid></code>
059: * <code>lenyadoc:/<language>/<uuid></code>
060: *
061: * If we want to request the meta data for a document
062: * instead of the document itself, we need to use
063: *
064: * <code>lenyadoc:meta:/<language>/<uuid></code>
065: * <code>lenyadoc:meta://<publication>/<area>/<language>/<uuid></code>
066: *
067: * @version $Id:$
068: */
069: public class LenyaDocSourceFactory extends AbstractLogEnabled implements
070: SourceFactory, ThreadSafe, Contextualizable, Serviceable,
071: Configurable {
072:
073: protected static final String SCHEME = "lenyadoc";
074:
075: private Context context;
076: private ServiceManager manager;
077:
078: /**
079: * Used for resolving the object model.
080: * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
081: */
082: public void contextualize(Context context) throws ContextException {
083: this .context = context;
084: }
085:
086: /**
087: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
088: */
089: public void service(ServiceManager manager) throws ServiceException {
090: this .manager = manager;
091: }
092:
093: /**
094: * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
095: */
096: public void configure(Configuration configuration)
097: throws ConfigurationException {
098: }
099:
100: /**
101: * @see org.apache.excalibur.source.SourceFactory#getSource(java.lang.String, java.util.Map)
102: */
103: public Source getSource(String location, Map parameters)
104: throws MalformedURLException, IOException, SourceException {
105: String scheme = null;
106: String area = null;
107: String language = null;
108: String uuid = null;
109: Publication pub;
110:
111: // Parse the url
112: int start = 0;
113: int end;
114:
115: // Scheme
116: end = location.indexOf(':', start);
117: if (end == -1) {
118: throw new MalformedURLException(
119: "Malformed lenyadoc: URI: can not find scheme part ["
120: + location + "]");
121: }
122: scheme = location.substring(start, end);
123: if (!SCHEME.equals(scheme)) {
124: throw new MalformedURLException(
125: "Malformed lenyadoc: URI: unknown scheme ["
126: + location + "]");
127: }
128:
129: Map objectModel = ContextHelper.getObjectModel(this .context);
130: Request request = ObjectModelHelper.getRequest(objectModel);
131: DocumentFactory factory = DocumentUtil.getDocumentFactory(
132: this .manager, request);
133:
134: start = end + 1;
135:
136: // Absolute vs. relative
137: if (location.startsWith("//", start)) {
138: // Absolute: get publication id
139: start += 2;
140: end = location.indexOf('/', start);
141: if (end == -1) {
142: throw new MalformedURLException(
143: "Malformed lenyadoc: URI: publication part not found ["
144: + location + "]");
145: }
146: String publicationId = location.substring(start, end);
147: try {
148: pub = factory.getPublication(publicationId);
149: } catch (PublicationException e) {
150: throw new MalformedURLException(
151: "Malformed lenyadoc: Publication ["
152: + publicationId
153: + "] does not exist or could not be initialized");
154: }
155: if (pub == null || !pub.exists()) {
156: throw new SourceException("The publication ["
157: + publicationId + "] does not exist!");
158: }
159:
160: // Area
161: start = end + 1;
162: end = location.indexOf('/', start);
163: if (end == -1) {
164: throw new MalformedURLException(
165: "Malformed lenyadoc: URI: cannot find area ["
166: + location + "]");
167: }
168: area = location.substring(start, end);
169:
170: } else if (location.startsWith("/", start)) {
171: end += 1;
172: // Relative: get publication id and area from page envelope
173: try {
174: pub = PublicationUtil.getPublication(this .manager,
175: objectModel);
176: } catch (PublicationException e) {
177: throw new SourceException(
178: "Error getting publication id / area from page envelope ["
179: + location + "]");
180: }
181: if (pub != null && pub.exists()) {
182: String url = ServletHelper.getWebappURI(request);
183: area = new URLInformation(url).getArea();
184: } else {
185: throw new SourceException(
186: "Error getting publication id / area from page envelope ["
187: + location + "]");
188: }
189: } else {
190: throw new MalformedURLException("Malformed lenyadoc: URI ["
191: + location + "]");
192: }
193:
194: // Language
195: start = end + 1;
196: end = location.indexOf('/', start);
197: if (end == -1) {
198: throw new MalformedURLException(
199: "Malformed lenyadoc: URI: cannot find language ["
200: + location + "]");
201: }
202: language = location.substring(start, end);
203:
204: // UUID
205: start = end + 1;
206: uuid = location.substring(start);
207:
208: Session session;
209: try {
210: session = RepositoryUtil.getSession(this .manager, request);
211: } catch (RepositoryException e1) {
212: throw new RuntimeException(e1);
213: }
214:
215: if (getLogger().isDebugEnabled()) {
216: getLogger().debug(
217: "Creating repository source for URI [" + location
218: + "]");
219: }
220: Document document;
221: try {
222: document = factory.get(pub, area, uuid, language);
223: } catch (DocumentBuildException e) {
224: throw new MalformedURLException(
225: "Malformed lenyadoc: Document [" + uuid + ":"
226: + language + "] could not be created.");
227: }
228:
229: String lenyaURL = document.getSourceURI();
230:
231: if (getLogger().isDebugEnabled()) {
232: getLogger().debug(
233: "Mapping 'lenyadoc:' URL [" + location
234: + "] to 'lenya:' URL [" + lenyaURL + "]");
235: getLogger().debug(
236: "Creating repository source for URI [" + lenyaURL
237: + "]");
238: }
239:
240: return new RepositorySource(manager, lenyaURL, session,
241: getLogger());
242: }
243:
244: /**
245: * @see org.apache.excalibur.source.SourceFactory#release(org.apache.excalibur.source.Source)
246: */
247: public void release(Source source) {
248: // Source will be released by delegated source factory.
249: }
250: }
|