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.excalibur.source.SourceResolver;
042: import org.apache.lenya.cms.linking.Link;
043: import org.apache.lenya.cms.linking.LinkResolver;
044: import org.apache.lenya.cms.linking.LinkTarget;
045: import org.apache.lenya.cms.publication.Document;
046: import org.apache.lenya.cms.publication.DocumentException;
047: import org.apache.lenya.cms.publication.DocumentFactory;
048: import org.apache.lenya.cms.publication.DocumentUtil;
049: import org.apache.lenya.cms.publication.URLInformation;
050: import org.apache.lenya.util.Query;
051: import org.apache.lenya.util.ServletHelper;
052:
053: /**
054: * <p>
055: * This source factory allows to access documents using the link syntax of the
056: * {@link org.apache.lenya.cms.linking.LinkResolver}.
057: * </p>
058: * <p>
059: * Additional optional parameters, separated using <code>...?f=foo&b=bar</code>:
060: * </p>
061: * <ul>
062: * <li><strong>format</strong> - the resource type format</li>
063: * <li><strong>session</strong> - the session.
064: * To use the session of the current usecase, specify <code>session=usecase</code></li>
065: * </ul>
066: */
067: public class DocumentSourceFactory extends AbstractLogEnabled implements
068: SourceFactory, ThreadSafe, Contextualizable, Serviceable,
069: Configurable {
070:
071: /**
072: * The URI scheme.
073: */
074: public static final String SCHEME = "lenya-document";
075:
076: private Context context;
077: private ServiceManager manager;
078:
079: /**
080: * Used for resolving the object model.
081: *
082: * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
083: */
084: public void contextualize(Context context) throws ContextException {
085: this .context = context;
086: }
087:
088: private SourceResolver sourceResolver;
089:
090: /**
091: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
092: */
093: public void service(ServiceManager manager) throws ServiceException {
094: this .manager = manager;
095: }
096:
097: /**
098: * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
099: */
100: public void configure(Configuration configuration)
101: throws ConfigurationException {
102: }
103:
104: /**
105: * @see org.apache.excalibur.source.SourceFactory#getSource(java.lang.String,
106: * java.util.Map)
107: */
108: public Source getSource(String location, Map parameters)
109: throws MalformedURLException, IOException, SourceException {
110:
111: Map objectModel = ContextHelper.getObjectModel(this .context);
112: Request request = ObjectModelHelper.getRequest(objectModel);
113:
114: String[] uriAndQuery = location.split("\\?");
115:
116: String linkUri = uriAndQuery[0];
117: String queryString = null;
118: if (uriAndQuery.length > 1) {
119: queryString = uriAndQuery[1];
120: }
121:
122: LinkResolver resolver = null;
123: try {
124: if (this .sourceResolver == null) {
125: this .sourceResolver = (SourceResolver) this .manager
126: .lookup(SourceResolver.ROLE);
127: }
128:
129: resolver = (LinkResolver) this .manager
130: .lookup(LinkResolver.ROLE);
131: DocumentFactory factory = DocumentUtil.getDocumentFactory(
132: this .manager, request);
133: String webappUrl = ServletHelper.getWebappURI(request);
134: LinkTarget target;
135: if (factory.isDocument(webappUrl)) {
136: Document currentDoc = factory.getFromURL(webappUrl);
137: target = resolver.resolve(currentDoc, linkUri);
138: } else {
139: Link link = new Link(linkUri);
140: contextualize(link, webappUrl);
141: target = resolver.resolve(factory, link.getUri());
142: }
143:
144: Document doc = target.getDocument();
145:
146: if (target.isRevisionSpecified()) {
147: if (queryString == null) {
148: queryString = "";
149: }
150: queryString += "rev=" + target.getRevisionNumber();
151: }
152:
153: String format = null;
154: if (queryString != null) {
155: Query query = new Query(queryString);
156: format = query.getValue("format");
157: }
158: if (format != null) {
159: return getFormatSource(doc, format);
160: } else {
161: String lenyaURL = doc.getSourceURI();
162: if (queryString != null) {
163: lenyaURL += "?" + queryString;
164: }
165: return this .sourceResolver.resolveURI(lenyaURL);
166: }
167:
168: } catch (Exception e) {
169: throw new RuntimeException(e);
170: }
171:
172: }
173:
174: /**
175: * If the link doesn't contain context information (publication ID, area), provide it.
176: * @param link The link.
177: * @param webappUrl The web application URL to extract the context information from..
178: */
179: protected void contextualize(Link link, String webappUrl) {
180: URLInformation url = new URLInformation(webappUrl);
181: if (link.getPubId() == null) {
182: link.setPubId(url.getPublicationId());
183: }
184: if (link.getArea() == null) {
185: link.setArea(url.getArea());
186: }
187: }
188:
189: protected Source getFormatSource(Document doc, String format)
190: throws DocumentException, ServiceException, IOException {
191: String formatBaseUri = doc.getResourceType().getFormatURI(
192: format);
193: String formatUri = formatBaseUri + "/"
194: + doc.getPublication().getId() + "/" + doc.getArea()
195: + "/" + doc.getUUID() + "/" + doc.getLanguage();
196:
197: return this .sourceResolver.resolveURI(formatUri);
198: }
199:
200: /**
201: * @see org.apache.excalibur.source.SourceFactory#release(org.apache.excalibur.source.Source)
202: */
203: public void release(Source source) {
204: this.sourceResolver.release(source);
205: }
206:
207: }
|