This project has retired. For details please refer to its Attic page.
VersioningServiceImpl 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  package org.apache.chemistry.opencmis.client.bindings.spi.atompub;
20  
21  import static org.apache.chemistry.opencmis.commons.impl.Converter.convert;
22  import static org.apache.chemistry.opencmis.commons.impl.Converter.convertPolicyIds;
23  
24  import java.io.InputStream;
25  import java.io.OutputStream;
26  import java.util.ArrayList;
27  import java.util.List;
28  
29  import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession;
30  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
31  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
32  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed;
33  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
34  import org.apache.chemistry.opencmis.client.bindings.spi.http.HttpUtils;
35  import org.apache.chemistry.opencmis.commons.data.Acl;
36  import org.apache.chemistry.opencmis.commons.data.ContentStream;
37  import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
38  import org.apache.chemistry.opencmis.commons.data.ObjectData;
39  import org.apache.chemistry.opencmis.commons.data.Properties;
40  import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
41  import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
42  import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
43  import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
44  import org.apache.chemistry.opencmis.commons.impl.Constants;
45  import org.apache.chemistry.opencmis.commons.impl.ReturnVersion;
46  import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
47  import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisObjectType;
48  import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisPropertiesType;
49  import org.apache.chemistry.opencmis.commons.spi.Holder;
50  import org.apache.chemistry.opencmis.commons.spi.VersioningService;
51  
52  /**
53   * Versioning Service AtomPub client.
54   */
55  public class VersioningServiceImpl extends AbstractAtomPubService implements VersioningService {
56  
57      /**
58       * Constructor.
59       */
60      public VersioningServiceImpl(BindingSession session) {
61          setSession(session);
62      }
63  
64      public void checkOut(String repositoryId, Holder<String> objectId, ExtensionsData extension,
65              Holder<Boolean> contentCopied) {
66          if ((objectId == null) || (objectId.getValue() == null) || (objectId.getValue().length() == 0)) {
67              throw new CmisInvalidArgumentException("Object id must be set!");
68          }
69  
70          // find the link
71          String link = loadCollection(repositoryId, Constants.COLLECTION_CHECKEDOUT);
72  
73          if (link == null) {
74              throw new CmisObjectNotFoundException("Unknown repository or checkedout collection not supported!");
75          }
76  
77          UrlBuilder url = new UrlBuilder(link);
78  
79          // set up object and writer
80          final AtomEntryWriter entryWriter = new AtomEntryWriter(createIdObject(objectId.getValue()));
81  
82          // post move request
83          HttpUtils.Response resp = post(url, Constants.MEDIATYPE_ENTRY, new HttpUtils.Output() {
84              public void write(OutputStream out) throws Exception {
85                  entryWriter.write(out);
86              }
87          });
88  
89          // parse the response
90          AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
91  
92          objectId.setValue(entry.getId());
93  
94          lockLinks();
95          try {
96              // clean up cache
97              removeLinks(repositoryId, entry.getId());
98  
99              // walk through the entry
100             for (AtomElement element : entry.getElements()) {
101                 if (element.getObject() instanceof AtomLink) {
102                     addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
103                 }
104             }
105         } finally {
106             unlockLinks();
107         }
108 
109         if (contentCopied != null) {
110             contentCopied.setValue(null);
111         }
112     }
113 
114     public void cancelCheckOut(String repositoryId, String objectId, ExtensionsData extension) {
115         // find the link
116         String link = loadLink(repositoryId, objectId, Constants.REL_SELF, Constants.MEDIATYPE_ENTRY);
117 
118         if (link == null) {
119             throwLinkException(repositoryId, objectId, Constants.REL_SELF, Constants.MEDIATYPE_ENTRY);
120         }
121 
122         // prefer working copy link if available
123         // (workaround for non-compliant repositories)
124         String wcLink = getLink(repositoryId, objectId, Constants.REL_WORKINGCOPY, Constants.MEDIATYPE_ENTRY);
125         if (wcLink != null) {
126             link = wcLink;
127         }
128 
129         delete(new UrlBuilder(link));
130     }
131 
132     public void checkIn(String repositoryId, Holder<String> objectId, Boolean major, Properties properties,
133             ContentStream contentStream, String checkinComment, List<String> policies, Acl addAces, Acl removeAces,
134             ExtensionsData extension) {
135         // we need an object id
136         if ((objectId == null) || (objectId.getValue() == null) || (objectId.getValue().length() == 0)) {
137             throw new CmisInvalidArgumentException("Object id must be set!");
138         }
139 
140         // find the link
141         String link = loadLink(repositoryId, objectId.getValue(), Constants.REL_SELF, Constants.MEDIATYPE_ENTRY);
142 
143         if (link == null) {
144             throwLinkException(repositoryId, objectId.getValue(), Constants.REL_SELF, Constants.MEDIATYPE_ENTRY);
145         }
146 
147         // prefer working copy link if available
148         // (workaround for non-compliant repositories)
149         String wcLink = getLink(repositoryId, objectId.getValue(), Constants.REL_WORKINGCOPY, Constants.MEDIATYPE_ENTRY);
150         if (wcLink != null) {
151             link = wcLink;
152         }
153 
154         UrlBuilder url = new UrlBuilder(link);
155         url.addParameter(Constants.PARAM_CHECKIN_COMMENT, checkinComment);
156         url.addParameter(Constants.PARAM_MAJOR, major);
157         url.addParameter(Constants.PARAM_CHECK_IN, "true");
158 
159         // set up object and writer
160         CmisObjectType object = new CmisObjectType();
161         object.setProperties(convert(properties));
162         object.setPolicyIds(convertPolicyIds(policies));
163 
164         if (object.getProperties() == null) {
165             object.setProperties(new CmisPropertiesType());
166         }
167 
168         String mediaType = null;
169         InputStream stream = null;
170 
171         if (contentStream != null) {
172             mediaType = contentStream.getMimeType();
173             stream = contentStream.getStream();
174         }
175 
176         final AtomEntryWriter entryWriter = new AtomEntryWriter(object, mediaType, stream);
177 
178         // update
179         HttpUtils.Response resp = put(url, Constants.MEDIATYPE_ENTRY, new HttpUtils.Output() {
180             public void write(OutputStream out) throws Exception {
181                 entryWriter.write(out);
182             }
183         });
184 
185         // parse new entry
186         AtomEntry entry = parse(resp.getStream(), AtomEntry.class);
187 
188         // we expect a CMIS entry
189         if (entry.getId() == null) {
190             throw new CmisConnectionException("Received Atom entry is not a CMIS entry!");
191         }
192 
193         // set object id
194         objectId.setValue(entry.getId());
195 
196         Acl originalAces = null;
197 
198         lockLinks();
199         try {
200             // clean up cache
201             removeLinks(repositoryId, entry.getId());
202 
203             // walk through the entry
204             for (AtomElement element : entry.getElements()) {
205                 if (element.getObject() instanceof AtomLink) {
206                     addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
207                 } else if (element.getObject() instanceof CmisObjectType) {
208                     // extract current ACL
209                     object = (CmisObjectType) element.getObject();
210                     originalAces = convert(object.getAcl(), object.isExactACL());
211                 }
212             }
213         } finally {
214             unlockLinks();
215         }
216 
217         // handle ACL modifications
218         if ((originalAces != null) && (isAclMergeRequired(addAces, removeAces))) {
219             // merge and update ACL
220             Acl newACL = mergeAcls(originalAces, addAces, removeAces);
221             if (newACL != null) {
222                 updateAcl(repositoryId, entry.getId(), newACL, null);
223             }
224         }
225     }
226 
227     public List<ObjectData> getAllVersions(String repositoryId, String objectId, String versionSeriesId, String filter,
228             Boolean includeAllowableActions, ExtensionsData extension) {
229         List<ObjectData> result = new ArrayList<ObjectData>();
230 
231         // find the link
232         String link = loadLink(repositoryId, objectId, Constants.REL_VERSIONHISTORY, Constants.MEDIATYPE_FEED);
233 
234         if (link == null) {
235             throwLinkException(repositoryId, objectId, Constants.REL_VERSIONHISTORY, Constants.MEDIATYPE_FEED);
236         }
237 
238         UrlBuilder url = new UrlBuilder(link);
239         url.addParameter(Constants.PARAM_FILTER, filter);
240         url.addParameter(Constants.PARAM_ALLOWABLE_ACTIONS, includeAllowableActions);
241 
242         // read and parse
243         HttpUtils.Response resp = read(url);
244         AtomFeed feed = parse(resp.getStream(), AtomFeed.class);
245 
246         // get the versions
247         if (!feed.getEntries().isEmpty()) {
248             for (AtomEntry entry : feed.getEntries()) {
249                 ObjectData version = null;
250 
251                 lockLinks();
252                 try {
253                     // clean up cache
254                     removeLinks(repositoryId, entry.getId());
255 
256                     // walk through the entry
257                     for (AtomElement element : entry.getElements()) {
258                         if (element.getObject() instanceof AtomLink) {
259                             addLink(repositoryId, entry.getId(), (AtomLink) element.getObject());
260                         } else if (element.getObject() instanceof CmisObjectType) {
261                             version = convert((CmisObjectType) element.getObject());
262                         }
263                     }
264                 } finally {
265                     unlockLinks();
266                 }
267 
268                 if (version != null) {
269                     result.add(version);
270                 }
271             }
272         }
273 
274         return result;
275     }
276 
277     public ObjectData getObjectOfLatestVersion(String repositoryId, String objectId, String versionSeriesId,
278             Boolean major, String filter, Boolean includeAllowableActions, IncludeRelationships includeRelationships,
279             String renditionFilter, Boolean includePolicyIds, Boolean includeACL, ExtensionsData extension) {
280 
281         ReturnVersion returnVersion = ReturnVersion.LATEST;
282         if ((major != null) && (major.booleanValue())) {
283             returnVersion = ReturnVersion.LASTESTMAJOR;
284         }
285 
286         return getObjectInternal(repositoryId, IdentifierType.ID, objectId, returnVersion, filter,
287                 includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds, includeACL, extension);
288     }
289 
290     public Properties getPropertiesOfLatestVersion(String repositoryId, String objectId, String versionSeriesId,
291             Boolean major, String filter, ExtensionsData extension) {
292 
293         ReturnVersion returnVersion = ReturnVersion.LATEST;
294         if ((major != null) && (major.booleanValue())) {
295             returnVersion = ReturnVersion.LASTESTMAJOR;
296         }
297 
298         ObjectData object = getObjectInternal(repositoryId, IdentifierType.ID, objectId, returnVersion, filter,
299                 Boolean.FALSE, IncludeRelationships.NONE, "cmis:none", Boolean.FALSE, Boolean.FALSE, extension);
300 
301         return object.getProperties();
302     }
303 }