SourceWrapper.java :  » Content-Management-System » apache-lenya-2.0 » org » apache » lenya » cms » repository » Java Open Source

Java Open Source » Content Management System » apache lenya 2.0 
apache lenya 2.0 » org » apache » lenya » cms » repository » SourceWrapper.java
/*
 * 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.repository;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.util.Date;
import java.util.Map;
import java.util.WeakHashMap;

import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.excalibur.source.ModifiableSource;
import org.apache.excalibur.source.SourceResolver;
import org.apache.excalibur.source.TraversableSource;
import org.apache.lenya.cms.cocoon.source.SourceUtil;
import org.apache.lenya.cms.publication.DocumentFactory;
import org.apache.lenya.cms.publication.DocumentUtil;
import org.apache.lenya.cms.publication.Publication;
import org.apache.lenya.cms.rc.CheckInEntry;
import org.apache.lenya.cms.rc.RevisionControlException;
import org.apache.lenya.util.Assert;

/**
 * Provide access to a source.
 */
public class SourceWrapper extends AbstractLogEnabled {

    private SourceNode node;
    private String sourceUri;
    protected ServiceManager manager;

    /**
     * Ctor.
     * @param node
     * @param sourceUri
     * @param manager
     * @param logger
     */
    public SourceWrapper(SourceNode node, String sourceUri, ServiceManager manager, Logger logger) {

        Assert.notNull("node", node);
        this.node = node;

        Assert.notNull("source URI", sourceUri);
        this.sourceUri = sourceUri;

        Assert.notNull("service manager", manager);
        this.manager = manager;

        enableLogging(logger);
    }

    protected static final String FILE_PREFIX = "file:/";
    protected static final String CONTEXT_PREFIX = "context://";

    protected SourceNode getNode() {
        return this.node;
    }

    private String realSourceUri;

    /**
     * Returns the URI of the actual source which is used.
     * 
     * @return A string.
     */
    protected String getRealSourceUri() {
        if (this.realSourceUri == null) {
            this.realSourceUri = computeRealSourceUri(this.manager, getNode().getSession(),
                    this.sourceUri, getLogger());
        }
        return this.realSourceUri;
    }

    protected static final String computeRealSourceUri(ServiceManager manager, Session session,
            String sourceUri, Logger logger) {
        String contentDir = null;
        String publicationId = null;
        try {
            String pubBase = Node.LENYA_PROTOCOL + Publication.PUBLICATION_PREFIX_URI + "/";
            String publicationsPath = sourceUri.substring(pubBase.length());
            int firstSlashIndex = publicationsPath.indexOf("/");
            publicationId = publicationsPath.substring(0, firstSlashIndex);
            DocumentFactory factory = DocumentUtil.createDocumentFactory(manager, session);
            Publication pub = factory.getPublication(publicationId);
            contentDir = pub.getContentDir();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        String contentBaseUri = null;
        String urlID = sourceUri.substring(Node.LENYA_PROTOCOL.length());

        // Substitute e.g. "lenya://lenya/pubs/PUB_ID/content" by "contentDir"
        String filePrefix = urlID.substring(0, urlID.indexOf(publicationId)) + publicationId;
        String tempString = urlID.substring(filePrefix.length() + 1);
        String fileMiddle = tempString.substring(0, tempString.indexOf("/"));
        String fileSuffix = tempString.substring(fileMiddle.length() + 1, tempString.length());
        String uriSuffix;
        if (new File(contentDir).isAbsolute()) {
            // Absolute
            contentBaseUri = FILE_PREFIX + contentDir;
            uriSuffix = File.separator + fileSuffix;
        } else {
            // Relative
            contentBaseUri = CONTEXT_PREFIX + contentDir;
            uriSuffix = "/" + fileSuffix;
        }

        String realSourceUri = contentBaseUri + uriSuffix;

        if (logger.isDebugEnabled()) {
            try {
                if (!SourceUtil.exists(contentBaseUri, manager)) {
                    logger.debug("The content directory [" + contentBaseUri + "] does not exist. "
                            + "It will be created as soon as documents are added.");
                }
            } catch (ServiceException e) {
                throw new RuntimeException(e);
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            logger.debug("Real Source URI: " + realSourceUri);
        }

        return realSourceUri;
    }

    /**
     * @throws RepositoryException if an error occurs.
     * @see org.apache.lenya.transaction.Transactionable#deleteTransactionable()
     */
    public void deleteTransactionable() throws RepositoryException {
        try {
            if (!getNode().isCheckedOut()) {
                throw new RuntimeException("Cannot delete source [" + getSourceUri()
                        + "]: not checked out!");
            } else {
                this.data = null;
                SourceUtil.delete(getRealSourceUri(), this.manager);
            }
        } catch (Exception e) {
            throw new RepositoryException(e);
        }
    }

    byte[] data = null;

    /**
     * @return An input stream.
     * @throws RepositoryException if an error occurs.
     * @see org.apache.lenya.cms.repository.Node#getInputStream()
     */
    public synchronized InputStream getInputStream() throws RepositoryException {
        loadData();
        if (this.data == null) {
            throw new RuntimeException(this + " does not exist!");
        }
        return new ByteArrayInputStream(this.data);
    }

    /**
     * @return A boolean value.
     * @throws RepositoryException if an error occurs.
     * @see org.apache.lenya.cms.repository.Node#exists()
     */
    public boolean exists() throws RepositoryException {
        if (this.deleted == true) {
            return false;
        } else if (this.data != null) {
            return true;
        } else {
            try {
                return SourceUtil.exists(getRealSourceUri(), this.manager);
            } catch (Exception e) {
                throw new RepositoryException(e);
            }
        }
    }

    private boolean deleted;
    private int loadRevision = -1;

    protected void delete() {
        this.deleted = true;
    }

    /**
     * Loads the data from the real source.
     * 
     * @throws RepositoryException if an error occurs.
     */
    protected synchronized void loadData() throws RepositoryException {

        if (this.deleted || this.data != null) {
            return;
        }

        ByteArrayOutputStream out = null;
        InputStream in = null;
        SourceResolver resolver = null;
        TraversableSource source = null;
        try {
            resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
            source = (TraversableSource) resolver.resolveURI(getRealSourceUri());

            if (source.exists() && !source.isCollection()) {
                byte[] buf = new byte[4096];
                out = new ByteArrayOutputStream();
                in = source.getInputStream();
                int read = in.read(buf);

                while (read > 0) {
                    out.write(buf, 0, read);
                    read = in.read(buf);
                }

                this.data = out.toByteArray();
                this.mimeType = source.getMimeType();
            }
        } catch (Exception e) {
            throw new RepositoryException(e);
        } finally {
            try {
                if (in != null)
                    in.close();
                if (out != null)
                    out.close();
            } catch (Exception e) {
                throw new RepositoryException(e);
            }

            if (resolver != null) {
                if (source != null) {
                    resolver.release(source);
                }
                this.manager.release(resolver);
            }
        }
        this.loadRevision = this.node.getCurrentRevisionNumber();
    }

    /**
     * Store the source URLs which are currently written.
     */
    private static Map lockedUris = new WeakHashMap();

    /**
     * @throws RepositoryException if an error occurs.
     * @see org.apache.lenya.transaction.Transactionable#saveTransactionable()
     */
    protected synchronized void saveTransactionable() throws RepositoryException {
        if (getLogger().isDebugEnabled()) {
            getLogger().debug("Saving [" + this + "] to source [" + getRealSourceUri() + "]");
        }

        if (this.data != null) {

            String realSourceUri = getRealSourceUri();
            Object lock = lockedUris.get(realSourceUri);
            if (lock == null) {
                lock = new Object();
                lockedUris.put(realSourceUri, lock);
            }

            synchronized (lock) {
                saveTransactionable(realSourceUri);
            }
        }
    }

    protected void saveTransactionable(String realSourceUri) throws RepositoryException {
        SourceResolver resolver = null;
        ModifiableSource source = null;
        InputStream in = null;
        OutputStream out = null;

        try {
            resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
            source = (ModifiableSource) resolver.resolveURI(realSourceUri);

            out = source.getOutputStream();

            byte[] buf = new byte[4096];
            in = new ByteArrayInputStream(this.data);
            int read = in.read(buf);

            while (read > 0) {
                out.write(buf, 0, read);
                read = in.read(buf);
            }
        } catch (Exception e) {
            throw new RepositoryException(e);
        } finally {

            try {
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.flush();
                    out.close();
                }
            } catch (Throwable t) {
                throw new RuntimeException("Could not close streams: ", t);
            }

            if (resolver != null) {
                if (source != null) {
                    resolver.release(source);
                }
                manager.release(resolver);
            }
        }
    }

    /**
     * Output stream.
     */
    private class NodeOutputStream extends ByteArrayOutputStream {
        /**
         * @see java.io.OutputStream#close()
         */
        public synchronized void close() throws IOException {
            SourceWrapper.this.data = super.toByteArray();
            SourceWrapper.this.lastModified = new Date().getTime();
            try {
                SourceWrapper.this.getNode().registerDirty();
            } catch (RepositoryException e) {
                throw new RuntimeException(e);
            }
            super.close();
        }
    }

    /**
     * @return The content length.
     * @throws RepositoryException if an error occurs.
     * @see org.apache.lenya.cms.repository.Node#getContentLength()
     */
    public long getContentLength() throws RepositoryException {
        loadData();
        return this.data.length;
    }

    private long lastModified = -1;

    /**
     * @return The last modification date.
     * @throws RepositoryException if an error occurs.
     * @see org.apache.lenya.cms.repository.Node#getLastModified()
     */
    public long getLastModified() throws RepositoryException {
        try {
            CheckInEntry entry = this.node.getRcml().getLatestCheckInEntry();
            if (entry != null) {
                this.lastModified = entry.getTime();
            }
        } catch (RevisionControlException e) {
            throw new RepositoryException(e);
        }
        return this.lastModified;
    }

    private String mimeType;

    /**
     * @return A string.
     * @throws RepositoryException if an error occurs.
     * @see org.apache.lenya.cms.repository.Node#getMimeType()
     */
    public String getMimeType() throws RepositoryException {
        loadData();
        return this.mimeType;
    }

    /**
     * @return The source URI.
     */
    public String getSourceUri() {
        return this.sourceUri;
    }

    /**
     * @return An output stream.
     * @throws RepositoryException if an error occurs.
     * @see org.apache.lenya.cms.repository.Node#getOutputStream()
     */
    public synchronized OutputStream getOutputStream() throws RepositoryException {
        if (getLogger().isDebugEnabled())
            getLogger().debug("Get OutputStream for " + getSourceUri());
        loadData();
        return new NodeOutputStream();
    }
    
    protected int getLoadRevision() {
        return this.loadRevision;
    }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.