org.apache.roller.weblogger.webservices.atomprotocol.MediaCollection.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.roller.weblogger.webservices.atomprotocol.MediaCollection.java

Source

/*
 *  Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 *  Use is subject to license terms.
 * 
 *  Licensed 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.roller.weblogger.webservices.atomprotocol;

import com.sun.syndication.feed.atom.Content;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.feed.atom.Feed;
import com.sun.syndication.feed.atom.Link;
import com.sun.syndication.propono.atom.common.rome.AppModule;
import com.sun.syndication.propono.atom.common.rome.AppModuleImpl;
import com.sun.syndication.propono.atom.server.AtomException;
import com.sun.syndication.propono.atom.server.AtomMediaResource;
import com.sun.syndication.propono.atom.server.AtomNotAuthorizedException;
import com.sun.syndication.propono.atom.server.AtomNotFoundException;
import com.sun.syndication.propono.atom.server.AtomRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.UUID;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.weblogger.WebloggerException;
import org.apache.roller.weblogger.business.FileIOException;
import org.apache.roller.weblogger.business.MediaFileManager;
import org.apache.roller.weblogger.business.URLStrategy;
import org.apache.roller.weblogger.business.WeblogManager;
import org.apache.roller.weblogger.business.Weblogger;
import org.apache.roller.weblogger.business.WebloggerFactory;
import org.apache.roller.weblogger.config.WebloggerRuntimeConfig;
import org.apache.roller.weblogger.pojos.MediaFile;
import org.apache.roller.weblogger.pojos.MediaFileDirectory;
import org.apache.roller.weblogger.pojos.User;
import org.apache.roller.weblogger.pojos.Weblog;
import org.apache.roller.weblogger.util.RollerMessages;
import org.apache.roller.weblogger.util.Utilities;

/**
 * Collection of media resources.
 * @author davidm.johnson@sun.com
 */
public class MediaCollection {
    private Weblogger roller;
    private User user;
    private int maxEntries = 20;
    private final String atomURL;

    private static Log log = LogFactory.getFactory().getInstance(EntryCollection.class);

    public MediaCollection(User user, String atomURL) {
        this.user = user;
        this.atomURL = atomURL;
        this.roller = WebloggerFactory.getWeblogger();
    }

    public Entry postMedia(AtomRequest areq, Entry entry) throws AtomException {
        log.debug("Entering");
        String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/");

        try {
            // get incoming slug from HTTP header
            String slug = areq.getHeader("Slug");

            Content content = (Content) entry.getContents().get(0);
            String contentType = content.getType();
            InputStream is = areq.getInputStream();
            String title = entry.getTitle() != null ? entry.getTitle() : slug;

            // authenticated client posted a weblog entry
            File tempFile = null;
            String handle = pathInfo[0];
            MediaFileManager fileMgr = roller.getMediaFileManager();
            Weblog website = WebloggerFactory.getWeblogger().getWeblogManager().getWeblogByHandle(handle);
            if (!RollerAtomHandler.canEdit(user, website)) {
                throw new AtomNotAuthorizedException("Not authorized to edit weblog: " + handle);
            }
            if (pathInfo.length > 1) {
                // Save to temp file
                String fileName = createFileName(website,
                        (slug != null) ? slug : Utilities.replaceNonAlphanumeric(title, ' '), contentType);
                try {
                    tempFile = File.createTempFile(fileName, "tmp");
                    FileOutputStream fos = new FileOutputStream(tempFile);
                    Utilities.copyInputToOutput(is, fos);
                    fos.close();

                    // Parse pathinfo to determine file path
                    String path = filePathFromPathInfo(pathInfo);
                    String justPath = path;
                    int lastSlash = path.lastIndexOf("/");
                    if (lastSlash > -1) {
                        justPath = path.substring(lastSlash);
                    }

                    MediaFileDirectory mdir = fileMgr.getMediaFileDirectoryByPath(website, justPath);

                    if (mdir.hasMediaFile(fileName)) {
                        throw new AtomException("Duplicate file name");
                    }

                    if (path.length() > 0)
                        path = path + File.separator;
                    FileInputStream fis = new FileInputStream(tempFile);

                    MediaFile mf = new MediaFile();
                    mf.setDirectory(mdir);
                    mf.setWeblog(website);
                    mf.setName(fileName);
                    mf.setOriginalPath(justPath);
                    mf.setContentType(contentType);
                    mf.setInputStream(fis);
                    mf.setLength(tempFile.length());

                    RollerMessages errors = new RollerMessages();
                    fileMgr.createMediaFile(website, mf, errors);
                    if (errors.getErrorCount() > 0) {
                        throw new AtomException(errors.toString());
                    }

                    roller.flush();

                    fis.close();

                    MediaFile stored = fileMgr.getMediaFile(mf.getId());
                    Entry mediaEntry = createAtomResourceEntry(website, stored);
                    for (Iterator it = mediaEntry.getOtherLinks().iterator(); it.hasNext();) {
                        Link link = (Link) it.next();
                        if ("edit".equals(link.getRel())) {
                            log.debug("Exiting");
                            return mediaEntry;
                        }
                    }
                    log.error("ERROR: no edit link found in saved media entry");

                } catch (FileIOException fie) {
                    throw new AtomException("File upload disabled, over-quota or other error", fie);
                } finally {
                    if (tempFile != null)
                        tempFile.delete();
                }
            }
            throw new AtomException("Error saving media entry");

        } catch (WebloggerException re) {
            throw new AtomException("Posting media", re);
        } catch (IOException ioe) {
            throw new AtomException("Posting media", ioe);
        }
    }

    public Entry getEntry(AtomRequest areq) throws AtomException {
        try {
            String[] pathInfo = Utilities.stringToStringArray(areq.getPathInfo(), "/");

            String filePath = filePathFromPathInfo(pathInfo);
            filePath = filePath.substring(0, filePath.length() - ".media-link".length());
            String handle = pathInfo[0];
            Weblog website = roller.getWeblogManager().getWeblogByHandle(handle);

            MediaFileManager fileMgr = roller.getMediaFileManager();
            MediaFile mf = fileMgr.getMediaFileByPath(website, filePath);

            log.debug("Exiting");
            if (mf != null) {
                return createAtomResourceEntry(website, mf);
            }

        } catch (WebloggerException ex) {
            throw new AtomException("ERROR fetching entry", ex);
        }
        throw new AtomNotFoundException("ERROR resource not found");
    }

    public AtomMediaResource getMediaResource(AtomRequest areq) throws AtomException {
        log.debug("Entering");
        String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/");
        try {
            // authenticated client posted a weblog entry
            File tempFile = null;
            String handle = pathInfo[0];
            MediaFileManager fmgr = roller.getMediaFileManager();
            Weblog website = WebloggerFactory.getWeblogger().getWeblogManager().getWeblogByHandle(handle);
            if (!RollerAtomHandler.canEdit(user, website)) {
                throw new AtomNotAuthorizedException("Not authorized to edit weblog: " + handle);
            }
            if (pathInfo.length > 1) {
                try {
                    // Parse pathinfo to determine file path
                    String filePath = filePathFromPathInfo(pathInfo);
                    MediaFile mf = fmgr.getMediaFileByOriginalPath(website, filePath);
                    return new AtomMediaResource(mf.getName(), mf.getLength(), new Date(mf.getLastModified()),
                            mf.getInputStream());
                } catch (Exception e) {
                    throw new AtomException("Unexpected error during file upload", e);
                }
            }
            throw new AtomException("Incorrect path information");

        } catch (WebloggerException re) {
            throw new AtomException("Posting media");
        }
    }

    public Feed getCollection(AtomRequest areq) throws AtomException {
        log.debug("Entering");
        String[] rawPathInfo = StringUtils.split(areq.getPathInfo(), "/");
        try {
            int start = 0;
            int max = maxEntries;
            String[] pathInfo = rawPathInfo;
            if (rawPathInfo.length > 2) {
                try {
                    start = Integer.parseInt(rawPathInfo[rawPathInfo.length - 1]);
                    pathInfo = new String[rawPathInfo.length - 1];
                    for (int i = 0; i < rawPathInfo.length - 1; i++) {
                        pathInfo[i] = rawPathInfo[i];
                    }
                } catch (Exception ingored) {
                }
            }
            String path = filePathFromPathInfo(pathInfo);
            if (!path.equals(""))
                path = path + File.separator;

            String handle = pathInfo[0];
            String absUrl = WebloggerRuntimeConfig.getAbsoluteContextURL();
            Weblog website = roller.getWeblogManager().getWeblogByHandle(handle);
            if (website == null) {
                throw new AtomNotFoundException("Cannot find weblog: " + handle);
            }
            if (!RollerAtomHandler.canView(user, website)) {
                throw new AtomNotAuthorizedException("Not authorized to access website");
            }

            Feed feed = new Feed();
            feed.setId(atomURL + "/" + website.getHandle() + "/resources/" + path + start);
            feed.setTitle(website.getName());

            Link link = new Link();
            link.setHref(absUrl + "/" + website.getHandle());
            link.setRel("alternate");
            link.setType("text/html");
            feed.setAlternateLinks(Collections.singletonList(link));

            MediaFileManager fmgr = roller.getMediaFileManager();
            MediaFileDirectory dir = null;
            if (StringUtils.isNotEmpty(path)) {
                log.debug("Fetching resource collection from weblog " + handle + " at path: " + path);
                dir = fmgr.getMediaFileDirectoryByPath(website, path);
            } else {
                log.debug("Fetching root resource collection from weblog " + handle);
                dir = fmgr.getMediaFileRootDirectory(website);
            }
            Set<MediaFile> files = dir.getMediaFiles();

            SortedSet sortedSet = new TreeSet(new Comparator() {
                public int compare(Object o1, Object o2) {
                    MediaFile f1 = (MediaFile) o1;
                    MediaFile f2 = (MediaFile) o2;
                    if (f1.getLastModified() < f2.getLastModified())
                        return 1;
                    else if (f1.getLastModified() == f2.getLastModified())
                        return 0;
                    else
                        return -1;
                }
            });

            if (files != null && start < files.size()) {
                for (MediaFile mf : files) {
                    sortedSet.add(mf);
                }
                int count = 0;
                MediaFile[] sortedResources = (MediaFile[]) sortedSet.toArray(new MediaFile[sortedSet.size()]);
                List atomEntries = new ArrayList();
                for (int i = start; i < (start + max) && i < (sortedResources.length); i++) {
                    Entry entry = createAtomResourceEntry(website, sortedResources[i]);
                    atomEntries.add(entry);
                    if (count == 0) {
                        // first entry is most recent
                        feed.setUpdated(entry.getUpdated());
                    }
                    count++;
                }

                List otherLinks = new ArrayList();
                if (start + count < files.size()) { // add next link
                    int nextOffset = start + max;
                    String url = atomURL + "/" + website.getHandle() + "/resources/" + path + nextOffset;
                    Link nextLink = new Link();
                    nextLink.setRel("next");
                    nextLink.setHref(url);
                    otherLinks.add(nextLink);
                }
                if (start > 0) { // add previous link
                    int prevOffset = start > max ? start - max : 0;
                    String url = atomURL + "/" + website.getHandle() + "/resources/" + path + prevOffset;
                    Link prevLink = new Link();
                    prevLink.setRel("previous");
                    prevLink.setHref(url);
                    otherLinks.add(prevLink);
                }
                feed.setOtherLinks(otherLinks);
                feed.setEntries(atomEntries);

                log.debug("Collection contains: " + count);

            } else {
                log.debug("Returning empty collection");
            }

            log.debug("Exiting");
            return feed;

        } catch (WebloggerException re) {
            throw new AtomException("Getting resource collection", re);
        }
    }

    public void putMedia(AtomRequest areq) throws AtomException {
        String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/");
        String contentType = areq.getContentType();
        try {
            InputStream is = areq.getInputStream();

            // authenticated client posted a weblog entry
            File tempFile = null;
            String handle = pathInfo[0];
            MediaFileManager fmgr = roller.getMediaFileManager();
            WeblogManager wmgr = roller.getWeblogManager();
            Weblog website = wmgr.getWeblogByHandle(handle);
            if (!RollerAtomHandler.canEdit(user, website)) {
                throw new AtomNotAuthorizedException("Not authorized to edit weblog: " + handle);
            }
            if (pathInfo.length > 1) {
                // Save to temp file
                try {
                    tempFile = File.createTempFile(UUID.randomUUID().toString(), "tmp");
                    FileOutputStream fos = new FileOutputStream(tempFile);
                    Utilities.copyInputToOutput(is, fos);
                    fos.close();

                    FileInputStream fis = new FileInputStream(tempFile);

                    // Parse pathinfo to determine file path
                    String path = filePathFromPathInfo(pathInfo);

                    // Attempt to load file, to ensure it exists
                    MediaFile mf = fmgr.getMediaFileByPath(website, path);
                    mf.setContentType(contentType);
                    mf.setInputStream(fis);
                    mf.setLength(tempFile.length());

                    fmgr.updateMediaFile(website, mf, fis);

                    roller.flush();

                    fis.close();

                    log.debug("Exiting");
                    return;

                } catch (FileIOException fie) {
                    throw new AtomException("File upload disabled, over-quota or other error", fie);
                } catch (Exception e) {
                    throw new AtomException("Unexpected error during file upload", e);
                } finally {
                    if (tempFile != null)
                        tempFile.delete();
                }
            }
            throw new AtomException("Incorrect path information");

        } catch (WebloggerException re) {
            throw new AtomException("Posting media");
        } catch (IOException ioe) {
            throw new AtomException("Posting media", ioe);
        }
    }

    public void deleteEntry(AtomRequest areq) throws AtomException {
        try {
            String[] pathInfo = StringUtils.split(areq.getPathInfo(), "/");
            String handle = pathInfo[0];
            Weblog website = roller.getWeblogManager().getWeblogByHandle(handle);
            if (website == null) {
                throw new AtomNotFoundException("cannot find specified weblog");
            }
            if (RollerAtomHandler.canEdit(user, website) && pathInfo.length > 1) {
                try {
                    String path = filePathFromPathInfo(pathInfo);
                    String fileName = path.substring(0, path.length() - ".media-link".length());
                    MediaFileManager fmgr = roller.getMediaFileManager();
                    MediaFile mf = fmgr.getMediaFileByPath(website, path);
                    fmgr.removeMediaFile(website, mf);
                    log.debug("Deleted media entry: " + fileName);
                    return;

                } catch (Exception e) {
                    String msg = "ERROR deleting media entry";
                    log.error(msg, e);
                    throw new AtomException(msg);
                }
            }
            log.debug("Not authorized to delete media entry");
            log.debug("Exiting via exception");

        } catch (WebloggerException ex) {
            throw new AtomException("ERROR deleting media entry", ex);
        }
        throw new AtomNotAuthorizedException("Not authorized to delete entry");
    }

    private String filePathFromPathInfo(String[] pathInfo) {
        String path = null;
        if (pathInfo.length > 2) {
            for (int i = 2; i < pathInfo.length; i++) {
                if (path != null && path.length() > 0)
                    path = path + File.separator + pathInfo[i];
                else
                    path = pathInfo[i];
            }
        }
        if (pathInfo.length == 2) {
            path = "";
        }
        return path;
    }

    private Entry createAtomResourceEntry(Weblog website, MediaFile file) {
        String filePath = file.getPath().endsWith("/") ? file.getPath() + file.getName()
                : file.getPath() + "/" + file.getName();
        String editURI = atomURL + "/" + website.getHandle() + "/resource/" + filePath + ".media-link";
        String editMediaURI = atomURL + "/" + website.getHandle() + "/resource/" + filePath;
        URLStrategy urlStrategy = WebloggerFactory.getWeblogger().getUrlStrategy();

        String contentType = Utilities.getContentTypeFromFileName(file.getName());

        Entry entry = new Entry();
        entry.setId(editMediaURI);
        entry.setTitle(file.getName());
        entry.setUpdated(new Date(file.getLastModified()));

        Link altlink = new Link();
        altlink.setRel("alternate");
        altlink.setHref(file.getPermalink());
        List altlinks = new ArrayList();
        altlinks.add(altlink);
        entry.setAlternateLinks(altlinks);

        List otherlinks = new ArrayList();
        entry.setOtherLinks(otherlinks);
        Link editlink = new Link();
        editlink.setRel("edit");
        editlink.setHref(editURI);
        otherlinks.add(editlink);
        Link editMedialink = new Link();
        editMedialink.setRel("edit-media");
        editMedialink.setHref(editMediaURI);
        otherlinks.add(editMedialink);

        Content content = new Content();
        content.setSrc(file.getPermalink());
        content.setType(contentType);
        List contents = new ArrayList();
        contents.add(content);
        entry.setContents(contents);

        List modules = new ArrayList();
        AppModule app = new AppModuleImpl();
        app.setDraft(false);
        app.setEdited(entry.getUpdated());
        modules.add(app);
        entry.setModules(modules);

        return entry;
    }

    /**
     * Creates a file name for a file based on a weblog, title string and a 
     * content-type. 
     * 
     * @param weblog      Weblog for which file name is being created
     * @param title       Title to be used as basis for file name (or null)
     * @param contentType Content type of file (must not be null)
     * 
     * If a title is specified, the method will apply the same create-anchor 
     * logic we use for weblog entries to create a file name based on the title.
     *
     * If title is null, the base file name will be the weblog handle plus a 
     * YYYYMMDDHHSS timestamp. 
     *
     * The extension will be formed by using the part of content type that
     * comes after he slash. 
     *
     * For example:
     *    weblog.handle = "daveblog"
     *    title         = "Port Antonio"
     *    content-type  = "image/jpg"
     * Would result in port_antonio.jpg
     *
     * Another example:
     *    weblog.handle = "daveblog"
     *    title         = null
     *    content-type  = "image/jpg"
     * Might result in daveblog-200608201034.jpg
     */
    private String createFileName(Weblog weblog, String slug, String contentType) {

        if (weblog == null)
            throw new IllegalArgumentException("weblog cannot be null");
        if (contentType == null)
            throw new IllegalArgumentException("contentType cannot be null");

        String fileName = null;

        // Determine the extension based on the contentType. This is a hack.
        // The info we need to map from contentType to file extension is in 
        // JRE/lib/content-type.properties, but Java Activation doesn't provide 
        // a way to do a reverse mapping or to get at the data.
        String[] typeTokens = contentType.split("/");
        String ext = typeTokens[1];

        if (slug != null && !slug.trim().equals("")) {
            // We've got a title, so use it to build file name
            StringTokenizer toker = new StringTokenizer(slug);
            String tmp = null;
            int count = 0;
            while (toker.hasMoreTokens() && count < 5) {
                String s = toker.nextToken();
                s = s.toLowerCase();
                tmp = (tmp == null) ? s : tmp + "_" + s;
                count++;
            }
            if (!tmp.endsWith("." + ext)) {
                fileName = tmp + "." + ext;
            } else {
                fileName = tmp;
            }
        } else {
            // No title or text, so instead we'll use the item's date
            // in YYYYMMDD format to form the file name
            SimpleDateFormat sdf = new SimpleDateFormat();
            sdf.applyPattern("yyyyMMddHHSS");
            fileName = weblog.getHandle() + "-" + sdf.format(new Date()) + "." + ext;
        }

        return fileName;
    }
}