/* * 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.cocoon.components; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.Iterator; import org.apache.avalon.framework.component.Component; import org.apache.avalon.framework.component.ComponentException; import org.apache.avalon.framework.component.ComponentManager; import org.apache.cocoon.environment.Request; import org.apache.cocoon.servlet.multipart.Part; import org.apache.excalibur.source.ModifiableSource; import org.apache.excalibur.source.ModifiableTraversableSource; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.SourceException; import org.apache.excalibur.source.SourceResolver; import org.apache.excalibur.source.SourceUtil; import org.apache.excalibur.source.TraversableSource; /** * @author stefano * @version CVS $Id$ */ public class SourceRepository { public static final String FILE_NAME = "document"; private static SourceRepository instance; private static ComponentManager manager; private SourceRepository() { manager = CocoonComponentManager.getSitemapComponentManager(); } public static SourceRepository getInstance() { if (instance == null) { instance = new SourceRepository(); } return instance; } private static Source resolve(String uri) throws MalformedURLException, IOException { SourceResolver resolver = null; TraversableSource source; try { resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE); source = (TraversableSource) resolver.resolveURI(uri); } catch (ComponentException ce) { throw new IOException("ComponentException"); } finally { manager.release((Component)resolver); } return source; } private static TraversableSource getCollection(String colName) { TraversableSource source; try { source = (TraversableSource)resolve(colName); } catch (MalformedURLException e) { throw new RuntimeException("'unable to resolve source: malformed URL"); } catch (IOException e) { throw new RuntimeException("'unable to resolve source: IOException"); } if (!source.isCollection()) throw new RuntimeException(colName + " is not a collection!"); return source; } public static void save(Request request, String dirName) throws Exception { TraversableSource collection = getCollection(dirName); ModifiableTraversableSource result; Enumeration params = request.getParameterNames(); while (params.hasMoreElements()) { String name = (String) params.nextElement(); if (name.indexOf("..") > -1) throw new Exception("We are under attack!!"); //System.out.println("[param] " + name); if (name.startsWith("save:")) { Part part = (Part) request.get(name); String code = name.substring(5); if (!(collection instanceof ModifiableSource)) { throw new RuntimeException("Cannot modify the given source"); } result = (ModifiableTraversableSource)resolve(collection.getURI() + "/" + code); save(part, result); } else if (name.startsWith("delete:")) { String value = request.getParameter(name); if (value.length() > 0) { String code = name.substring(7); result = (ModifiableTraversableSource)resolve(collection + "/" + code); remove(result); } } } } public static void save(Request request, String param, String dest) throws Exception { Part part = (Part) request.get(param); save(part, (ModifiableTraversableSource)resolve(dest)); } public static void save(Part part, ModifiableTraversableSource destination) throws Exception { InputStream in = null; OutputStream out = null; try { in = part.getInputStream(); out = destination.getOutputStream(); copy(in, out); } finally { if (out != null) { out.close(); } if (in != null) { in.close(); } } } public static OutputStream getOutputStream(String collection) throws IOException { String mainResource = collection + "/" + FILE_NAME + ".xml"; String versionedResource = collection + "/" + FILE_NAME + "." + getVersionID(collection) + ".xml"; copy(mainResource, versionedResource); return ((ModifiableSource)resolve(mainResource)).getOutputStream(); } public static void revertFrom(String collection, int version) throws IOException { String mainResource = collection + "/" + FILE_NAME + ".xml"; String versionedResource = collection + "/" + FILE_NAME + "." + version + ".xml"; copy(versionedResource,mainResource); } /** * Returns the highest version id of the files included in the given * directory. */ public static int getVersionID(String colName) { TraversableSource collection = getCollection(colName); int id = 0; Collection contents; try { contents = collection.getChildren(); } catch (SourceException se) { throw new RuntimeException("Unable to list contents for collection " + colName); } for (Iterator iter = contents.iterator(); iter.hasNext();) { TraversableSource content = (TraversableSource) iter.next(); if (!content.isCollection()) { try { int localid = getVersion(content.getName()); if (localid > id) id = localid; } catch (Exception e) {} } } return ++id; } public static Object[] getVersions(String colName) { TraversableSource collection = getCollection(colName); ArrayList versions = new ArrayList(); Collection contents; try { contents = collection.getChildren(); } catch (SourceException se) { throw new RuntimeException("Unable to list contents for collection " + colName); } for (Iterator iter = contents.iterator(); iter.hasNext();) { TraversableSource content = (TraversableSource) iter.next(); if (!content.isCollection()) { try { int version = getVersion(content.getName()); if (version > 0) { versions.add(new Integer(version)); } } catch (Exception e) {} } } return versions.toArray(); } /** * Return the version encoded into the name as a numeric subextension of * an .xml extension. * * Example: * anything.123.xml -> 123 * document.3.xml -> 3 * document.0.xml -> 0 * document.xml -> -1 * image.0.jpg -> -1 */ private static int getVersion(String name) { int extIndex = name.lastIndexOf(".xml"); if (extIndex > 0) { String nameWithoutExtension = name.substring(0,extIndex); int dotIndex = nameWithoutExtension.lastIndexOf('.'); if (dotIndex > 0) { String localidString = nameWithoutExtension.substring(dotIndex + 1); return Integer.parseInt(localidString); } } return -1; } public static int getID(String colName) { TraversableSource collection = getCollection(colName); int id = 0; Collection contents; try { contents = collection.getChildren(); } catch (SourceException se) { throw new RuntimeException("Unable to list contents for collection " + colName); } for (Iterator iter = contents.iterator(); iter.hasNext();) { TraversableSource content = (TraversableSource) iter.next(); if (content.isCollection()) { try { String name = content.getName(); int localid = Integer.parseInt(name); if (localid > id) id = localid; } catch (Exception e) {} } } return ++id; } public static boolean remove(String resourceName) { try { return remove((ModifiableTraversableSource)resolve(resourceName)); } catch (MalformedURLException e) { return false; } catch (IOException e) { return false; } } public static boolean remove(ModifiableTraversableSource resource) { boolean success = true; if (resource.isCollection()) { Collection contents; try { contents = resource.getChildren(); } catch (SourceException se) { throw new RuntimeException("Unable to list contents for collection " + resource); } for (Iterator iter = contents.iterator(); iter.hasNext();) { ModifiableTraversableSource element = (ModifiableTraversableSource) iter.next(); success = remove(element); } } try { resource.delete(); return success; } catch (SourceException e) { return false; } } public static void copy(String from, String to) throws IOException { copy((ModifiableTraversableSource)resolve(from), (ModifiableTraversableSource)resolve(to)); } public static void copy(ModifiableTraversableSource from, ModifiableTraversableSource to) throws IOException { if (!from.exists()) { throw new IOException("Cannot find source file/folder"); } if (from.isCollection()) { to.makeCollection(); Collection contents; try { contents = from.getChildren(); } catch (SourceException se) { throw new RuntimeException("Unable to list contents for collection " + from); } for (Iterator iter = contents.iterator(); iter.hasNext();) { ModifiableTraversableSource src = (ModifiableTraversableSource) iter.next(); SourceUtil.copy(src, resolve(to.getURI() + "/" + src.getName())); } } else { to = (ModifiableTraversableSource)resolve(to.getURI()); InputStream in = null; OutputStream out = null; try { in = from.getInputStream(); out = to.getOutputStream(); copy(in,out); } finally { if (out != null) out.close(); if (in != null) in.close(); } } } public static void copy(InputStream from, OutputStream to) throws IOException { byte[] buffer = new byte[64 * 1024]; int count = 0; do { to.write(buffer, 0, count); count = from.read(buffer, 0, buffer.length); } while (count != -1); } }