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.repository.impl;
018:
019: import java.io.BufferedInputStream;
020: import java.io.IOException;
021: import java.io.InputStream;
022: import java.net.MalformedURLException;
023: import java.util.Properties;
024:
025: import javax.xml.transform.OutputKeys;
026:
027: import org.apache.avalon.framework.activity.Disposable;
028: import org.apache.avalon.framework.activity.Initializable;
029: import org.apache.avalon.framework.component.Component;
030: import org.apache.avalon.framework.configuration.Configurable;
031: import org.apache.avalon.framework.configuration.Configuration;
032: import org.apache.avalon.framework.configuration.ConfigurationException;
033: import org.apache.avalon.framework.logger.AbstractLogEnabled;
034: import org.apache.avalon.framework.service.ServiceException;
035: import org.apache.avalon.framework.service.ServiceManager;
036: import org.apache.avalon.framework.service.Serviceable;
037: import org.apache.cocoon.ProcessingException;
038: import org.apache.cocoon.components.LifecycleHelper;
039: import org.apache.cocoon.components.repository.Repository;
040: import org.apache.cocoon.components.repository.helpers.CredentialsToken;
041: import org.apache.cocoon.components.repository.helpers.RepositoryTransactionHelper;
042: import org.apache.cocoon.components.repository.helpers.RepositoryPropertyHelper;
043: import org.apache.cocoon.components.repository.helpers.RepositoryVersioningHelper;
044: import org.apache.cocoon.components.webdav.WebDAVUtil;
045: import org.apache.cocoon.xml.XMLUtils;
046: import org.apache.commons.httpclient.HttpException;
047: import org.apache.commons.io.IOUtils;
048: import org.apache.excalibur.source.Source;
049: import org.apache.excalibur.xml.dom.DOMParser;
050: import org.apache.webdav.lib.WebdavResource;
051: import org.w3c.dom.Document;
052: import org.w3c.dom.Node;
053: import org.xml.sax.InputSource;
054: import org.xml.sax.SAXException;
055:
056: /**
057: * A repository implementation for WebDAV.
058: */
059: public class WebDAVRepository extends AbstractLogEnabled implements
060: Repository, Serviceable, Configurable, Initializable,
061: Disposable, Component {
062:
063: /** The name of the repository location configuration element */
064: public static final String REPO_BASE_CONF = "repo-base";
065:
066: /* The ServiceManager */
067: private ServiceManager manager;
068:
069: /* The RepositoryPropertyHelper */
070: private WebDAVRepositoryPropertyHelper propertyHelper;
071:
072: /* The RepositoryTransactionHelper */
073: private WebDAVRepositoryTransactionHelper transactionHelper;
074:
075: /* The RepositoryVersioningHelper */
076: private WebDAVRepositoryVersioningHelper versioningHelper;
077:
078: /* The location of the repository */
079: private String repoBaseUrl;
080:
081: /* The credentials to be used against the WebDAV repository */
082: private CredentialsToken credentials;
083:
084: /* (non-Javadoc)
085: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
086: */
087: public void service(ServiceManager manager) throws ServiceException {
088: this .manager = manager;
089:
090: }
091:
092: /* (non-Javadoc)
093: * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
094: */
095: public void configure(Configuration configuration)
096: throws ConfigurationException {
097: this .repoBaseUrl = configuration.getChild(REPO_BASE_CONF)
098: .getValue();
099: if (this .getLogger().isDebugEnabled()) {
100: this .getLogger().debug(
101: "configuring repository location "
102: + this .repoBaseUrl);
103: }
104: }
105:
106: /* (non-Javadoc)
107: * @see org.apache.avalon.framework.activity.Initializable#initialize()
108: */
109: public void initialize() throws Exception {
110: this .propertyHelper = new WebDAVRepositoryPropertyHelper(
111: this .credentials, this );
112: this .transactionHelper = new WebDAVRepositoryTransactionHelper(
113: this .credentials, this );
114: this .versioningHelper = new WebDAVRepositoryVersioningHelper(
115: this .credentials, this );
116: LifecycleHelper lh = new LifecycleHelper(this .getLogger(),
117: null, this .manager, null, null);
118: lh.setupComponent(this .propertyHelper, true);
119: lh.setupComponent(this .transactionHelper, true);
120: lh.setupComponent(this .versioningHelper, true);
121: }
122:
123: /* (non-Javadoc)
124: * @see org.apache.avalon.framework.activity.Disposable#dispose()
125: */
126: public void dispose() {
127: this .manager = null;
128: this .propertyHelper.dispose();
129: this .transactionHelper.dispose();
130: this .versioningHelper.dispose();
131: this .propertyHelper = null;
132: this .transactionHelper = null;
133: this .versioningHelper = null;
134: }
135:
136: /* (non-Javadoc)
137: * @see org.apache.cocoon.components.repository.Repository#getContentString(java.lang.String)
138: */
139: public String getContentString(String uri)
140: throws ProcessingException {
141:
142: try {
143: return IOUtils.toString(this .getContentStream(uri));
144:
145: } catch (IOException ioe) {
146: throw new ProcessingException("Error loading resource: "
147: + this .repoBaseUrl + uri, ioe);
148: }
149: }
150:
151: /* (non-Javadoc)
152: * @see org.apache.cocoon.components.repository.Repository#getContentStream(java.lang.String)
153: */
154: public InputStream getContentStream(String uri)
155: throws ProcessingException {
156:
157: if (this .getLogger().isDebugEnabled()) {
158: this .getLogger().debug("getting content of: " + uri);
159: }
160:
161: try {
162:
163: WebdavResource resource = WebDAVUtil.getWebdavResource(this
164: .getAbsoluteURI(uri));
165: if (!resource.exists()) {
166: throw new HttpException(uri + " does not exist");
167: }
168: return new BufferedInputStream(resource.getMethodData());
169:
170: } catch (MalformedURLException mue) {
171: throw new ProcessingException("Bad URL for resource: "
172: + this .repoBaseUrl + uri, mue);
173: } catch (IOException ioe) {
174: throw new ProcessingException("Error loading resource: "
175: + this .repoBaseUrl + uri, ioe);
176: }
177: }
178:
179: /* (non-Javadoc)
180: * @see org.apache.cocoon.components.repository.Repository#getContentDOM(java.lang.String)
181: */
182: public Document getContentDOM(String uri)
183: throws ProcessingException {
184:
185: DOMParser parser = null;
186:
187: try {
188: parser = (DOMParser) this .manager.lookup(DOMParser.ROLE);
189: return parser.parseDocument(new InputSource(this
190: .getContentStream(uri)));
191:
192: } catch (SAXException se) {
193: throw new ProcessingException("Error parsing: "
194: + this .repoBaseUrl + uri, se);
195: } catch (IOException ioe) {
196: throw new ProcessingException("Error getting: "
197: + this .repoBaseUrl + uri, ioe);
198: } catch (ServiceException se) {
199: throw new ProcessingException("Error getting DOMParser", se);
200:
201: } finally {
202: this .manager.release(parser);
203: }
204: }
205:
206: /* (non-Javadoc)
207: * @see org.apache.cocoon.components.repository.Repository#saveContent(java.lang.String, java.lang.String)
208: */
209: public boolean saveContent(String uri, String content) {
210:
211: if (this .getLogger().isDebugEnabled()) {
212: this .getLogger().debug("save content to " + uri);
213: }
214:
215: try {
216: return WebDAVUtil.getWebdavResource(
217: this .getAbsoluteURI(uri)).putMethod(content);
218:
219: } catch (HttpException he) {
220: this .getLogger().error(
221: "Error saving: " + this .repoBaseUrl + uri, he);
222: } catch (IOException ioe) {
223: this .getLogger().error(
224: "Error saving: " + this .repoBaseUrl + uri, ioe);
225: }
226:
227: return false;
228: }
229:
230: /* (non-Javadoc)
231: * @see org.apache.cocoon.components.repository.Repository#saveContent(java.lang.String, org.w3c.dom.Node)
232: */
233: public boolean saveContent(String uri, Node node) {
234:
235: try {
236: Properties format = new Properties();
237: format.put(OutputKeys.METHOD, "xml");
238: format.put(OutputKeys.OMIT_XML_DECLARATION, "yes");
239: return this .saveContent(uri, XMLUtils.serializeNode(node,
240: format));
241:
242: } catch (ProcessingException pe) {
243: this .getLogger().error(
244: "Error saving dom to: " + this .repoBaseUrl + uri,
245: pe);
246: }
247:
248: return false;
249: }
250:
251: /* (non-Javadoc)
252: * @see org.apache.cocoon.components.repository.Repository#saveContent(java.lang.String, org.apache.excalibur.source.Source)
253: */
254: public boolean saveContent(String uri, Source source) {
255:
256: try {
257: return this .saveContent(uri, IOUtils.toString(source
258: .getInputStream()));
259:
260: } catch (IOException ioe) {
261: this .getLogger().error(
262: "Error saving source: " + source.getURI() + " to "
263: + this .repoBaseUrl + uri, ioe);
264: }
265:
266: return false;
267: }
268:
269: /* (non-Javadoc)
270: * @see org.apache.cocoon.components.repository.Repository#createResource(java.lang.String, java.lang.String)
271: */
272: public boolean createResource(String uri, String content) {
273:
274: if (this .getLogger().isDebugEnabled()) {
275: this .getLogger().debug("creating new resource " + uri);
276: }
277:
278: try {
279: WebDAVUtil
280: .createResource(this .getAbsoluteURI(uri), content);
281: return true;
282:
283: } catch (HttpException he) {
284: this .getLogger().error(
285: "Error creating resource: " + this .repoBaseUrl
286: + uri, he);
287: } catch (IOException ioe) {
288: this .getLogger().error(
289: "Error creating resource: " + this .repoBaseUrl
290: + uri, ioe);
291: }
292:
293: return false;
294: }
295:
296: /* (non-Javadoc)
297: * @see org.apache.cocoon.components.repository.Repository#exists(java.lang.String)
298: */
299: public boolean exists(String uri) {
300:
301: if (this .getLogger().isDebugEnabled()) {
302: this .getLogger().debug("checking existance of " + uri);
303: }
304:
305: try {
306: return WebDAVUtil.getWebdavResource(
307: this .getAbsoluteURI(uri)).exists();
308:
309: } catch (HttpException he) {
310: this .getLogger().error(
311: "HTTP Error occurred while checking for existance of: "
312: + uri, he);
313: } catch (IOException ioe) {
314: this .getLogger().error(
315: "IO Error occurred while checking for existance of: "
316: + uri, ioe);
317: }
318:
319: return false;
320: }
321:
322: /* (non-Javadoc)
323: * @see org.apache.cocoon.components.repository.Repository#copy(java.lang.String, java.lang.String, boolean)
324: */
325: public boolean copy(String uri, String dest, boolean recurse,
326: boolean overwrite) {
327:
328: try {
329: WebDAVUtil.copyResource(this .getAbsoluteURI(uri), this
330: .getAbsoluteURI(dest), recurse, overwrite);
331: return true;
332:
333: } catch (HttpException he) {
334: this .getLogger()
335: .error(
336: "HTTP Error copying: " + this .repoBaseUrl
337: + uri, he);
338: } catch (IOException ioe) {
339: this .getLogger().error(
340: "IO Error copying: " + this .repoBaseUrl + uri, ioe);
341: }
342:
343: return false;
344: }
345:
346: /* (non-Javadoc)
347: * @see org.apache.cocoon.components.repository.Repository#move(java.lang.String, java.lang.String, boolean)
348: */
349: public boolean move(String uri, String dest, boolean recurse,
350: boolean overwrite) {
351:
352: try {
353: WebDAVUtil.moveResource(this .getAbsoluteURI(uri), this
354: .getAbsoluteURI(dest), recurse, overwrite);
355: return true;
356: } catch (HttpException he) {
357: this .getLogger().error(
358: "HTTP Error moving: " + this .repoBaseUrl + uri, he);
359: } catch (IOException ioe) {
360: this .getLogger().error(
361: "IO Error moving: " + this .repoBaseUrl + uri, ioe);
362: }
363:
364: return false;
365: }
366:
367: /* (non-Javadoc)
368: * @see org.apache.cocoon.components.repository.Repository#remove(java.lang.String)
369: */
370: public boolean remove(String uri) {
371:
372: try {
373: return WebDAVUtil.getWebdavResource(
374: this .getAbsoluteURI(uri)).deleteMethod();
375:
376: } catch (HttpException he) {
377: this .getLogger().error(
378: "HTTP Error removing: " + this .repoBaseUrl + uri,
379: he);
380: } catch (IOException ioe) {
381: this .getLogger()
382: .error(
383: "IO Error removing: " + this .repoBaseUrl
384: + uri, ioe);
385: }
386:
387: return false;
388: }
389:
390: /* (non-Javadoc)
391: * @see org.apache.cocoon.components.repository.Repository#makeCollection(java.lang.String, boolean)
392: */
393: public boolean makeCollection(String uri, boolean recursive) {
394:
395: try {
396: if (uri.endsWith("/"))
397: uri = uri.substring(0, uri.length() - 1);
398: if (recursive) {
399: WebDAVUtil.makePath(this .getAbsoluteURI(uri));
400: return true;
401: } else {
402: String parent = uri.substring(0, uri.lastIndexOf("/"));
403: String collection = uri
404: .substring(uri.lastIndexOf("/") + 1);
405: WebDAVUtil.makeCollection(this .getAbsoluteURI(parent),
406: collection);
407: return true;
408: }
409:
410: } catch (HttpException he) {
411: this .getLogger().error(
412: "HTTP Error making collection: " + this .repoBaseUrl
413: + uri, he);
414: } catch (IOException ioe) {
415: this .getLogger().error(
416: "IO Error making collection: " + this .repoBaseUrl
417: + uri, ioe);
418: }
419:
420: return false;
421: }
422:
423: /**
424: * get a WebDAV property helper
425: *
426: * @return a WebDAV property helper.
427: */
428: public RepositoryPropertyHelper getPropertyHelper() {
429: return this .propertyHelper;
430: }
431:
432: /**
433: * get a WebDAV transaction helper
434: *
435: * @return a WebDAV transaction helper.
436: */
437: public RepositoryTransactionHelper getTransactionHelper() {
438: return this .transactionHelper;
439: }
440:
441: /**
442: * get a WebDAV versioning helper
443: *
444: * @return a WebDAV versioning helper.
445: */
446: public RepositoryVersioningHelper getVersioningHelper() {
447: return this .versioningHelper;
448: }
449:
450: /**
451: * get the absolute URI of a given path
452: *
453: * @param uri the uri to get a versioning helper for.
454: * @return the absolute URI.
455: */
456: public String getAbsoluteURI(String uri) {
457:
458: return "http://" + this .credentials.getPrincipal().getName()
459: + ":" + this .credentials.getCredentials() + "@"
460: + this .repoBaseUrl + uri;
461: }
462:
463: /* (non-Javadoc)
464: * @see org.apache.cocoon.components.repository.Repository#getCredentials()
465: */
466: public CredentialsToken getCredentials() {
467: return this .credentials;
468: }
469:
470: /* (non-Javadoc)
471: * @see org.apache.cocoon.components.repository.Repository#setCredentials(org.apache.cocoon.components.repository.helpers.CredentialsToken)
472: */
473: public void setCredentials(CredentialsToken credentials) {
474: this.credentials = credentials;
475: }
476:
477: }
|