001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.components;
018:
019: import java.io.IOException;
020: import java.io.InputStream;
021: import java.io.OutputStream;
022: import java.net.MalformedURLException;
023: import java.util.ArrayList;
024: import java.util.Collection;
025: import java.util.Enumeration;
026: import java.util.Iterator;
027:
028: import org.apache.avalon.framework.component.Component;
029: import org.apache.avalon.framework.component.ComponentException;
030: import org.apache.avalon.framework.component.ComponentManager;
031: import org.apache.cocoon.environment.Request;
032: import org.apache.cocoon.servlet.multipart.Part;
033: import org.apache.excalibur.source.ModifiableSource;
034: import org.apache.excalibur.source.ModifiableTraversableSource;
035: import org.apache.excalibur.source.Source;
036: import org.apache.excalibur.source.SourceException;
037: import org.apache.excalibur.source.SourceResolver;
038: import org.apache.excalibur.source.SourceUtil;
039: import org.apache.excalibur.source.TraversableSource;
040:
041: /**
042: * @author stefano
043: * @version CVS $Id: SourceRepository.java 540711 2007-05-22 19:36:07Z cziegeler $
044: */
045: public class SourceRepository {
046:
047: public static final String FILE_NAME = "document";
048:
049: private static SourceRepository instance;
050:
051: private static ComponentManager manager;
052:
053: private SourceRepository() {
054: manager = CocoonComponentManager.getSitemapComponentManager();
055: }
056:
057: public static SourceRepository getInstance() {
058: if (instance == null) {
059: instance = new SourceRepository();
060: }
061: return instance;
062: }
063:
064: private static Source resolve(String uri)
065: throws MalformedURLException, IOException {
066: SourceResolver resolver = null;
067: TraversableSource source;
068: try {
069: resolver = (SourceResolver) manager
070: .lookup(SourceResolver.ROLE);
071: source = (TraversableSource) resolver.resolveURI(uri);
072: } catch (ComponentException ce) {
073: throw new IOException("ComponentException");
074: } finally {
075: manager.release((Component) resolver);
076: }
077: return source;
078: }
079:
080: private static TraversableSource getCollection(String colName) {
081: TraversableSource source;
082: try {
083: source = (TraversableSource) resolve(colName);
084: } catch (MalformedURLException e) {
085: throw new RuntimeException(
086: "'unable to resolve source: malformed URL");
087: } catch (IOException e) {
088: throw new RuntimeException(
089: "'unable to resolve source: IOException");
090: }
091: if (!source.isCollection())
092: throw new RuntimeException(colName
093: + " is not a collection!");
094: return source;
095: }
096:
097: public static void save(Request request, String dirName)
098: throws Exception {
099: TraversableSource collection = getCollection(dirName);
100: ModifiableTraversableSource result;
101:
102: Enumeration params = request.getParameterNames();
103: while (params.hasMoreElements()) {
104: String name = (String) params.nextElement();
105: if (name.indexOf("..") > -1)
106: throw new Exception("We are under attack!!");
107: //System.out.println("[param] " + name);
108: if (name.startsWith("save:")) {
109: Part part = (Part) request.get(name);
110: String code = name.substring(5);
111: if (!(collection instanceof ModifiableSource)) {
112: throw new RuntimeException(
113: "Cannot modify the given source");
114: }
115: result = (ModifiableTraversableSource) resolve(collection
116: .getURI()
117: + "/" + code);
118:
119: save(part, result);
120: } else if (name.startsWith("delete:")) {
121: String value = request.getParameter(name);
122: if (value.length() > 0) {
123: String code = name.substring(7);
124: result = (ModifiableTraversableSource) resolve(collection
125: + "/" + code);
126: remove(result);
127: }
128: }
129: }
130: }
131:
132: public static void save(Request request, String param, String dest)
133: throws Exception {
134: Part part = (Part) request.get(param);
135: save(part, (ModifiableTraversableSource) resolve(dest));
136: }
137:
138: public static void save(Part part,
139: ModifiableTraversableSource destination) throws Exception {
140: InputStream in = null;
141: OutputStream out = null;
142: try {
143: in = part.getInputStream();
144: out = destination.getOutputStream();
145: copy(in, out);
146: } finally {
147: if (out != null) {
148: out.close();
149: }
150: if (in != null) {
151: in.close();
152: }
153: }
154: }
155:
156: public static OutputStream getOutputStream(String collection)
157: throws IOException {
158: String mainResource = collection + "/" + FILE_NAME + ".xml";
159: String versionedResource = collection + "/" + FILE_NAME + "."
160: + getVersionID(collection) + ".xml";
161: copy(mainResource, versionedResource);
162: return ((ModifiableSource) resolve(mainResource))
163: .getOutputStream();
164: }
165:
166: public static void revertFrom(String collection, int version)
167: throws IOException {
168: String mainResource = collection + "/" + FILE_NAME + ".xml";
169: String versionedResource = collection + "/" + FILE_NAME + "."
170: + version + ".xml";
171: copy(versionedResource, mainResource);
172: }
173:
174: /**
175: * Returns the highest version id of the files included in the given
176: * directory.
177: */
178: public static int getVersionID(String colName) {
179: TraversableSource collection = getCollection(colName);
180: int id = 0;
181: Collection contents;
182: try {
183: contents = collection.getChildren();
184: } catch (SourceException se) {
185: throw new RuntimeException(
186: "Unable to list contents for collection " + colName);
187: }
188: for (Iterator iter = contents.iterator(); iter.hasNext();) {
189: TraversableSource content = (TraversableSource) iter.next();
190: if (!content.isCollection()) {
191: try {
192: int localid = getVersion(content.getName());
193: if (localid > id)
194: id = localid;
195: } catch (Exception e) {
196: }
197:
198: }
199: }
200:
201: return ++id;
202: }
203:
204: public static Object[] getVersions(String colName) {
205: TraversableSource collection = getCollection(colName);
206: ArrayList versions = new ArrayList();
207:
208: Collection contents;
209: try {
210: contents = collection.getChildren();
211: } catch (SourceException se) {
212: throw new RuntimeException(
213: "Unable to list contents for collection " + colName);
214: }
215:
216: for (Iterator iter = contents.iterator(); iter.hasNext();) {
217: TraversableSource content = (TraversableSource) iter.next();
218: if (!content.isCollection()) {
219: try {
220: int version = getVersion(content.getName());
221: if (version > 0) {
222: versions.add(new Integer(version));
223: }
224: } catch (Exception e) {
225: }
226: }
227:
228: }
229:
230: return versions.toArray();
231: }
232:
233: /**
234: * Return the version encoded into the name as a numeric subextension of
235: * an .xml extension.
236: *
237: * Example:
238: * anything.123.xml -> 123
239: * document.3.xml -> 3
240: * document.0.xml -> 0
241: * document.xml -> -1
242: * image.0.jpg -> -1
243: */
244: private static int getVersion(String name) {
245: int extIndex = name.lastIndexOf(".xml");
246: if (extIndex > 0) {
247: String nameWithoutExtension = name.substring(0, extIndex);
248: int dotIndex = nameWithoutExtension.lastIndexOf('.');
249: if (dotIndex > 0) {
250: String localidString = nameWithoutExtension
251: .substring(dotIndex + 1);
252: return Integer.parseInt(localidString);
253: }
254: }
255: return -1;
256: }
257:
258: public static int getID(String colName) {
259: TraversableSource collection = getCollection(colName);
260:
261: int id = 0;
262: Collection contents;
263: try {
264: contents = collection.getChildren();
265: } catch (SourceException se) {
266: throw new RuntimeException(
267: "Unable to list contents for collection " + colName);
268: }
269:
270: for (Iterator iter = contents.iterator(); iter.hasNext();) {
271: TraversableSource content = (TraversableSource) iter.next();
272: if (content.isCollection()) {
273: try {
274: String name = content.getName();
275: int localid = Integer.parseInt(name);
276: if (localid > id)
277: id = localid;
278: } catch (Exception e) {
279: }
280: }
281: }
282: return ++id;
283: }
284:
285: public static boolean remove(String resourceName) {
286: try {
287: return remove((ModifiableTraversableSource) resolve(resourceName));
288: } catch (MalformedURLException e) {
289: return false;
290: } catch (IOException e) {
291: return false;
292: }
293:
294: }
295:
296: public static boolean remove(ModifiableTraversableSource resource) {
297: boolean success = true;
298:
299: if (resource.isCollection()) {
300: Collection contents;
301: try {
302: contents = resource.getChildren();
303: } catch (SourceException se) {
304: throw new RuntimeException(
305: "Unable to list contents for collection "
306: + resource);
307: }
308: for (Iterator iter = contents.iterator(); iter.hasNext();) {
309: ModifiableTraversableSource element = (ModifiableTraversableSource) iter
310: .next();
311: success = remove(element);
312: }
313:
314: }
315: try {
316: resource.delete();
317: return success;
318: } catch (SourceException e) {
319: return false;
320: }
321:
322: }
323:
324: public static void copy(String from, String to) throws IOException {
325: copy((ModifiableTraversableSource) resolve(from),
326: (ModifiableTraversableSource) resolve(to));
327: }
328:
329: public static void copy(ModifiableTraversableSource from,
330: ModifiableTraversableSource to) throws IOException {
331:
332: if (!from.exists()) {
333: throw new IOException("Cannot find source file/folder");
334: }
335:
336: if (from.isCollection()) {
337: to.makeCollection();
338: Collection contents;
339: try {
340: contents = from.getChildren();
341: } catch (SourceException se) {
342: throw new RuntimeException(
343: "Unable to list contents for collection "
344: + from);
345: }
346: for (Iterator iter = contents.iterator(); iter.hasNext();) {
347: ModifiableTraversableSource src = (ModifiableTraversableSource) iter
348: .next();
349: SourceUtil.copy(src, resolve(to.getURI() + "/"
350: + src.getName()));
351:
352: }
353: } else {
354: to = (ModifiableTraversableSource) resolve(to.getURI());
355: InputStream in = null;
356: OutputStream out = null;
357: try {
358: in = from.getInputStream();
359: out = to.getOutputStream();
360: copy(in, out);
361: } finally {
362: if (out != null)
363: out.close();
364: if (in != null)
365: in.close();
366: }
367: }
368: }
369:
370: public static void copy(InputStream from, OutputStream to)
371: throws IOException {
372: byte[] buffer = new byte[64 * 1024];
373: int count = 0;
374: do {
375: to.write(buffer, 0, count);
376: count = from.read(buffer, 0, buffer.length);
377: } while (count != -1);
378: }
379:
380: }
|