This project has retired. For details please refer to its Attic page.
AbstractCmisObject 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.runtime;
20  
21  import java.io.Serializable;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.GregorianCalendar;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  import java.util.concurrent.locks.ReentrantReadWriteLock;
31  
32  import org.apache.chemistry.opencmis.client.api.CmisObject;
33  import org.apache.chemistry.opencmis.client.api.ObjectFactory;
34  import org.apache.chemistry.opencmis.client.api.ObjectId;
35  import org.apache.chemistry.opencmis.client.api.ObjectType;
36  import org.apache.chemistry.opencmis.client.api.OperationContext;
37  import org.apache.chemistry.opencmis.client.api.Policy;
38  import org.apache.chemistry.opencmis.client.api.Property;
39  import org.apache.chemistry.opencmis.client.api.Relationship;
40  import org.apache.chemistry.opencmis.client.api.Rendition;
41  import org.apache.chemistry.opencmis.client.api.TransientCmisObject;
42  import org.apache.chemistry.opencmis.commons.PropertyIds;
43  import org.apache.chemistry.opencmis.commons.data.Ace;
44  import org.apache.chemistry.opencmis.commons.data.Acl;
45  import org.apache.chemistry.opencmis.commons.data.AllowableActions;
46  import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement;
47  import org.apache.chemistry.opencmis.commons.data.ObjectData;
48  import org.apache.chemistry.opencmis.commons.data.RenditionData;
49  import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
50  import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
51  import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
52  import org.apache.chemistry.opencmis.commons.enums.ExtensionLevel;
53  import org.apache.chemistry.opencmis.commons.enums.Updatability;
54  import org.apache.chemistry.opencmis.commons.spi.CmisBinding;
55  import org.apache.chemistry.opencmis.commons.spi.Holder;
56  
57  /**
58   * Base class for all persistent session object impl classes.
59   */
60  public abstract class AbstractCmisObject implements CmisObject, Serializable {
61  
62      private static final long serialVersionUID = 1L;
63  
64      private SessionImpl session;
65      private ObjectType objectType;
66      private Map<String, Property<?>> properties;
67      private AllowableActions allowableActions;
68      private List<Rendition> renditions;
69      private Acl acl;
70      private List<Policy> policies;
71      private List<Relationship> relationships;
72      private Map<ExtensionLevel, List<CmisExtensionElement>> extensions;
73      private OperationContext creationContext;
74      private long refreshTimestamp;
75  
76      private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
77  
78      /**
79       * Initializes the object.
80       */
81      protected void initialize(SessionImpl session, ObjectType objectType, ObjectData objectData,
82              OperationContext context) {
83          if (session == null) {
84              throw new IllegalArgumentException("Session must be set!");
85          }
86  
87          if (objectType == null) {
88              throw new IllegalArgumentException("Object type must be set!");
89          }
90  
91          if ((objectType.getPropertyDefinitions() == null) || objectType.getPropertyDefinitions().size() < 9) {
92              // there must be at least the 9 standard properties that all objects
93              // have
94              throw new IllegalArgumentException("Object type must have property definitions!");
95          }
96  
97          this.session = session;
98          this.objectType = objectType;
99          this.extensions = new HashMap<ExtensionLevel, List<CmisExtensionElement>>();
100         this.creationContext = new OperationContextImpl(context);
101         this.refreshTimestamp = System.currentTimeMillis();
102 
103         ObjectFactory of = getObjectFactory();
104 
105         if (objectData != null) {
106             // handle properties
107             if (objectData.getProperties() != null) {
108                 this.properties = of.convertProperties(objectType, objectData.getProperties());
109                 extensions.put(ExtensionLevel.PROPERTIES, objectData.getProperties().getExtensions());
110             }
111 
112             // handle allowable actions
113             if (objectData.getAllowableActions() != null) {
114                 this.allowableActions = objectData.getAllowableActions();
115                 extensions.put(ExtensionLevel.ALLOWABLE_ACTIONS, objectData.getAllowableActions().getExtensions());
116             }
117 
118             // handle renditions
119             if (objectData.getRenditions() != null) {
120                 this.renditions = new ArrayList<Rendition>();
121                 for (RenditionData rd : objectData.getRenditions()) {
122                     this.renditions.add(of.convertRendition(getId(), rd));
123                 }
124             }
125 
126             // handle ACL
127             if (objectData.getAcl() != null) {
128                 acl = objectData.getAcl();
129                 extensions.put(ExtensionLevel.ACL, objectData.getAcl().getExtensions());
130             }
131 
132             // handle policies
133             if ((objectData.getPolicyIds() != null) && (objectData.getPolicyIds().getPolicyIds() != null)) {
134                 policies = new ArrayList<Policy>();
135                 for (String pid : objectData.getPolicyIds().getPolicyIds()) {
136                     CmisObject policy = session.getObject(getSession().createObjectId(pid));
137                     if (policy instanceof Policy) {
138                         policies.add((Policy) policy);
139                     }
140                 }
141                 extensions.put(ExtensionLevel.POLICIES, objectData.getPolicyIds().getExtensions());
142             }
143 
144             // handle relationships
145             if (objectData.getRelationships() != null) {
146                 relationships = new ArrayList<Relationship>();
147                 for (ObjectData rod : objectData.getRelationships()) {
148                     CmisObject relationship = of.convertObject(rod, this.creationContext);
149                     if (relationship instanceof Relationship) {
150                         relationships.add((Relationship) relationship);
151                     }
152                 }
153             }
154 
155             extensions.put(ExtensionLevel.OBJECT, objectData.getExtensions());
156         }
157     }
158 
159     /**
160      * Acquires a write lock.
161      */
162     protected void writeLock() {
163         lock.writeLock().lock();
164     }
165 
166     /**
167      * Releases a write lock.
168      */
169     protected void writeUnlock() {
170         lock.writeLock().unlock();
171     }
172 
173     /**
174      * Acquires a read lock.
175      */
176     protected void readLock() {
177         lock.readLock().lock();
178     }
179 
180     /**
181      * Releases a read lock.
182      */
183     protected void readUnlock() {
184         lock.readLock().unlock();
185     }
186 
187     /**
188      * Returns the session object.
189      */
190     protected SessionImpl getSession() {
191         return this.session;
192     }
193 
194     /**
195      * Returns the repository id.
196      */
197     protected String getRepositoryId() {
198         return getSession().getRepositoryId();
199     }
200 
201     /**
202      * Returns the object type.
203      */
204     protected ObjectType getObjectType() {
205         readLock();
206         try {
207             return this.objectType;
208         } finally {
209             readUnlock();
210         }
211     }
212 
213     /**
214      * Returns the binding object.
215      */
216     protected CmisBinding getBinding() {
217         return getSession().getBinding();
218     }
219 
220     /**
221      * Returns the object factory.
222      */
223     protected ObjectFactory getObjectFactory() {
224         return getSession().getObjectFactory();
225     }
226 
227     /**
228      * Returns the id of this object or throws an exception if the id is
229      * unknown.
230      */
231     protected String getObjectId() {
232         String objectId = getId();
233         if (objectId == null) {
234             throw new IllegalStateException("Object Id is unknown!");
235         }
236 
237         return objectId;
238     }
239 
240     /**
241      * Returns the {@link OperationContext} that was used to create this object.
242      */
243     protected OperationContext getCreationContext() {
244         return creationContext;
245     }
246 
247     /**
248      * Returns the query name of a property.
249      */
250     protected String getPropertyQueryName(String propertyId) {
251         readLock();
252         try {
253             PropertyDefinition<?> propDef = objectType.getPropertyDefinitions().get(propertyId);
254             if (propDef == null) {
255                 return null;
256             }
257 
258             return propDef.getQueryName();
259         } finally {
260             readUnlock();
261         }
262     }
263 
264     // --- properties ---
265 
266     public void delete(boolean allVersions) {
267         readLock();
268         try {
269             String objectId = getObjectId();
270             getBinding().getObjectService().deleteObject(getRepositoryId(), objectId, allVersions, null);
271             getSession().removeObjectFromCache(this);
272         } finally {
273             readUnlock();
274         }
275     }
276 
277     public CmisObject updateProperties(Map<String, ?> properties) {
278         ObjectId objectId = updateProperties(properties, true);
279         if (objectId == null) {
280             return null;
281         }
282 
283         if (!getObjectId().equals(objectId.getId())) {
284             return getSession().getObject(objectId, getCreationContext());
285         }
286 
287         return this;
288     }
289 
290     public ObjectId updateProperties(Map<String, ?> properties, boolean refresh) {
291         if (properties == null || properties.isEmpty()) {
292             throw new IllegalArgumentException("Properties must not be empty!");
293         }
294 
295         readLock();
296         String newObjectId = null;
297         try {
298             String objectId = getObjectId();
299             Holder<String> objectIdHolder = new Holder<String>(objectId);
300 
301             String changeToken = getChangeToken();
302             Holder<String> changeTokenHolder = new Holder<String>(changeToken);
303 
304             Set<Updatability> updatebility = new HashSet<Updatability>();
305             updatebility.add(Updatability.READWRITE);
306 
307             // check if checked out
308             Boolean isCheckedOut = getPropertyValue(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT);
309             if ((isCheckedOut != null) && isCheckedOut.booleanValue()) {
310                 updatebility.add(Updatability.WHENCHECKEDOUT);
311             }
312 
313             // it's time to update
314             getBinding().getObjectService().updateProperties(getRepositoryId(), objectIdHolder, changeTokenHolder,
315                     getObjectFactory().convertProperties(properties, this.objectType, updatebility), null);
316 
317             newObjectId = objectIdHolder.getValue();
318         } finally {
319             readUnlock();
320         }
321 
322         if (refresh) {
323             refresh();
324         }
325 
326         if (newObjectId == null) {
327             return null;
328         }
329 
330         return getSession().createObjectId(newObjectId);
331     }
332 
333     // --- properties ---
334 
335     public ObjectType getBaseType() {
336         BaseTypeId baseTypeId = getBaseTypeId();
337         if (baseTypeId == null) {
338             return null;
339         }
340 
341         return getSession().getTypeDefinition(baseTypeId.value());
342     }
343 
344     public BaseTypeId getBaseTypeId() {
345         String baseType = getPropertyValue(PropertyIds.BASE_TYPE_ID);
346         if (baseType == null) {
347             return null;
348         }
349 
350         return BaseTypeId.fromValue(baseType);
351     }
352 
353     public String getChangeToken() {
354         return getPropertyValue(PropertyIds.CHANGE_TOKEN);
355     }
356 
357     public String getCreatedBy() {
358         return getPropertyValue(PropertyIds.CREATED_BY);
359     }
360 
361     public GregorianCalendar getCreationDate() {
362         return getPropertyValue(PropertyIds.CREATION_DATE);
363     }
364 
365     public String getId() {
366         return getPropertyValue(PropertyIds.OBJECT_ID);
367     }
368 
369     public GregorianCalendar getLastModificationDate() {
370         return getPropertyValue(PropertyIds.LAST_MODIFICATION_DATE);
371     }
372 
373     public String getLastModifiedBy() {
374         return getPropertyValue(PropertyIds.LAST_MODIFIED_BY);
375     }
376 
377     public String getName() {
378         return getPropertyValue(PropertyIds.NAME);
379     }
380 
381     public List<Property<?>> getProperties() {
382         readLock();
383         try {
384             return Collections.unmodifiableList(new ArrayList<Property<?>>(this.properties.values()));
385         } finally {
386             readUnlock();
387         }
388     }
389 
390     @SuppressWarnings("unchecked")
391     public <T> Property<T> getProperty(String id) {
392         readLock();
393         try {
394             return (Property<T>) this.properties.get(id);
395         } finally {
396             readUnlock();
397         }
398     }
399 
400     @SuppressWarnings("unchecked")
401     public <T> T getPropertyValue(String id) {
402         Property<T> property = getProperty(id);
403         if (property == null) {
404             return null;
405         }
406         // explicit cast needed by the Sun compiler
407         return (T) property.getValue();
408     }
409 
410     public ObjectType getType() {
411         readLock();
412         try {
413             return this.objectType;
414         } finally {
415             readUnlock();
416         }
417     }
418 
419     // --- allowable actions ---
420 
421     public AllowableActions getAllowableActions() {
422         readLock();
423         try {
424             return this.allowableActions;
425         } finally {
426             readUnlock();
427         }
428     }
429 
430     // --- renditions ---
431 
432     public List<Rendition> getRenditions() {
433         readLock();
434         try {
435             return this.renditions;
436         } finally {
437             readUnlock();
438         }
439     }
440 
441     // --- ACL ---
442 
443     public Acl getAcl(boolean onlyBasicPermissions) {
444         String objectId = getObjectId();
445         return getBinding().getAclService().getAcl(getRepositoryId(), objectId, onlyBasicPermissions, null);
446     }
447 
448     public Acl applyAcl(List<Ace> addAces, List<Ace> removeAces, AclPropagation aclPropagation) {
449         Acl result = getSession().applyAcl(this, addAces, removeAces, aclPropagation);
450 
451         refresh();
452 
453         return result;
454     }
455 
456     public Acl addAcl(List<Ace> addAces, AclPropagation aclPropagation) {
457         return applyAcl(addAces, null, aclPropagation);
458     }
459 
460     public Acl removeAcl(List<Ace> removeAces, AclPropagation aclPropagation) {
461         return applyAcl(null, removeAces, aclPropagation);
462     }
463 
464     public Acl getAcl() {
465         readLock();
466         try {
467             return this.acl;
468         } finally {
469             readUnlock();
470         }
471     }
472 
473     // --- policies ---
474 
475     public void applyPolicy(ObjectId... policyIds) {
476         readLock();
477         try {
478             getSession().applyPolicy(this, policyIds);
479         } finally {
480             readUnlock();
481         }
482 
483         refresh();
484     }
485 
486     public void removePolicy(ObjectId... policyIds) {
487         readLock();
488         try {
489             getSession().removePolicy(this, policyIds);
490         } finally {
491             readUnlock();
492         }
493 
494         refresh();
495     }
496 
497     public List<Policy> getPolicies() {
498         readLock();
499         try {
500             return this.policies;
501         } finally {
502             readUnlock();
503         }
504     }
505 
506     // --- relationships ---
507 
508     public List<Relationship> getRelationships() {
509         readLock();
510         try {
511             return this.relationships;
512         } finally {
513             readUnlock();
514         }
515     }
516 
517     // --- extensions ---
518 
519     public List<CmisExtensionElement> getExtensions(ExtensionLevel level) {
520         List<CmisExtensionElement> ext = extensions.get(level);
521         if (ext == null) {
522             return null;
523         }
524 
525         return Collections.unmodifiableList(ext);
526     }
527 
528     // --- adapters ---
529 
530     @SuppressWarnings("unchecked")
531     public <T> T getAdapter(Class<T> adapterInterface) {
532         if (adapterInterface == null) {
533             return null;
534         }
535         if (adapterInterface.equals(TransientCmisObject.class)) {
536             return (T) createTransientCmisObject();
537         }
538         return null;
539     }
540 
541     public TransientCmisObject getTransientObject() {
542         return getAdapter(TransientCmisObject.class);
543     }
544 
545     protected TransientCmisObject createTransientCmisObject() {
546         return null;
547     }
548 
549     // --- other ---
550 
551     public long getRefreshTimestamp() {
552         readLock();
553         try {
554             return this.refreshTimestamp;
555         } finally {
556             readUnlock();
557         }
558     }
559 
560     public void refresh() {
561         writeLock();
562         try {
563             String objectId = getObjectId();
564 
565             OperationContext oc = getCreationContext();
566 
567             // get the latest data from the repository
568             ObjectData objectData = getSession()
569                     .getBinding()
570                     .getObjectService()
571                     .getObject(getRepositoryId(), objectId, oc.getFilterString(), oc.isIncludeAllowableActions(),
572                             oc.getIncludeRelationships(), oc.getRenditionFilterString(), oc.isIncludePolicies(),
573                             oc.isIncludeAcls(), null);
574 
575             // reset this object
576             initialize(getSession(), getObjectType(), objectData, this.creationContext);
577         } finally {
578             writeUnlock();
579         }
580     }
581 
582     public void refreshIfOld(long durationInMillis) {
583         writeLock();
584         try {
585             if (this.refreshTimestamp < System.currentTimeMillis() - durationInMillis) {
586                 refresh();
587             }
588         } finally {
589             writeUnlock();
590         }
591     }
592 }