0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.cocoon.components.source.impl;
0019:
0020: import java.io.ByteArrayOutputStream;
0021: import java.io.IOException;
0022: import java.io.InputStream;
0023: import java.io.OutputStream;
0024: import java.io.StringReader;
0025: import java.util.ArrayList;
0026: import java.util.Collection;
0027: import java.util.Collections;
0028: import java.util.Date;
0029: import java.util.Enumeration;
0030: import java.util.List;
0031:
0032: import org.apache.avalon.framework.activity.Initializable;
0033: import org.apache.avalon.framework.context.Context;
0034: import org.apache.avalon.framework.context.ContextException;
0035: import org.apache.avalon.framework.context.Contextualizable;
0036: import org.apache.avalon.framework.logger.AbstractLogEnabled;
0037: import org.apache.avalon.framework.logger.LogEnabled;
0038: import org.apache.avalon.framework.logger.Logger;
0039: import org.apache.avalon.framework.service.ServiceManager;
0040: import org.apache.avalon.framework.service.Serviceable;
0041: import org.apache.cocoon.CascadingIOException;
0042: import org.apache.cocoon.Constants;
0043: import org.apache.cocoon.components.source.InspectableSource;
0044: import org.apache.cocoon.components.source.LockableSource;
0045: import org.apache.cocoon.components.source.VersionableSource;
0046: import org.apache.cocoon.components.source.helpers.SourceLock;
0047: import org.apache.cocoon.components.source.helpers.SourceProperty;
0048: import org.apache.excalibur.source.ModifiableTraversableSource;
0049: import org.apache.excalibur.source.MoveableSource;
0050: import org.apache.excalibur.source.Source;
0051: import org.apache.excalibur.source.SourceException;
0052: import org.apache.excalibur.source.SourceUtil;
0053: import org.apache.excalibur.source.SourceValidity;
0054: import org.apache.excalibur.source.impl.validity.TimeStampValidity;
0055: import org.apache.excalibur.xml.dom.DOMParser;
0056: import org.apache.slide.authenticate.CredentialsToken;
0057: import org.apache.slide.common.NamespaceAccessToken;
0058: import org.apache.slide.common.SlideException;
0059: import org.apache.slide.common.SlideToken;
0060: import org.apache.slide.common.SlideTokenImpl;
0061: import org.apache.slide.content.Content;
0062: import org.apache.slide.content.NodeProperty;
0063: import org.apache.slide.content.NodeRevisionContent;
0064: import org.apache.slide.content.NodeRevisionDescriptor;
0065: import org.apache.slide.content.NodeRevisionDescriptors;
0066: import org.apache.slide.content.NodeRevisionNumber;
0067: import org.apache.slide.content.RevisionDescriptorNotFoundException;
0068: import org.apache.slide.lock.Lock;
0069: import org.apache.slide.lock.NodeLock;
0070: import org.apache.slide.macro.Macro;
0071: import org.apache.slide.security.AccessDeniedException;
0072: import org.apache.slide.structure.ObjectNode;
0073: import org.apache.slide.structure.ObjectNotFoundException;
0074: import org.apache.slide.structure.Structure;
0075: import org.apache.slide.structure.SubjectNode;
0076: import org.w3c.dom.Document;
0077: import org.xml.sax.InputSource;
0078:
0079: /**
0080: * A sources from jakarta slide repositories.
0081: *
0082: * @version CVS $Id: SlideSource.java 433543 2006-08-22 06:22:54Z crossley $
0083: */
0084: public class SlideSource extends AbstractLogEnabled implements
0085: Contextualizable, Serviceable, Initializable, Source,
0086: ModifiableTraversableSource, MoveableSource, LockableSource,
0087: InspectableSource, VersionableSource {
0088:
0089: /* framework objects */
0090: private Context m_context;
0091: private ServiceManager m_manager;
0092:
0093: /* Slide access */
0094: private NamespaceAccessToken m_nat;
0095: private SlideToken m_slideToken;
0096:
0097: /* Slide helpers */
0098: private Structure m_structure;
0099: private Content m_content;
0100: private Lock m_lock;
0101: private Macro m_macro;
0102:
0103: /* Source specifics */
0104: private String m_scheme;
0105: private String m_path;
0106: private String m_scope;
0107: private String m_uri;
0108:
0109: private ObjectNode m_node;
0110: private NodeRevisionNumber m_version;
0111: private NodeRevisionDescriptors m_descriptors;
0112: private NodeRevisionDescriptor m_descriptor;
0113:
0114: private String m_principal;
0115: private SourceValidity m_validity;
0116:
0117: private SlideSourceOutputStream m_outputStream;
0118:
0119: /**
0120: * Create a slide source.
0121: *
0122: * @param nat Namespace access token
0123: * @param scheme Scheme of the source
0124: * @param path Path of the source.
0125: */
0126: public SlideSource(NamespaceAccessToken nat, String scheme,
0127: String scope, String path, String principal, String version) {
0128:
0129: m_nat = nat;
0130: m_scheme = scheme;
0131: m_scope = scope;
0132: m_path = path;
0133: if (path.equals("/")) {
0134: m_uri = scope;
0135: } else if (scope.equals("/")) {
0136: m_uri = path;
0137: } else {
0138: m_uri = scope + path;
0139: }
0140: m_principal = principal;
0141: if (version != null) {
0142: m_version = new NodeRevisionNumber(version);
0143: }
0144: }
0145:
0146: /**
0147: * Pass the Context to the component.
0148: * This method is called after the LogEnabled.enableLogging() (if present)
0149: * method and before any other method.
0150: *
0151: * @param context The context.
0152: */
0153: public void contextualize(Context context) {
0154: this .m_context = context;
0155: }
0156:
0157: /**
0158: * Pass the ServiceManager to the composer. The Serviceable implementation
0159: * should use the specified ServiceManager to acquire the services it needs for execution
0160: *
0161: * @param manager The ServiceManager which this Serviceable uses
0162: */
0163: public void service(ServiceManager manager) {
0164: m_manager = manager;
0165: }
0166:
0167: public void initialize() throws SourceException {
0168:
0169: CredentialsToken credentials = new CredentialsToken(m_principal);
0170: m_slideToken = new SlideTokenImpl(credentials);
0171:
0172: m_structure = m_nat.getStructureHelper();
0173: m_content = m_nat.getContentHelper();
0174: m_lock = m_nat.getLockHelper();
0175: m_macro = m_nat.getMacroHelper();
0176:
0177: try {
0178: if (m_node == null) {
0179: m_node = m_structure.retrieve(m_slideToken, m_uri);
0180: }
0181:
0182: m_descriptors = m_content.retrieve(m_slideToken, m_uri);
0183: if (m_version != null) {
0184: // get a specific version
0185: m_descriptor = m_content.retrieve(m_slideToken,
0186: m_descriptors, m_version);
0187: } else {
0188: // get the latest one
0189: m_descriptor = m_content.retrieve(m_slideToken,
0190: m_descriptors);
0191: m_version = m_descriptor.getRevisionNumber();
0192: }
0193: } catch (ObjectNotFoundException e) {
0194: if (getLogger().isDebugEnabled()) {
0195: getLogger().debug("Not found.", e);
0196: }
0197: // assert m_node == null;
0198: } catch (RevisionDescriptorNotFoundException e) {
0199: if (getLogger().isDebugEnabled()) {
0200: getLogger().debug("Could not retrieve descriptor.", e);
0201: }
0202: // assert m_descriptor == null;
0203: } catch (AccessDeniedException e) {
0204: throw new SourceException("Access denied.", e);
0205: } catch (SlideException e) {
0206: throw new SourceException(
0207: "Failure during source initialization.", e);
0208: }
0209: }
0210:
0211: /**
0212: * Return an <code>InputStream</code> object to read from the source.
0213: * This is the data at the point of invocation of this method,
0214: * so if this is Modifiable, you might get different content
0215: * from two different invocations.
0216: *
0217: * @return Input stream for the source.
0218: *
0219: * @throws IOException If an IO excepetion occurs.
0220: * @throws SourceException If an exception occurs.
0221: */
0222: public InputStream getInputStream() throws IOException,
0223: SourceException {
0224: try {
0225: return m_content.retrieve(m_slideToken, m_descriptors,
0226: m_descriptor).streamContent();
0227: } catch (SlideException se) {
0228: throw new SourceException("Could not get source", se);
0229: }
0230: }
0231:
0232: /**
0233: * Return the unique identifer for this source
0234: *
0235: * @return System identifier for the source.
0236: */
0237: public String getURI() {
0238: return m_scheme + "://" + m_principal + "@" + m_nat.getName()
0239: + m_path;
0240: }
0241:
0242: /**
0243: * @see org.apache.excalibur.source.Source#getScheme()
0244: *
0245: * @return Scheme of the source.
0246: */
0247: public String getScheme() {
0248: return m_scheme;
0249: }
0250:
0251: /**
0252: * Get the Validity object. This can either wrap the last modification
0253: * date or the expires information or...
0254: * If it is currently not possible to calculate such an information
0255: * <code>null</code> is returned.
0256: *
0257: * @return Validity for the source.
0258: */
0259: public SourceValidity getValidity() {
0260: if (m_validity == null && m_descriptor != null) {
0261: final long lastModified = getLastModified();
0262: if (lastModified > 0) {
0263: m_validity = new TimeStampValidity(lastModified);
0264: }
0265: }
0266: return m_validity;
0267: }
0268:
0269: /**
0270: * Refresh the content of this object after the underlying data
0271: * content has changed.
0272: */
0273: public void refresh() {
0274: m_validity = null;
0275: }
0276:
0277: /**
0278: * The mime-type of the content described by this object.
0279: * If the source is not able to determine the mime-type by itself
0280: * this can be null.
0281: *
0282: * @return Mime type of the source.
0283: */
0284: public String getMimeType() {
0285: if (m_descriptor != null) {
0286: return m_descriptor.getContentType();
0287: }
0288: return null;
0289: }
0290:
0291: /**
0292: * Does this source actually exist ?
0293: *
0294: * @return true if the resource exists.
0295: */
0296: public boolean exists() {
0297: return m_node != null;
0298: }
0299:
0300: /**
0301: * Return the content length of the content or -1 if the length is
0302: * unknown.
0303: *
0304: * @return Content length of the source.
0305: */
0306: public long getContentLength() {
0307: if (m_descriptor != null) {
0308: return m_descriptor.getContentLength();
0309: }
0310: return -1;
0311: }
0312:
0313: /**
0314: * Get the last modification date of the source or 0 if it
0315: * is not possible to determine the date.
0316: *
0317: * @return Last modified date of the source.
0318: */
0319: public long getLastModified() {
0320: if (m_descriptor != null) {
0321: return m_descriptor.getLastModifiedAsDate().getTime();
0322: }
0323: return 0;
0324: }
0325:
0326: // ---------------------------------------------------- ModifiableTraversableSource
0327:
0328: /**
0329: * Get an <code>OutputStream</code> where raw bytes can be written to.
0330: * The signification of these bytes is implementation-dependent and
0331: * is not restricted to a serialized XML document.
0332: *
0333: * @return a stream to write to
0334: *
0335: * @throws IOException
0336: * @throws SourceException
0337: */
0338: public OutputStream getOutputStream() throws IOException,
0339: SourceException {
0340: if (m_outputStream == null) {
0341: m_outputStream = new SlideSourceOutputStream();
0342: m_outputStream.enableLogging(getLogger());
0343: }
0344: return m_outputStream;
0345: }
0346:
0347: /**
0348: * Can the data sent to an <code>OutputStream</code> returned by
0349: * {@link #getOutputStream()} be cancelled ?
0350: *
0351: * @param stream The ouput stream, which should be cancelled.
0352: * @return true if the stream can be cancelled
0353: */
0354: public boolean canCancel(OutputStream stream) {
0355: return m_outputStream.canCancel();
0356: }
0357:
0358: /**
0359: * Cancel the data sent to an <code>OutputStream</code> returned by
0360: * {@link #getOutputStream()}.
0361: * <p>
0362: * After cancel, the stream should no more be used.
0363: *
0364: * @param stream The ouput stream, which should be cancelled.
0365: *
0366: * @throws SourceException If the ouput stream can't be cancelled.
0367: */
0368: public void cancel(OutputStream stream) throws SourceException {
0369: if (m_outputStream == stream) {
0370: try {
0371: m_outputStream.cancel();
0372: } catch (Exception e) {
0373: throw new SourceException(
0374: "Could not cancel output stream", e);
0375: }
0376: }
0377: }
0378:
0379: /**
0380: * Delete the source.
0381: */
0382: public void delete() {
0383: try {
0384: m_nat.begin();
0385: m_macro.delete(m_slideToken, m_uri);
0386: m_nat.commit();
0387: } catch (Exception se) {
0388: getLogger().error("Could not delete source.", se);
0389: try {
0390: m_nat.rollback();
0391: } catch (Exception rbe) {
0392: getLogger().error("Rollback failed for moving source",
0393: rbe);
0394: }
0395: }
0396: }
0397:
0398: public void makeCollection() throws SourceException {
0399: SubjectNode collection = new SubjectNode();
0400: NodeRevisionDescriptor descriptor = new NodeRevisionDescriptor(
0401: 0);
0402:
0403: descriptor.setResourceType("<collection/>");
0404: descriptor.setCreationDate(new Date());
0405: descriptor.setLastModified(new Date());
0406: descriptor.setContentLength(0);
0407: descriptor.setSource("");
0408: descriptor.setOwner(m_slideToken.getCredentialsToken()
0409: .getPublicCredentials());
0410:
0411: try {
0412: m_nat.begin();
0413: m_structure.create(m_slideToken, collection, m_uri);
0414: m_content.create(m_slideToken, m_uri, descriptor, null);
0415: m_nat.commit();
0416: } catch (Exception se) {
0417: try {
0418: m_nat.rollback();
0419: } catch (Exception rbe) {
0420: getLogger().error(
0421: "Rollback failed for creating collection", rbe);
0422: }
0423: throw new SourceException("Could not create collection.",
0424: se);
0425: }
0426: }
0427:
0428: public Source getChild(String name) throws SourceException {
0429: return getChildByPath(m_path + "/" + name);
0430: }
0431:
0432: private Source getChildByPath(String path) throws SourceException {
0433: SlideSource child = new SlideSource(m_nat, m_scheme, m_scope,
0434: path, m_principal, null);
0435: child.enableLogging(getLogger());
0436: child.contextualize(m_context);
0437: child.service(m_manager);
0438: child.initialize();
0439: return child;
0440: }
0441:
0442: public Collection getChildren() throws SourceException {
0443: if (m_node == null || !m_node.hasChildren()) {
0444: return Collections.EMPTY_LIST;
0445: }
0446: List result = new ArrayList();
0447: final Enumeration children = m_node.enumerateChildren();
0448: while (children.hasMoreElements()) {
0449: String child = (String) children.nextElement();
0450: child = child.substring(m_scope.length());
0451: result.add(getChildByPath(child));
0452: }
0453: return result;
0454: }
0455:
0456: public String getName() {
0457: int index = m_path.lastIndexOf('/');
0458: if (index != -1) {
0459: return m_path.substring(index + 1);
0460: }
0461: return m_path;
0462: }
0463:
0464: public Source getParent() throws SourceException {
0465: if (m_path.length() == 1) {
0466: // assert m_path.equals("/")
0467: return null;
0468: }
0469: int index = m_path.lastIndexOf('/');
0470: if (index == -1) {
0471: return null;
0472: }
0473: String parentPath;
0474: if (index == 0) {
0475: parentPath = "/";
0476: } else if (index == m_path.length() - 1) {
0477: // assert m_path.endsWith("/")
0478: parentPath = m_path.substring(0, m_path.substring(0,
0479: m_path.length() - 1).lastIndexOf('/'));
0480: } else {
0481: parentPath = m_path.substring(0, index);
0482: }
0483: SlideSource parent = new SlideSource(m_nat, m_scheme, m_scope,
0484: parentPath, m_principal, null);
0485: parent.enableLogging(getLogger());
0486: parent.contextualize(m_context);
0487: parent.service(m_manager);
0488: parent.initialize();
0489: return parent;
0490:
0491: }
0492:
0493: public boolean isCollection() {
0494: if (m_node == null) {
0495: return false;
0496: }
0497: if (m_descriptor == null) {
0498: // FIXME: is this correct?
0499: return true;
0500: }
0501: NodeProperty property = m_descriptor
0502: .getProperty("resourcetype");
0503: if (property != null
0504: && ((String) property.getValue())
0505: .startsWith("<collection/>")) {
0506: return true;
0507: }
0508: return false;
0509: }
0510:
0511: /**
0512: * A helper for the getOutputStream() method
0513: */
0514: class SlideSourceOutputStream extends ByteArrayOutputStream
0515: implements LogEnabled {
0516: private boolean isClosed = false;
0517: private Logger logger = null;
0518:
0519: /**
0520: * Provide component with a logger.
0521: *
0522: * @param logger the logger
0523: */
0524: public void enableLogging(Logger logger) {
0525: this .logger = logger;
0526: }
0527:
0528: /**
0529: *
0530: *
0531: * @throws IOException
0532: */
0533: public void close() throws IOException {
0534: super .close();
0535:
0536: byte[] bytes = new byte[0]; // must be initialized
0537:
0538: try {
0539: NodeRevisionContent content = new NodeRevisionContent();
0540: bytes = toByteArray();
0541: content.setContent(bytes);
0542:
0543: if (m_descriptor == null) {
0544: m_descriptor = new NodeRevisionDescriptor(0);
0545: m_descriptor.setName(getName());
0546: }
0547:
0548: m_descriptor.setContentLength(bytes.length);
0549: m_descriptor.setLastModified(new Date());
0550:
0551: m_nat.begin();
0552: if (m_version == null) {
0553: m_content.create(m_slideToken, m_uri, m_descriptor,
0554: null);
0555: }
0556: m_content.store(m_slideToken, m_uri, m_descriptor,
0557: content);
0558: try {
0559: m_nat.commit();
0560: } catch (Exception cme) {
0561: throw new CascadingIOException(
0562: "Could not commit the transaction", cme);
0563: }
0564:
0565: } catch (ObjectNotFoundException e) {
0566:
0567: // Todo : Check to see if parent exists
0568: SubjectNode subject = new SubjectNode();
0569:
0570: try {
0571: // Creating an object
0572: m_structure.create(m_slideToken, subject, m_uri);
0573: } catch (SlideException se) {
0574: throw new CascadingIOException(se);
0575: }
0576:
0577: NodeRevisionDescriptor descriptor = new NodeRevisionDescriptor(
0578: bytes.length);
0579: descriptor.setResourceType("");
0580: descriptor.setSource("");
0581: descriptor.setContentLanguage("en");
0582: descriptor.setContentLength(bytes.length);
0583: String contentType = null;
0584:
0585: try {
0586: contentType = ((org.apache.cocoon.environment.Context) m_context
0587: .get(Constants.CONTEXT_ENVIRONMENT_CONTEXT))
0588: .getMimeType(m_path);
0589: } catch (ContextException ce) {
0590: this .logger
0591: .warn("Could not get context to determine the mime type.");
0592: }
0593: if (contentType == null) {
0594: contentType = "application/octet-stream";
0595: }
0596: descriptor.setContentType(contentType);
0597: descriptor.setLastModified(new Date());
0598: descriptor.setOwner(m_slideToken.getCredentialsToken()
0599: .getPublicCredentials());
0600: NodeRevisionContent content = new NodeRevisionContent();
0601:
0602: content.setContent(bytes);
0603: try {
0604: m_content.create(m_slideToken, m_uri, descriptor,
0605: content);
0606: try {
0607: m_nat.commit();
0608: } catch (Exception cme) {
0609: throw new CascadingIOException(
0610: "Could not commit the transaction", cme);
0611:
0612: }
0613: } catch (SlideException se) {
0614: try {
0615: m_nat.rollback();
0616: } catch (Exception rbe) {
0617: this .logger.warn(
0618: "Could not rollback the transaction.",
0619: rbe);
0620: }
0621: throw new CascadingIOException(
0622: "Could not create source", se);
0623: }
0624:
0625: } catch (Exception e) {
0626: if (e instanceof IOException) {
0627: throw (IOException) e;
0628: }
0629: throw new CascadingIOException(
0630: "Could not create source", e);
0631: } finally {
0632: this .isClosed = true;
0633: }
0634: }
0635:
0636: /**
0637: * Can the data sent to an <code>OutputStream</code> returned by
0638: * {@link SlideSource#getOutputStream()} be cancelled ?
0639: *
0640: * @return true if the stream can be cancelled
0641: */
0642: boolean canCancel() {
0643: return !this .isClosed;
0644: }
0645:
0646: /**
0647: * Cancel the data sent to an <code>OutputStream</code> returned by
0648: * {@link SlideSource#getOutputStream()}.
0649: * <p>
0650: * After cancel, the stream should no more be used.
0651: *
0652: */
0653: void cancel() throws Exception {
0654: if (this .isClosed) {
0655: throw new IllegalStateException(
0656: "Cannot cancel : outputstrem is already closed");
0657: }
0658: this .isClosed = true;
0659: super .close();
0660: }
0661: }
0662:
0663: // ---------------------------------------------------- MoveableSource
0664:
0665: /**
0666: * Move the current source to a specified destination.
0667: *
0668: * @param source
0669: *
0670: * @throws SourceException If an exception occurs during the move.
0671: */
0672: public void moveTo(Source source) throws SourceException {
0673: if (source instanceof SlideSource) {
0674: try {
0675: m_nat.begin();
0676: String destination = m_scope
0677: + ((SlideSource) source).m_path;
0678: m_macro.move(m_slideToken, m_uri, destination);
0679: m_nat.commit();
0680: } catch (Exception se) {
0681: try {
0682: m_nat.rollback();
0683: } catch (Exception rbe) {
0684: getLogger().error(
0685: "Rollback failed for moving source", rbe);
0686: }
0687: throw new SourceException("Could not move source.", se);
0688: }
0689: } else {
0690: SourceUtil.move(this , source);
0691: }
0692: }
0693:
0694: /**
0695: * Copy the current source to a specified destination.
0696: *
0697: * @param source
0698: *
0699: * @throws SourceException If an exception occurs during the copy.
0700: */
0701: public void copyTo(Source source) throws SourceException {
0702: if (source instanceof SlideSource) {
0703: try {
0704: m_nat.begin();
0705: String destination = m_scope
0706: + ((SlideSource) source).m_path;
0707: m_macro.copy(m_slideToken, m_uri, destination);
0708: m_nat.commit();
0709: } catch (Exception se) {
0710: try {
0711: m_nat.rollback();
0712: } catch (Exception rbe) {
0713:
0714: getLogger().error(
0715: "Rollback failed for moving source", rbe);
0716: }
0717: throw new SourceException("Could not move source.", se);
0718: }
0719: } else {
0720: SourceUtil.copy(this , source);
0721: }
0722: }
0723:
0724: // ---------------------------------------------------- InspectableSource
0725:
0726: /**
0727: * Returns a property from a source.
0728: *
0729: * @param namespace Namespace of the property
0730: * @param name Name of the property
0731: *
0732: * @return Property of the source.
0733: *
0734: * @throws SourceException If an exception occurs.
0735: */
0736: public SourceProperty getSourceProperty(String namespace,
0737: String name) throws SourceException {
0738:
0739: if (m_descriptor == null) {
0740: return null;
0741: }
0742:
0743: final String quote = "\"";
0744: NodeProperty property = m_descriptor.getProperty(name,
0745: namespace);
0746:
0747: if (property == null) {
0748: return null;
0749: }
0750:
0751: String pre = "<" + name + " xmlns=" + quote + namespace + quote
0752: + " >";
0753: String post = "</" + name + " >";
0754:
0755: StringReader reader = new StringReader(pre
0756: + property.getValue().toString() + post);
0757: InputSource src = new InputSource(reader);
0758:
0759: DOMParser parser = null;
0760: Document doc = null;
0761:
0762: try {
0763: parser = (DOMParser) this .m_manager.lookup(DOMParser.ROLE);
0764: doc = parser.parseDocument(src);
0765: } catch (Exception e) {
0766: throw new SourceException("Could not parse property", e);
0767: } finally {
0768: this .m_manager.release(parser);
0769: }
0770:
0771: return new SourceProperty(doc.getDocumentElement());
0772: }
0773:
0774: /**
0775: * Sets a property for a source.
0776: *
0777: * @param property Property of the source
0778: *
0779: * @throws SourceException If an exception occurs during this operation
0780: */
0781: public void setSourceProperty(SourceProperty property)
0782: throws SourceException {
0783: try {
0784: m_descriptor.setProperty(property.getName(), property
0785: .getNamespace(), property.getValueAsString());
0786: m_descriptor.setLastModified(new Date());
0787:
0788: m_nat.begin();
0789: m_content.store(m_slideToken, m_uri, m_descriptor, null);
0790: m_nat.commit();
0791: } catch (Exception se) {
0792: try {
0793: m_nat.rollback();
0794: } catch (Exception rbe) {
0795: getLogger()
0796: .error(
0797: "Rollback failed for setting a source property",
0798: rbe);
0799: }
0800: throw new SourceException("Could not set source property",
0801: se);
0802: }
0803: }
0804:
0805: /**
0806: * Returns a enumeration of the properties
0807: *
0808: * @return Enumeration of SourceProperty
0809: *
0810: * @throws SourceException If an exception occurs.
0811: */
0812: public SourceProperty[] getSourceProperties()
0813: throws SourceException {
0814:
0815: if (m_descriptor == null) {
0816: return new SourceProperty[0];
0817: }
0818:
0819: List properties = new ArrayList();
0820: DOMParser parser = null;
0821: String xml = "";
0822:
0823: try {
0824: parser = (DOMParser) m_manager.lookup(DOMParser.ROLE);
0825: final String quote = "\"";
0826: Enumeration e = m_descriptor.enumerateProperties();
0827: while (e.hasMoreElements()) {
0828: NodeProperty property = (NodeProperty) e.nextElement();
0829: String name = property.getName();
0830: String namespace = property.getNamespace();
0831: String pre = "<" + name + " xmlns=" + quote + namespace
0832: + quote + " >";
0833: String post = "</" + name + " >";
0834: xml = pre + property.getValue().toString() + post;
0835:
0836: StringReader reader = new StringReader(xml);
0837: Document doc = parser.parseDocument(new InputSource(
0838: reader));
0839: properties.add(new SourceProperty(doc
0840: .getDocumentElement()));
0841: }
0842: } catch (Exception e) {
0843: throw new SourceException(
0844: "Could not parse property " + xml, e);
0845: } finally {
0846: m_manager.release(parser);
0847: }
0848:
0849: return (SourceProperty[]) properties
0850: .toArray(new SourceProperty[properties.size()]);
0851: }
0852:
0853: /**
0854: * Remove a specified source property.
0855: *
0856: * @param namespace Namespace of the property.
0857: * @param name Name of the property.
0858: *
0859: * @throws SourceException If an exception occurs.
0860: */
0861: public void removeSourceProperty(String namespace, String name)
0862: throws SourceException {
0863: try {
0864: if (m_descriptor != null && !namespace.equals("DAV:")) {
0865: m_descriptor.removeProperty(name, namespace);
0866: m_descriptor.setLastModified(new Date());
0867: m_nat.begin();
0868: m_content
0869: .store(m_slideToken, m_uri, m_descriptor, null);
0870: m_nat.commit();
0871: }
0872: } catch (Exception se) {
0873: try {
0874: m_nat.rollback();
0875: } catch (Exception rbe) {
0876: getLogger()
0877: .error(
0878: "Rollback failed for removing a source property",
0879: rbe);
0880: }
0881: throw new SourceException("Could not remove property", se);
0882: }
0883: }
0884:
0885: // ---------------------------------------------------- LockableSource
0886:
0887: /**
0888: * Add a lock to this source
0889: *
0890: * @param sourcelock Lock, which should be added
0891: *
0892: * @throws SourceException If an exception occurs during this operation
0893: */
0894: public void addSourceLocks(SourceLock sourcelock)
0895: throws SourceException {
0896: throw new SourceException("Operation not yet supported");
0897: }
0898:
0899: /**
0900: * Returns a enumeration of the existing locks
0901: *
0902: * @return Enumeration of SourceLock
0903: *
0904: * @throws SourceException If an exception occurs.
0905: */
0906: public SourceLock[] getSourceLocks() throws SourceException {
0907: try {
0908: List result = new ArrayList();
0909:
0910: NodeLock lock;
0911: Enumeration locks = m_lock.enumerateLocks(m_slideToken,
0912: m_uri, false);
0913: while (locks.hasMoreElements()) {
0914: lock = (NodeLock) locks.nextElement();
0915: result.add(new SourceLock(lock.getSubjectUri(), lock
0916: .getTypeUri(), lock.getExpirationDate(), lock
0917: .isInheritable(), lock.isExclusive()));
0918: }
0919:
0920: return (SourceLock[]) result.toArray(new SourceLock[result
0921: .size()]);
0922: } catch (SlideException se) {
0923: throw new SourceException("Could not retrieve locks", se);
0924: }
0925: }
0926:
0927: // ---------------------------------------------------- VersionableSource
0928:
0929: /**
0930: * If this source versioned
0931: *
0932: * @return True if the current source is versioned.
0933: *
0934: * @throws SourceException If an exception occurs.
0935: */
0936: public boolean isVersioned() throws SourceException {
0937: if (m_descriptors != null) {
0938: return m_descriptors.hasRevisions();
0939: }
0940: return false;
0941: }
0942:
0943: /**
0944: * Get the current revision of the source
0945: *
0946: * @return The current revision of the source
0947: *
0948: */
0949: public String getSourceRevision() {
0950: if (m_version != null) {
0951: return m_version.toString();
0952: }
0953: return null;
0954: }
0955:
0956: /**
0957: * Not implemented.
0958: *
0959: * @param revision The revision, which should be used.
0960: *
0961: * @throws SourceException If an exception occurs.
0962: */
0963: public void setSourceRevision(String revision)
0964: throws SourceException {
0965: // [UH] this method is wrong. different versions should be obtained
0966: // by creating a new source
0967: throw new SourceException("method not implemented");
0968: }
0969:
0970: /**
0971: * Get the current branch of the revision from the source
0972: *
0973: * @return The branch of the revision
0974: *
0975: * @throws SourceException If an exception occurs.
0976: */
0977: public String getSourceRevisionBranch() throws SourceException {
0978: if (m_descriptor != null) {
0979: return m_descriptor.getBranchName();
0980: }
0981: return null;
0982: }
0983:
0984: /**
0985: * Not implemented.
0986: *
0987: * @param branch The branch, which should be used.
0988: *
0989: * @throws SourceException If an exception occurs.
0990: */
0991: public void setSourceRevisionBranch(String branch)
0992: throws SourceException {
0993: // [UH] this method is wrong. different versions should be obtained
0994: // by creating a new source
0995: throw new SourceException("method not implemented");
0996: }
0997:
0998: /**
0999: * Get the latest revision
1000: *
1001: * @return Last revision of the source.
1002: *
1003: * @throws SourceException If an exception occurs.
1004: */
1005: public String getLatestSourceRevision() throws SourceException {
1006: if (m_descriptors != null) {
1007: return m_descriptors.getLatestRevision().toString();
1008: }
1009: return null;
1010: }
1011:
1012: }
|