Java tutorial
/* * 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; } }