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.io.InputStream;
022: import java.io.OutputStream;
023: import java.io.PipedInputStream;
024: import java.io.PipedOutputStream;
025: import java.net.MalformedURLException;
026: import java.util.Collection;
027:
028: import javax.xml.transform.Transformer;
029: import javax.xml.transform.TransformerException;
030: import javax.xml.transform.TransformerFactory;
031: import javax.xml.transform.dom.DOMSource;
032: import javax.xml.transform.stream.StreamResult;
033:
034: import org.apache.avalon.framework.logger.Logger;
035: import org.apache.avalon.framework.service.ServiceManager;
036: import org.apache.cocoon.environment.Request;
037: import org.apache.excalibur.source.ModifiableTraversableSource;
038: import org.apache.excalibur.source.Source;
039: import org.apache.excalibur.source.SourceException;
040: import org.apache.excalibur.source.SourceNotFoundException;
041: import org.apache.excalibur.source.SourceValidity;
042: import org.apache.excalibur.source.impl.AbstractSource;
043: import org.apache.lenya.cms.cocoon.components.context.ContextUtility;
044: import org.apache.lenya.cms.publication.Document;
045: import org.apache.lenya.cms.publication.Publication;
046: import org.apache.lenya.cms.publication.PublicationUtil;
047: import org.apache.lenya.cms.repository.ContentHolder;
048: import org.apache.lenya.cms.repository.Node;
049: import org.apache.lenya.cms.repository.NodeFactory;
050: import org.apache.lenya.cms.repository.RepositoryException;
051: import org.apache.lenya.cms.repository.Session;
052: import org.apache.lenya.util.Query;
053: import org.apache.lenya.util.ServletHelper;
054:
055: /**
056: * Repository source.
057: *
058: * @version $Id: RepositorySource.java 569341 2007-08-24 10:47:38Z andreas $
059: */
060: public class RepositorySource extends AbstractSource implements
061: ModifiableTraversableSource {
062:
063: private ServiceManager manager;
064: private ContentHolder content;
065: private Session session;
066: private Logger logger;
067: protected static final String SCHEME = "lenya";
068:
069: /**
070: * @param manager The service manager.
071: * @param uri The source URI.
072: * @param session The repository session.
073: * @param logger The logger.
074: * @throws SourceException if an error occurs.
075: * @throws MalformedURLException if an error occurs.
076: */
077: public RepositorySource(ServiceManager manager, String uri,
078: Session session, Logger logger) throws SourceException,
079: MalformedURLException {
080: this .manager = manager;
081: this .logger = logger;
082:
083: if (getLogger().isDebugEnabled())
084: getLogger().debug("Init RepositorySource: " + uri);
085:
086: if (session == null) {
087: throw new IllegalArgumentException(
088: "The repository session must not be null!");
089: }
090: this .session = session;
091:
092: if (uri == null) {
093: throw new MalformedURLException(
094: "The source URI must not be null!");
095: }
096:
097: setSystemId(uri);
098:
099: // Scheme
100: int start = 0;
101: int end = uri.indexOf(':');
102: if (end == -1)
103: throw new MalformedURLException(
104: "Malformed uri for xmodule source (cannot find scheme) : "
105: + uri);
106:
107: String scheme = uri.substring(start, end);
108: if (!SCHEME.equals(scheme))
109: throw new MalformedURLException(
110: "Malformed uri for a xmodule source : " + uri);
111:
112: setScheme(scheme);
113:
114: NodeFactory factory = null;
115: try {
116: factory = (NodeFactory) this .manager
117: .lookup(NodeFactory.ROLE);
118:
119: String sourceUri;
120: int revisionNumber = -1;
121:
122: int questionMarkIndex = uri.indexOf("?");
123: if (questionMarkIndex > -1) {
124: sourceUri = uri.substring(0, questionMarkIndex);
125: Query query = new Query(uri
126: .substring(questionMarkIndex + 1));
127: String revisionString = query.getValue("rev", null);
128: if (revisionString != null) {
129:
130: ContextUtility util = null;
131: try {
132: util = (ContextUtility) this .manager
133: .lookup(ContextUtility.ROLE);
134: Request request = util.getRequest();
135: String webappUrl = ServletHelper
136: .getWebappURI(request);
137:
138: Publication pub = PublicationUtil
139: .getPublication(this .manager, request);
140: Document currentDoc = pub.getFactory()
141: .getFromURL(webappUrl);
142: if (currentDoc.getSourceURI().equals(sourceUri)) {
143: revisionNumber = Integer.valueOf(
144: revisionString).intValue();
145: }
146: } finally {
147: if (util != null) {
148: this .manager.release(util);
149: }
150: }
151: }
152: } else {
153: sourceUri = uri;
154: }
155:
156: if (revisionNumber == -1) {
157: this .content = (ContentHolder) session
158: .getRepositoryItem(factory, sourceUri);
159: } else {
160: Node node = (Node) session.getRepositoryItem(factory,
161: sourceUri);
162: this .content = node.getHistory().getRevision(
163: revisionNumber);
164: }
165:
166: } catch (Exception e) {
167: throw new SourceException(
168: "Creating repository node failed: ", e);
169: } finally {
170: if (factory != null) {
171: this .manager.release(factory);
172: }
173: }
174: }
175:
176: /**
177: * @return The repository node which is accessed by this source.
178: */
179: public Node getNode() {
180:
181: if (!(this .content instanceof Node)) {
182: throw new RuntimeException(
183: "This operation can only be invoked on nodes, not on revisions.");
184: }
185:
186: return (Node) this .content;
187: }
188:
189: protected Logger getLogger() {
190: return this .logger;
191: }
192:
193: /**
194: * @see org.apache.excalibur.source.ModifiableSource#getOutputStream()
195: */
196: public OutputStream getOutputStream() throws IOException {
197: try {
198: return getNode().getOutputStream();
199: } catch (RepositoryException e) {
200: throw new RuntimeException(e);
201: }
202: }
203:
204: /**
205: * @see org.apache.excalibur.source.ModifiableSource#delete()
206: */
207: public void delete() {
208: try {
209: getNode().delete();
210: } catch (RepositoryException e) {
211: throw new RuntimeException(e);
212: }
213: }
214:
215: /**
216: * @see org.apache.excalibur.source.ModifiableSource#canCancel(java.io.OutputStream)
217: */
218: public boolean canCancel(OutputStream arg0) {
219: return false;
220: }
221:
222: /**
223: * @see org.apache.excalibur.source.ModifiableSource#cancel(java.io.OutputStream)
224: */
225: public void cancel(OutputStream arg0) throws IOException {
226: }
227:
228: /**
229: * @see org.apache.excalibur.source.Source#exists()
230: */
231: public boolean exists() {
232: try {
233: if (getContent().exists()) {
234: return true;
235: } else {
236: return isCollection();
237: }
238: } catch (RepositoryException e) {
239: throw new RuntimeException(e);
240: }
241: }
242:
243: /**
244: * @see org.apache.excalibur.source.Source#getInputStream()
245: */
246: public InputStream getInputStream() throws IOException,
247: SourceNotFoundException {
248: if (getLogger().isDebugEnabled())
249: getLogger().debug("Get InputStream for " + getURI());
250: if (!exists()) {
251: throw new SourceNotFoundException("The source [" + getURI()
252: + "] does not exist!");
253: }
254: try {
255: return getContent().getInputStream();
256: } catch (RepositoryException e) {
257: throw new RuntimeException(e);
258: }
259: }
260:
261: protected InputStream convert(org.w3c.dom.Document edoc)
262: throws IOException {
263:
264: final org.w3c.dom.Document doc = edoc;
265: final PipedOutputStream pos = new PipedOutputStream();
266: PipedInputStream pis = new PipedInputStream();
267: pis.connect(pos);
268:
269: (new Thread(new Runnable() {
270:
271: public void run() {
272: try {
273: transform(doc, pos);
274: } catch (TransformerException e) {
275: throw new RuntimeException(
276: "Failed to tranform org.w3c.dom.Document to PipedOutputStream",
277: e);
278: } finally {
279: try {
280: pos.close();
281: } catch (Exception ignore) {
282: ignore.printStackTrace();
283: }
284: }
285: }
286: }, getClass().getName() + ".convert(org.w3c.dom.Document edoc)"))
287: .start();
288:
289: return pis;
290: }
291:
292: void transform(org.w3c.dom.Document edoc, PipedOutputStream pos)
293: throws TransformerException {
294:
295: TransformerFactory tFactory = TransformerFactory.newInstance();
296: Transformer transformer = tFactory.newTransformer();
297:
298: transformer.setOutputProperty("encoding", "UTF-8");
299: transformer.setOutputProperty("indent", "yes");
300:
301: transformer.transform(new DOMSource(edoc),
302: new StreamResult(pos));
303:
304: }
305:
306: /**
307: * @return The content of this source.
308: */
309: public ContentHolder getContent() {
310: return this .content;
311: }
312:
313: /**
314: * @see org.apache.excalibur.source.Source#getContentLength()
315: */
316: public long getContentLength() {
317: try {
318: return getContent().getContentLength();
319: } catch (RepositoryException e) {
320: throw new RuntimeException(e);
321: }
322: }
323:
324: /**
325: * @see org.apache.excalibur.source.Source#getLastModified()
326: */
327: public long getLastModified() {
328: try {
329: return getContent().getLastModified();
330: } catch (RepositoryException e) {
331: throw new RuntimeException(e);
332: }
333: }
334:
335: /**
336: * @return The source URI.
337: */
338: public String getSourceURI() {
339: return getContent().getSourceURI();
340: }
341:
342: /**
343: * @see org.apache.excalibur.source.Source#getMimeType()
344: */
345: public String getMimeType() {
346: try {
347: return getContent().getMimeType();
348: } catch (RepositoryException e) {
349: throw new RuntimeException(e);
350: }
351: }
352:
353: /**
354: *
355: */
356: public Source getParent() {
357: getLogger().warn("getParent() not implemented yet!");
358: return null;
359: }
360:
361: /**
362: *
363: */
364: public void makeCollection() {
365: getLogger()
366: .warn(
367: "RepositorySource().makeCollection() not implemented yet!");
368: }
369:
370: /**
371: *
372: */
373: public String getName() {
374: // Quick and dirty
375: String name = new java.io.File(getURI()).getName();
376: if (getLogger().isDebugEnabled())
377: getLogger().debug("getName(): URI: " + name);
378: return name;
379: }
380:
381: /**
382: *
383: */
384: public Source getChild(String name) {
385: getLogger().warn("getChild() not implemented yet!");
386: return null;
387: }
388:
389: /**
390: *
391: */
392: public Collection getChildren() {
393: try {
394: Collection children = getNode().getChildren();
395: java.util.Iterator iterator = children.iterator();
396: java.util.Vector newChildren = new java.util.Vector();
397: while (iterator.hasNext()) {
398: Node child = (Node) iterator.next();
399: newChildren
400: .add(new RepositorySource(this .manager, child
401: .getSourceURI(), this .session,
402: getLogger()));
403: }
404: return newChildren;
405: } catch (Exception e) {
406: throw new RuntimeException(e);
407: }
408: }
409:
410: /**
411: *
412: */
413: public boolean isCollection() {
414: try {
415: return getNode().isCollection();
416: } catch (RepositoryException e) {
417: throw new RuntimeException(e);
418: }
419: }
420:
421: private SourceValidity validity;
422:
423: public SourceValidity getValidity() {
424: if (this .validity == null) {
425: this .validity = new RepositorySourceValidity(this);
426: }
427: return this.validity;
428: }
429:
430: }
|