blob: bdaccba60aa31bba292297751b1e228deccb4adb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.lenya.cms.cocoon.source;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.net.MalformedURLException;
import java.util.Collection;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.cocoon.environment.Request;
import org.apache.excalibur.source.ModifiableTraversableSource;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceException;
import org.apache.excalibur.source.SourceNotFoundException;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.AbstractSource;
import org.apache.lenya.cms.cocoon.components.context.ContextUtility;
import org.apache.lenya.cms.publication.Document;
import org.apache.lenya.cms.publication.Publication;
import org.apache.lenya.cms.publication.PublicationUtil;
import org.apache.lenya.cms.repository.ContentHolder;
import org.apache.lenya.cms.repository.Node;
import org.apache.lenya.cms.repository.NodeFactory;
import org.apache.lenya.cms.repository.RepositoryException;
import org.apache.lenya.cms.repository.Session;
import org.apache.lenya.util.Query;
import org.apache.lenya.util.ServletHelper;
/**
* Repository source.
*
* @version $Id$
*/
public class RepositorySource extends AbstractSource implements ModifiableTraversableSource {
private ServiceManager manager;
private ContentHolder content;
private Session session;
private Logger logger;
protected static final String SCHEME = "lenya";
/**
* @param manager The service manager.
* @param uri The source URI.
* @param session The repository session.
* @param logger The logger.
* @throws SourceException if an error occurs.
* @throws MalformedURLException if an error occurs.
*/
public RepositorySource(ServiceManager manager, String uri, Session session, Logger logger)
throws SourceException, MalformedURLException {
this.manager = manager;
this.logger = logger;
if (getLogger().isDebugEnabled())
getLogger().debug("Init RepositorySource: " + uri);
if (session == null) {
throw new IllegalArgumentException("The repository session must not be null!");
}
this.session = session;
if (uri == null) {
throw new MalformedURLException("The source URI must not be null!");
}
setSystemId(uri);
// Scheme
int start = 0;
int end = uri.indexOf(':');
if (end == -1)
throw new MalformedURLException("Malformed uri for xmodule source (cannot find scheme) : "
+ uri);
String scheme = uri.substring(start, end);
if (!SCHEME.equals(scheme))
throw new MalformedURLException("Malformed uri for a xmodule source : " + uri);
setScheme(scheme);
NodeFactory factory = null;
try {
factory = (NodeFactory) this.manager.lookup(NodeFactory.ROLE);
String sourceUri;
int revisionNumber = -1;
int questionMarkIndex = uri.indexOf("?");
if (questionMarkIndex > -1) {
sourceUri = uri.substring(0, questionMarkIndex);
Query query = new Query(uri.substring(questionMarkIndex + 1));
String revisionString = query.getValue("rev", null);
if (revisionString != null) {
ContextUtility util = null;
try {
util = (ContextUtility) this.manager.lookup(ContextUtility.ROLE);
Request request = util.getRequest();
String webappUrl = ServletHelper.getWebappURI(request);
Publication pub = PublicationUtil.getPublication(this.manager, request);
Document currentDoc = pub.getFactory().getFromURL(webappUrl);
if (currentDoc.getSourceURI().equals(sourceUri)) {
revisionNumber = Integer.valueOf(revisionString).intValue();
}
}
finally {
if (util != null) {
this.manager.release(util);
}
}
}
}
else {
sourceUri = uri;
}
if (revisionNumber == -1) {
this.content = (ContentHolder) session.getRepositoryItem(factory, sourceUri);
}
else {
Node node = (Node) session.getRepositoryItem(factory, sourceUri);
this.content = node.getHistory().getRevision(revisionNumber);
}
} catch (Exception e) {
throw new SourceException("Creating repository node failed: ", e);
} finally {
if (factory != null) {
this.manager.release(factory);
}
}
}
/**
* @return The repository node which is accessed by this source.
*/
public Node getNode() {
if (!(this.content instanceof Node)) {
throw new RuntimeException("This operation can only be invoked on nodes, not on revisions.");
}
return (Node) this.content;
}
protected Logger getLogger() {
return this.logger;
}
/**
* @see org.apache.excalibur.source.ModifiableSource#getOutputStream()
*/
public OutputStream getOutputStream() throws IOException {
try {
return getNode().getOutputStream();
} catch (RepositoryException e) {
throw new RuntimeException(e);
}
}
/**
* @see org.apache.excalibur.source.ModifiableSource#delete()
*/
public void delete() {
try {
getNode().delete();
} catch (RepositoryException e) {
throw new RuntimeException(e);
}
}
/**
* @see org.apache.excalibur.source.ModifiableSource#canCancel(java.io.OutputStream)
*/
public boolean canCancel(OutputStream arg0) {
return false;
}
/**
* @see org.apache.excalibur.source.ModifiableSource#cancel(java.io.OutputStream)
*/
public void cancel(OutputStream arg0) throws IOException {
}
/**
* @see org.apache.excalibur.source.Source#exists()
*/
public boolean exists() {
try {
if (getContent().exists()) {
return true;
} else {
return isCollection();
}
} catch (RepositoryException e) {
throw new RuntimeException(e);
}
}
/**
* @see org.apache.excalibur.source.Source#getInputStream()
*/
public InputStream getInputStream() throws IOException, SourceNotFoundException {
if (getLogger().isDebugEnabled())
getLogger().debug("Get InputStream for " + getURI());
if (!exists()) {
throw new SourceNotFoundException("The source [" + getURI() + "] does not exist!");
}
try {
return getContent().getInputStream();
} catch (RepositoryException e) {
throw new RuntimeException(e);
}
}
protected InputStream convert(org.w3c.dom.Document edoc) throws IOException {
final org.w3c.dom.Document doc = edoc;
final PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream();
pis.connect(pos);
(new Thread(new Runnable() {
public void run() {
try {
transform(doc, pos);
} catch (TransformerException e) {
throw new RuntimeException("Failed to tranform org.w3c.dom.Document to PipedOutputStream",
e);
} finally {
try {
pos.close();
} catch (Exception ignore) {
ignore.printStackTrace();
}
}
}
},
getClass().getName() + ".convert(org.w3c.dom.Document edoc)")).start();
return pis;
}
void transform(org.w3c.dom.Document edoc, PipedOutputStream pos) throws TransformerException {
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty("encoding", "UTF-8");
transformer.setOutputProperty("indent", "yes");
transformer.transform(new DOMSource(edoc), new StreamResult(pos));
}
/**
* @return The content of this source.
*/
public ContentHolder getContent() {
return this.content;
}
/**
* @see org.apache.excalibur.source.Source#getContentLength()
*/
public long getContentLength() {
try {
return getContent().getContentLength();
} catch (RepositoryException e) {
throw new RuntimeException(e);
}
}
/**
* @see org.apache.excalibur.source.Source#getLastModified()
*/
public long getLastModified() {
try {
return getContent().getLastModified();
} catch (RepositoryException e) {
throw new RuntimeException(e);
}
}
/**
* @return The source URI.
*/
public String getSourceURI() {
return getContent().getSourceURI();
}
/**
* @see org.apache.excalibur.source.Source#getMimeType()
*/
public String getMimeType() {
try {
return getContent().getMimeType();
} catch (RepositoryException e) {
throw new RuntimeException(e);
}
}
/**
*
*/
public Source getParent() {
getLogger().warn("getParent() not implemented yet!");
return null;
}
/**
*
*/
public void makeCollection() {
getLogger().warn("RepositorySource().makeCollection() not implemented yet!");
}
/**
*
*/
public String getName() {
// Quick and dirty
String name = new java.io.File(getURI()).getName();
if (getLogger().isDebugEnabled())
getLogger().debug("getName(): URI: " + name);
return name;
}
/**
*
*/
public Source getChild(String name) {
getLogger().warn("getChild() not implemented yet!");
return null;
}
/**
*
*/
public Collection getChildren() {
try {
Collection children = getNode().getChildren();
java.util.Iterator iterator = children.iterator();
java.util.Vector newChildren = new java.util.Vector();
while (iterator.hasNext()) {
Node child = (Node) iterator.next();
newChildren.add(new RepositorySource(this.manager,
child.getSourceURI(),
this.session,
getLogger()));
}
return newChildren;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
*
*/
public boolean isCollection() {
try {
return getNode().isCollection();
} catch (RepositoryException e) {
throw new RuntimeException(e);
}
}
private SourceValidity validity;
public SourceValidity getValidity() {
if (this.validity == null) {
this.validity = new RepositorySourceValidity(this);
}
return this.validity;
}
}