This project has retired. For details please refer to its Attic page.
JcrDocument xref

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.chemistry.opencmis.jcr;
21  
22  import org.apache.chemistry.opencmis.commons.PropertyIds;
23  import org.apache.chemistry.opencmis.commons.data.ContentStream;
24  import org.apache.chemistry.opencmis.commons.enums.Action;
25  import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
26  import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException;
27  import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
28  import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
29  import org.apache.chemistry.opencmis.commons.exceptions.CmisStorageException;
30  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
31  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl;
32  import org.apache.chemistry.opencmis.commons.impl.server.ObjectInfoImpl;
33  import org.apache.chemistry.opencmis.jcr.type.JcrTypeHandlerManager;
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  
37  import javax.jcr.Binary;
38  import javax.jcr.Node;
39  import javax.jcr.PathNotFoundException;
40  import javax.jcr.Property;
41  import javax.jcr.RepositoryException;
42  import java.io.BufferedInputStream;
43  import java.io.IOException;
44  import java.math.BigInteger;
45  import java.util.Set;
46  
47  /**
48   * Instances of this class represent a cmis:document backed by an underlying JCR <code>Node</code>.
49   */
50  public abstract class JcrDocument extends JcrNode {
51      private static final Log log = LogFactory.getLog(JcrDocument.class);
52  
53      public static final String MIME_UNKNOWN = "application/octet-stream";
54  
55      protected JcrDocument(Node node, JcrTypeManager typeManager, PathManager pathManager, JcrTypeHandlerManager typeHandlerManager) {
56          super(node, typeManager, pathManager, typeHandlerManager);
57      }
58  
59      /**
60       * @return  <code>true</code> iff the document is checked out
61       */
62      public boolean isDocumentCheckedOut() {
63          try {
64              return getNode().isCheckedOut();
65          }
66          catch (RepositoryException e) {
67              log.debug(e.getMessage(), e);
68              throw new CmisRuntimeException(e.getMessage(), e);
69          }
70      }
71  
72      /**
73       * See CMIS 1.0 section 2.2.4.10 getContentStream
74       *
75       * @throws CmisObjectNotFoundException
76       * @throws CmisRuntimeException
77       */
78      public ContentStream getContentStream() {
79          try {
80              Node contentNode = getContextNode();
81              Property data = contentNode.getProperty(Property.JCR_DATA);
82  
83              // compile data
84              ContentStreamImpl result = new ContentStreamImpl();
85              result.setFileName(getNodeName());
86              result.setLength(BigInteger.valueOf(data.getLength()));
87              result.setMimeType(getPropertyOrElse(contentNode, Property.JCR_MIMETYPE, MIME_UNKNOWN));
88              result.setStream(new BufferedInputStream(data.getBinary().getStream()));  // stream closed by consumer
89  
90              return result;
91          }
92          catch (PathNotFoundException e) {
93              log.debug(e.getMessage(), e);
94              throw new CmisObjectNotFoundException(e.getMessage(), e);
95          }
96          catch (RepositoryException e) {
97              log.debug(e.getMessage(), e);
98              throw new CmisRuntimeException(e.getMessage(), e);
99          }
100     }
101 
102     /**
103      * See CMIS 1.0 section 2.2.4.16 setContentStream
104      *
105      * @throws CmisStorageException
106      */
107     public JcrNode setContentStream(ContentStream contentStream, boolean overwriteFlag) {
108         try {
109             // get content node. For version series this is *not* the same as the
110             // context node. See CMIS-438.
111             Node contentNode = getNode().getNode(Node.JCR_CONTENT);
112             Property data = contentNode.getProperty(Property.JCR_DATA);
113 
114             // check overwrite
115             if (!overwriteFlag && data.getLength() != 0) {
116                 throw new CmisContentAlreadyExistsException("Content already exists!");
117             }
118 
119             JcrVersionBase jcrVersion = isVersionable()
120                     ? asVersion()
121                     : null;
122 
123             boolean autoCheckout = jcrVersion != null && !jcrVersion.isCheckedOut();
124             if (autoCheckout) {
125                 jcrVersion.checkout();
126             }
127 
128             // write content, if available
129             Binary binary = contentStream == null || contentStream.getStream() == null
130                     ? JcrBinary.EMPTY
131                     : new JcrBinary(new BufferedInputStream(contentStream.getStream()));
132             try {
133                 contentNode.setProperty(Property.JCR_DATA, binary);
134                 if (contentStream != null && contentStream.getMimeType() != null) {
135                     contentNode.setProperty(Property.JCR_MIMETYPE, contentStream.getMimeType());
136                 }
137             }
138             finally {
139                 binary.dispose();
140             }
141 
142             contentNode.getSession().save();
143 
144             if (autoCheckout) {
145                 // auto versioning -> return new version created by checkin
146                 return jcrVersion.checkin(null, null, "auto checkout");
147             }
148             else if (jcrVersion != null) {
149                 // the node is checked out -> return pwc.
150                 return jcrVersion.getPwc();
151             }
152             else {
153                 // non versionable -> return this
154                 return this;
155             }
156         }
157         catch (RepositoryException e) {
158             log.debug(e.getMessage(), e);
159             throw new CmisStorageException(e.getMessage(), e);
160         }
161         catch (IOException e) {
162             log.debug(e.getMessage(), e);
163             throw new CmisStorageException(e.getMessage(), e);
164         }
165 
166     }
167 
168     //------------------------------------------< protected >---
169 
170     /**
171      * @return  the value of the <code>cmis:isLatestVersion</code> property
172      * @throws RepositoryException
173      */
174     protected abstract boolean isLatestVersion() throws RepositoryException;
175 
176     /**
177      * @return  the value of the <code>cmis:isMajorVersion</code> property
178      * @throws RepositoryException
179      */
180     protected abstract boolean isMajorVersion() throws RepositoryException;
181 
182     /**
183      * @return  the value of the <code>cmis:isLatestMajorVersion</code> property
184      * @throws RepositoryException
185      */
186     protected abstract boolean isLatestMajorVersion() throws RepositoryException;
187 
188     /**
189      * @return  the value of the <code>cmis:versionLabel</code> property
190      * @throws RepositoryException
191      */
192     protected abstract String getVersionLabel() throws RepositoryException;
193 
194     /**
195      * @return  the value of the <code>cmis:isVersionSeriesCheckedOut</code> property
196      * @throws RepositoryException
197      */
198     protected abstract boolean isCheckedOut() throws RepositoryException;
199 
200     /**
201      * @return  the value of the <code>cmis:versionSeriesCheckedOutId</code> property
202      * @throws RepositoryException
203      */
204     protected abstract String getCheckedOutId() throws RepositoryException;
205 
206     /**
207      * @return  the value of the <code>cmis:versionSeriesCheckedOutBy</code> property
208      * @throws RepositoryException
209      */
210     protected abstract String getCheckedOutBy() throws RepositoryException;
211 
212 
213     /**
214      * @return  the value of the <code>cmis:checkinComment</code> property
215      * @throws RepositoryException
216      */
217     protected abstract String getCheckInComment() throws RepositoryException;
218 
219     protected boolean getIsImmutable() {
220         return false;
221     }
222 
223     @Override
224     protected void compileProperties(PropertiesImpl properties, Set<String> filter, ObjectInfoImpl objectInfo)
225             throws RepositoryException {
226 
227         super.compileProperties(properties, filter, objectInfo);
228 
229         objectInfo.setHasContent(true);
230         objectInfo.setHasParent(true);
231         objectInfo.setSupportsDescendants(false);
232         objectInfo.setSupportsFolderTree(false);
233 
234         String typeId = getTypeIdInternal();
235         Node contextNode = getContextNode();
236 
237         // mutability
238         addPropertyBoolean(properties, typeId, filter, PropertyIds.IS_IMMUTABLE, getIsImmutable());
239 
240         // content stream
241         long length = getPropertyLength(contextNode, Property.JCR_DATA);
242         addPropertyInteger(properties, typeId, filter, PropertyIds.CONTENT_STREAM_LENGTH, length);
243 
244         // mime type
245         String mimeType = getPropertyOrElse(contextNode, Property.JCR_MIMETYPE, MIME_UNKNOWN);
246         addPropertyString(properties, typeId, filter, PropertyIds.CONTENT_STREAM_MIME_TYPE, mimeType);
247         objectInfo.setContentType(mimeType);
248 
249         // file name
250         String fileName = getNodeName();
251         addPropertyString(properties, typeId, filter, PropertyIds.CONTENT_STREAM_FILE_NAME, fileName);
252         objectInfo.setFileName(fileName);
253 
254         addPropertyId(properties, typeId, filter, PropertyIds.CONTENT_STREAM_ID, getObjectId() + "/stream");
255 
256         // versioning
257         addPropertyBoolean(properties, typeId, filter, PropertyIds.IS_LATEST_VERSION, isLatestVersion());
258         addPropertyBoolean(properties, typeId, filter, PropertyIds.IS_MAJOR_VERSION, isMajorVersion());
259         addPropertyBoolean(properties, typeId, filter, PropertyIds.IS_LATEST_MAJOR_VERSION, isLatestMajorVersion());
260         addPropertyString(properties, typeId, filter, PropertyIds.VERSION_LABEL, getVersionLabel());
261         addPropertyId(properties, typeId, filter, PropertyIds.VERSION_SERIES_ID, getVersionSeriesId());
262         addPropertyString(properties, typeId, filter, PropertyIds.CHECKIN_COMMENT, getCheckInComment());
263 
264         boolean isCheckedOut = isCheckedOut();
265         addPropertyBoolean(properties, typeId, filter, PropertyIds.IS_VERSION_SERIES_CHECKED_OUT, isCheckedOut);
266 
267         if (isCheckedOut) {
268             addPropertyId(properties, typeId, filter, PropertyIds.VERSION_SERIES_CHECKED_OUT_ID, getCheckedOutId());
269             addPropertyString(properties, typeId, filter, PropertyIds.VERSION_SERIES_CHECKED_OUT_BY, getCheckedOutBy());
270         }
271     }
272 
273     @Override
274     protected Set<Action> compileAllowableActions(Set<Action> aas) {
275         Set<Action> result = super.compileAllowableActions(aas);
276         setAction(result, Action.CAN_GET_CONTENT_STREAM, true);
277         setAction(result, Action.CAN_SET_CONTENT_STREAM, true);
278         setAction(result, Action.CAN_DELETE_CONTENT_STREAM, true);
279         setAction(result, Action.CAN_GET_RENDITIONS, false);
280         return result;
281     }
282 
283     @Override
284     protected BaseTypeId getBaseTypeId() {
285         return BaseTypeId.CMIS_DOCUMENT;
286     }
287 
288 }