View Javadoc

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 static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNotEmpty;
22  import static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNullOrEmpty;
23  
24  import java.io.Serializable;
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.EnumMap;
28  import java.util.EnumSet;
29  import java.util.GregorianCalendar;
30  import java.util.HashMap;
31  import java.util.HashSet;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.Set;
35  import java.util.concurrent.locks.ReentrantReadWriteLock;
36  
37  import org.apache.chemistry.opencmis.client.api.CmisObject;
38  import org.apache.chemistry.opencmis.client.api.ObjectFactory;
39  import org.apache.chemistry.opencmis.client.api.ObjectId;
40  import org.apache.chemistry.opencmis.client.api.ObjectType;
41  import org.apache.chemistry.opencmis.client.api.OperationContext;
42  import org.apache.chemistry.opencmis.client.api.Policy;
43  import org.apache.chemistry.opencmis.client.api.Property;
44  import org.apache.chemistry.opencmis.client.api.Relationship;
45  import org.apache.chemistry.opencmis.client.api.Rendition;
46  import org.apache.chemistry.opencmis.client.api.SecondaryType;
47  import org.apache.chemistry.opencmis.commons.PropertyIds;
48  import org.apache.chemistry.opencmis.commons.data.Ace;
49  import org.apache.chemistry.opencmis.commons.data.Acl;
50  import org.apache.chemistry.opencmis.commons.data.AllowableActions;
51  import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement;
52  import org.apache.chemistry.opencmis.commons.data.ObjectData;
53  import org.apache.chemistry.opencmis.commons.data.RenditionData;
54  import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
55  import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
56  import org.apache.chemistry.opencmis.commons.enums.Action;
57  import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
58  import org.apache.chemistry.opencmis.commons.enums.ExtensionLevel;
59  import org.apache.chemistry.opencmis.commons.enums.Updatability;
60  import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
61  import org.apache.chemistry.opencmis.commons.spi.CmisBinding;
62  import org.apache.chemistry.opencmis.commons.spi.Holder;
63  
64  /**
65   * Base class for all persistent session object impl classes.
66   */
67  public abstract class AbstractCmisObject implements CmisObject, Serializable {
68  
69      private static final long serialVersionUID = 1L;
70  
71      private SessionImpl session;
72      private ObjectType objectType;
73      private List<SecondaryType> secondaryTypes;
74      private Map<String, Property<?>> properties;
75      private AllowableActions allowableActions;
76      private List<Rendition> renditions;
77      private Acl acl;
78      private List<String> policyIds;
79      private List<Policy> policies;
80      private List<Relationship> relationships;
81      private Map<ExtensionLevel, List<CmisExtensionElement>> extensions;
82      private OperationContext creationContext;
83      private long refreshTimestamp;
84  
85      private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
86  
87      /**
88       * Initializes the object.
89       */
90      protected void initialize(SessionImpl session, ObjectType objectType, ObjectData objectData,
91              OperationContext context) {
92          if (session == null) {
93              throw new IllegalArgumentException("Session must be set!");
94          }
95  
96          if (objectType == null) {
97              throw new IllegalArgumentException("Object type must be set!");
98          }
99  
100         if (objectType.getPropertyDefinitions() == null || objectType.getPropertyDefinitions().size() < 9) {
101             // there must be at least the 9 standard properties that all objects
102             // have
103             throw new IllegalArgumentException("Object type must have property definitions!");
104         }
105 
106         if (objectData == null) {
107             throw new IllegalArgumentException("Object data must be set!");
108         }
109 
110         if (objectData.getProperties() == null) {
111             throw new IllegalArgumentException("Properties must be set!");
112         }
113 
114         if (objectData.getId() == null) {
115             throw new IllegalArgumentException("Object ID must be set!");
116         }
117 
118         this.session = session;
119         this.objectType = objectType;
120         this.secondaryTypes = null;
121         this.extensions = new EnumMap<ExtensionLevel, List<CmisExtensionElement>>(ExtensionLevel.class);
122         this.creationContext = new OperationContextImpl(context);
123         this.refreshTimestamp = System.currentTimeMillis();
124 
125         ObjectFactory of = getObjectFactory();
126 
127         // get secondary types
128         if (objectData.getProperties().getProperties() != null
129                 && objectData.getProperties().getProperties().containsKey(PropertyIds.SECONDARY_OBJECT_TYPE_IDS)) {
130             @SuppressWarnings("unchecked")
131             List<String> stids = (List<String>) objectData.getProperties().getProperties()
132                     .get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getValues();
133             if (isNotEmpty(stids)) {
134                 secondaryTypes = new ArrayList<SecondaryType>(stids.size());
135                 for (String stid : stids) {
136                     if (stid != null) {
137                         ObjectType type = session.getTypeDefinition(stid);
138                         if (type instanceof SecondaryType) {
139                             secondaryTypes.add((SecondaryType) type);
140                         }
141                     }
142                 }
143             } else {
144                 secondaryTypes = null;
145             }
146         }
147 
148         // handle properties
149         this.properties = of.convertProperties(objectType, secondaryTypes, objectData.getProperties());
150         extensions.put(ExtensionLevel.PROPERTIES, objectData.getProperties().getExtensions());
151 
152         // handle allowable actions
153         if (objectData.getAllowableActions() != null) {
154             allowableActions = objectData.getAllowableActions();
155             extensions.put(ExtensionLevel.ALLOWABLE_ACTIONS, objectData.getAllowableActions().getExtensions());
156         } else {
157             allowableActions = null;
158         }
159 
160         // handle renditions
161         if (objectData.getRenditions() != null && !objectData.getRenditions().isEmpty()) {
162             renditions = new ArrayList<Rendition>(objectData.getRenditions().size());
163             for (RenditionData rd : objectData.getRenditions()) {
164                 renditions.add(of.convertRendition(getId(), rd));
165             }
166         } else {
167             renditions = null;
168         }
169 
170         // handle ACL
171         if (objectData.getAcl() != null) {
172             acl = objectData.getAcl();
173             extensions.put(ExtensionLevel.ACL, objectData.getAcl().getExtensions());
174 
175             if (objectData.isExactAcl() != null) {
176                 final Acl objectAcl = objectData.getAcl();
177                 final Boolean isExact = objectData.isExactAcl();
178                 acl = new Acl() {
179 
180                     @Override
181                     public void setExtensions(List<CmisExtensionElement> extensions) {
182                         objectAcl.setExtensions(extensions);
183                     }
184 
185                     @Override
186                     public List<CmisExtensionElement> getExtensions() {
187                         return objectAcl.getExtensions();
188                     }
189 
190                     @Override
191                     public Boolean isExact() {
192                         return isExact;
193                     }
194 
195                     @Override
196                     public List<Ace> getAces() {
197                         return objectAcl.getAces();
198                     }
199                 };
200             }
201         } else {
202             acl = null;
203         }
204 
205         // handle policies
206         policies = null;
207         if (objectData.getPolicyIds() != null && objectData.getPolicyIds().getPolicyIds() != null) {
208             if (objectData.getPolicyIds().getPolicyIds().isEmpty()) {
209                 policyIds = null;
210             } else {
211                 policyIds = objectData.getPolicyIds().getPolicyIds();
212             }
213             extensions.put(ExtensionLevel.POLICIES, objectData.getPolicyIds().getExtensions());
214         } else {
215             policyIds = null;
216         }
217 
218         // handle relationships
219         if (objectData.getRelationships() != null && !objectData.getRelationships().isEmpty()) {
220             relationships = new ArrayList<Relationship>(objectData.getRelationships().size());
221             for (ObjectData rod : objectData.getRelationships()) {
222                 CmisObject relationship = of.convertObject(rod, this.creationContext);
223                 if (relationship instanceof Relationship) {
224                     relationships.add((Relationship) relationship);
225                 }
226             }
227         } else {
228             relationships = null;
229         }
230 
231         extensions.put(ExtensionLevel.OBJECT, objectData.getExtensions());
232     }
233 
234     /**
235      * Acquires a write lock.
236      */
237     protected void writeLock() {
238         lock.writeLock().lock();
239     }
240 
241     /**
242      * Releases a write lock.
243      */
244     protected void writeUnlock() {
245         lock.writeLock().unlock();
246     }
247 
248     /**
249      * Acquires a read lock.
250      */
251     protected void readLock() {
252         lock.readLock().lock();
253     }
254 
255     /**
256      * Releases a read lock.
257      */
258     protected void readUnlock() {
259         lock.readLock().unlock();
260     }
261 
262     /**
263      * Returns the session object.
264      */
265     protected SessionImpl getSession() {
266         return session;
267     }
268 
269     /**
270      * Returns the repository id.
271      */
272     protected String getRepositoryId() {
273         return getSession().getRepositoryId();
274     }
275 
276     /**
277      * Returns the object type.
278      */
279     protected ObjectType getObjectType() {
280         readLock();
281         try {
282             return objectType;
283         } finally {
284             readUnlock();
285         }
286     }
287 
288     /**
289      * Returns the binding object.
290      */
291     protected CmisBinding getBinding() {
292         return getSession().getBinding();
293     }
294 
295     /**
296      * Returns the object factory.
297      */
298     protected ObjectFactory getObjectFactory() {
299         return getSession().getObjectFactory();
300     }
301 
302     /**
303      * Returns the id of this object or throws an exception if the id is
304      * unknown.
305      */
306     protected String getObjectId() {
307         String objectId = getId();
308         if (objectId == null) {
309             throw new IllegalStateException("Object Id is unknown!");
310         }
311 
312         return objectId;
313     }
314 
315     /**
316      * Returns the {@link OperationContext} that was used to create this object.
317      */
318     protected OperationContext getCreationContext() {
319         return creationContext;
320     }
321 
322     /**
323      * Returns the query name of a property.
324      */
325     protected String getPropertyQueryName(String propertyId) {
326         readLock();
327         try {
328             PropertyDefinition<?> propDef = objectType.getPropertyDefinitions().get(propertyId);
329             if (propDef == null) {
330                 return null;
331             }
332 
333             return propDef.getQueryName();
334         } finally {
335             readUnlock();
336         }
337     }
338 
339     // --- delete ---
340 
341     @Override
342     public void delete() {
343         delete(true);
344     }
345 
346     @Override
347     public void delete(boolean allVersions) {
348         readLock();
349         try {
350             getSession().delete(this, allVersions);
351         } finally {
352             readUnlock();
353         }
354     }
355 
356     // --- update properties ---
357 
358     @Override
359     public CmisObject updateProperties(Map<String, ?> properties) {
360         ObjectId objectId = updateProperties(properties, true);
361         if (objectId == null) {
362             return null;
363         }
364 
365         if (!getObjectId().equals(objectId.getId())) {
366             return getSession().getObject(objectId, getCreationContext());
367         }
368 
369         return this;
370     }
371 
372     @Override
373     public ObjectId updateProperties(Map<String, ?> properties, boolean refresh) {
374         if (isNullOrEmpty(properties)) {
375             throw new IllegalArgumentException("Properties must not be empty!");
376         }
377 
378         readLock();
379         String newObjectId = null;
380         try {
381             String objectId = getObjectId();
382             Holder<String> objectIdHolder = new Holder<String>(objectId);
383 
384             String changeToken = getChangeToken();
385             Holder<String> changeTokenHolder = new Holder<String>(changeToken);
386 
387             Set<Updatability> updatebility = EnumSet.noneOf(Updatability.class);
388             updatebility.add(Updatability.READWRITE);
389 
390             // check if checked out
391             Boolean isCheckedOut = getPropertyValue(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT);
392             if (Boolean.TRUE.equals(isCheckedOut)) {
393                 updatebility.add(Updatability.WHENCHECKEDOUT);
394             }
395 
396             // it's time to update
397             getBinding().getObjectService().updateProperties(getRepositoryId(), objectIdHolder, changeTokenHolder,
398                     getObjectFactory().convertProperties(properties, this.objectType, this.secondaryTypes,
399                             updatebility),
400                     null);
401 
402             newObjectId = objectIdHolder.getValue();
403 
404             // remove the object from the cache, it has been changed
405             getSession().removeObjectFromCache(objectId);
406         } finally {
407             readUnlock();
408         }
409 
410         if (refresh) {
411             refresh();
412         }
413 
414         if (newObjectId == null) {
415             return null;
416         }
417 
418         return getSession().createObjectId(newObjectId);
419     }
420 
421     @Override
422     public CmisObject updateProperties(Map<String, ?> properties, List<String> addSecondaryTypeIds,
423             List<String> removeSecondaryTypeIds) {
424         ObjectId objectId = updateProperties(properties, addSecondaryTypeIds, removeSecondaryTypeIds, true);
425         if (objectId == null) {
426             return null;
427         }
428 
429         if (!getObjectId().equals(objectId.getId())) {
430             return getSession().getObject(objectId, getCreationContext());
431         }
432 
433         return this;
434     }
435 
436     @Override
437     public ObjectId updateProperties(Map<String, ?> properties, List<String> addSecondaryTypeIds,
438             List<String> removeSecondaryTypeIds, boolean refresh) {
439         if ((addSecondaryTypeIds == null || addSecondaryTypeIds.isEmpty())
440                 && (removeSecondaryTypeIds == null || removeSecondaryTypeIds.isEmpty())) {
441             return updateProperties(properties, refresh);
442         }
443 
444         List<String> secondaryTypeIds = new ArrayList<String>();
445 
446         readLock();
447         try {
448             // check if secondary types have been fetched
449             if (!this.properties.containsKey(PropertyIds.SECONDARY_OBJECT_TYPE_IDS)) {
450                 throw new IllegalStateException("Secondary Object Type Ids are not available!");
451             }
452 
453             // compile new list of secondary type IDs
454             if (secondaryTypes != null) {
455                 for (SecondaryType type : secondaryTypes) {
456                     if (removeSecondaryTypeIds == null || !removeSecondaryTypeIds.contains(type.getId())) {
457                         secondaryTypeIds.add(type.getId());
458                     }
459                 }
460             }
461 
462             if (addSecondaryTypeIds != null) {
463                 for (String addId : addSecondaryTypeIds) {
464                     if (!secondaryTypeIds.contains(addId)) {
465                         secondaryTypeIds.add(addId);
466                     }
467                 }
468             }
469         } finally {
470             readUnlock();
471         }
472 
473         // set up properties
474         Map<String, Object> newProperties = new HashMap<String, Object>();
475         if (properties != null) {
476             newProperties.putAll(properties);
477         }
478         newProperties.put(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, secondaryTypeIds);
479 
480         return updateProperties(newProperties, refresh);
481     }
482 
483     @Override
484     public CmisObject rename(String newName) {
485         if (newName == null || newName.length() == 0) {
486             throw new IllegalArgumentException("New name must not be empty!");
487         }
488 
489         Map<String, Object> prop = new HashMap<String, Object>(2);
490         prop.put(PropertyIds.NAME, newName);
491 
492         return updateProperties(prop);
493     }
494 
495     @Override
496     public ObjectId rename(String newName, boolean refresh) {
497         if (newName == null || newName.length() == 0) {
498             throw new IllegalArgumentException("New name must not be empty!");
499         }
500 
501         Map<String, Object> prop = new HashMap<String, Object>(2);
502         prop.put(PropertyIds.NAME, newName);
503 
504         return updateProperties(prop, refresh);
505     }
506 
507     // --- properties ---
508 
509     @Override
510     public ObjectType getBaseType() {
511         BaseTypeId baseTypeId = getBaseTypeId();
512         if (baseTypeId == null) {
513             return null;
514         }
515 
516         return getSession().getTypeDefinition(baseTypeId.value());
517     }
518 
519     @Override
520     public BaseTypeId getBaseTypeId() {
521         String baseType = getPropertyValue(PropertyIds.BASE_TYPE_ID);
522         if (baseType == null) {
523             return null;
524         }
525 
526         return BaseTypeId.fromValue(baseType);
527     }
528 
529     @Override
530     public String getChangeToken() {
531         return getPropertyValue(PropertyIds.CHANGE_TOKEN);
532     }
533 
534     @Override
535     public String getCreatedBy() {
536         return getPropertyValue(PropertyIds.CREATED_BY);
537     }
538 
539     @Override
540     public GregorianCalendar getCreationDate() {
541         return getPropertyValue(PropertyIds.CREATION_DATE);
542     }
543 
544     @Override
545     public String getId() {
546         return getPropertyValue(PropertyIds.OBJECT_ID);
547     }
548 
549     @Override
550     public GregorianCalendar getLastModificationDate() {
551         return getPropertyValue(PropertyIds.LAST_MODIFICATION_DATE);
552     }
553 
554     @Override
555     public String getLastModifiedBy() {
556         return getPropertyValue(PropertyIds.LAST_MODIFIED_BY);
557     }
558 
559     @Override
560     public String getName() {
561         return getPropertyValue(PropertyIds.NAME);
562     }
563 
564     @Override
565     public String getDescription() {
566         return getPropertyValue(PropertyIds.DESCRIPTION);
567     }
568 
569     @Override
570     public List<Property<?>> getProperties() {
571         readLock();
572         try {
573             return Collections.unmodifiableList(new ArrayList<Property<?>>(properties.values()));
574         } finally {
575             readUnlock();
576         }
577     }
578 
579     @Override
580     @SuppressWarnings("unchecked")
581     public <T> Property<T> getProperty(String id) {
582         readLock();
583         try {
584             return (Property<T>) properties.get(id);
585         } finally {
586             readUnlock();
587         }
588     }
589 
590     @Override
591     @SuppressWarnings("unchecked")
592     public <T> T getPropertyValue(String id) {
593         Property<T> property = getProperty(id);
594         if (property == null) {
595             return null;
596         }
597         // explicit cast needed by the Sun compiler
598         return (T) property.getValue();
599     }
600 
601     @Override
602     public ObjectType getType() {
603         readLock();
604         try {
605             return objectType;
606         } finally {
607             readUnlock();
608         }
609     }
610 
611     @Override
612     public List<SecondaryType> getSecondaryTypes() {
613         readLock();
614         try {
615             return secondaryTypes;
616         } finally {
617             readUnlock();
618         }
619     }
620 
621     @Override
622     public List<ObjectType> findObjectType(String id) {
623         List<ObjectType> result = null;
624 
625         readLock();
626         try {
627             if (objectType.getPropertyDefinitions().containsKey(id)) {
628                 result = new ArrayList<ObjectType>();
629                 result.add(objectType);
630             }
631 
632             if (secondaryTypes != null) {
633                 for (SecondaryType secondaryType : secondaryTypes) {
634                     if (secondaryType.getPropertyDefinitions() != null
635                             && secondaryType.getPropertyDefinitions().containsKey(id)) {
636                         if (result == null) {
637                             result = new ArrayList<ObjectType>();
638                         }
639                         result.add(secondaryType);
640                     }
641                 }
642             }
643         } finally {
644             readUnlock();
645         }
646 
647         return result;
648     }
649 
650     // --- allowable actions ---
651 
652     @Override
653     public AllowableActions getAllowableActions() {
654         readLock();
655         try {
656             return allowableActions;
657         } finally {
658             readUnlock();
659         }
660     }
661 
662     @Override
663     public boolean hasAllowableAction(Action action) {
664         if (action == null) {
665             throw new IllegalArgumentException("Action must be set!");
666         }
667 
668         AllowableActions currentAllowableActions = getAllowableActions();
669         if (currentAllowableActions == null || currentAllowableActions.getAllowableActions() == null) {
670             throw new IllegalStateException("Allowable Actions are not available!");
671         }
672 
673         return currentAllowableActions.getAllowableActions().contains(action);
674     }
675 
676     // --- renditions ---
677 
678     @Override
679     public List<Rendition> getRenditions() {
680         readLock();
681         try {
682             return renditions;
683         } finally {
684             readUnlock();
685         }
686     }
687 
688     // --- ACL ---
689 
690     public Acl getAcl(boolean onlyBasicPermissions) {
691         String objectId = getObjectId();
692         return getBinding().getAclService().getAcl(getRepositoryId(), objectId, onlyBasicPermissions, null);
693     }
694 
695     @Override
696     public Acl applyAcl(List<Ace> addAces, List<Ace> removeAces, AclPropagation aclPropagation) {
697         Acl result = getSession().applyAcl(this, addAces, removeAces, aclPropagation);
698 
699         refresh();
700 
701         return result;
702     }
703 
704     @Override
705     public Acl addAcl(List<Ace> addAces, AclPropagation aclPropagation) {
706         return applyAcl(addAces, null, aclPropagation);
707     }
708 
709     @Override
710     public Acl removeAcl(List<Ace> removeAces, AclPropagation aclPropagation) {
711         return applyAcl(null, removeAces, aclPropagation);
712     }
713 
714     @Override
715     public Acl setAcl(List<Ace> aces) {
716         Acl result = getSession().setAcl(this, aces);
717 
718         refresh();
719 
720         return result;
721     }
722 
723     @Override
724     public Acl getAcl() {
725         readLock();
726         try {
727             return acl;
728         } finally {
729             readUnlock();
730         }
731     }
732 
733     @Override
734     public Set<String> getPermissionsForPrincipal(String principalId) {
735         if (principalId == null) {
736             throw new IllegalArgumentException("Principal must be set!");
737         }
738 
739         Acl currentAcl = getAcl();
740 
741         if (currentAcl == null) {
742             throw new IllegalStateException("ACLs are not available!");
743         }
744 
745         if (isNullOrEmpty(acl.getAces())) {
746             return Collections.emptySet();
747         }
748 
749         HashSet<String> result = new HashSet<String>();
750 
751         for (Ace ace : acl.getAces()) {
752             if (principalId.equals(ace.getPrincipalId()) && ace.getPermissions() != null) {
753                 result.addAll(ace.getPermissions());
754             }
755         }
756 
757         return result;
758     }
759 
760     // --- policies ---
761 
762     @Override
763     public void applyPolicy(ObjectId... policyIds) {
764         readLock();
765         try {
766             getSession().applyPolicy(this, policyIds);
767         } finally {
768             readUnlock();
769         }
770 
771         refresh();
772     }
773 
774     @Override
775     public void applyPolicy(ObjectId policyId, boolean refresh) {
776         readLock();
777         try {
778             getSession().applyPolicy(this, policyId);
779         } finally {
780             readUnlock();
781         }
782 
783         if (refresh) {
784             refresh();
785         }
786     }
787 
788     @Override
789     public void removePolicy(ObjectId... policyIds) {
790         readLock();
791         try {
792             getSession().removePolicy(this, policyIds);
793         } finally {
794             readUnlock();
795         }
796 
797         refresh();
798     }
799 
800     @Override
801     public void removePolicy(ObjectId policyId, boolean refresh) {
802         readLock();
803         try {
804             getSession().removePolicy(this, policyId);
805         } finally {
806             readUnlock();
807         }
808 
809         if (refresh) {
810             refresh();
811         }
812     }
813 
814     @Override
815     public List<Policy> getPolicies() {
816         readLock();
817         try {
818             if (policies != null || policyIds == null) {
819                 return policies;
820             }
821         } finally {
822             readUnlock();
823         }
824 
825         writeLock();
826         try {
827             if (policies == null) {
828                 policies = new ArrayList<Policy>(policyIds.size());
829                 for (String pid : policyIds) {
830                     try {
831                         CmisObject policy = session.getObject(pid);
832                         if (policy instanceof Policy) {
833                             policies.add((Policy) policy);
834                         }
835                     } catch (CmisObjectNotFoundException nfe) {
836                         // ignore
837                     }
838                 }
839             }
840 
841             return policies;
842         } finally {
843             writeUnlock();
844         }
845     }
846 
847     @Override
848     public List<ObjectId> getPolicyIds() {
849         readLock();
850         try {
851             if (policyIds == null) {
852                 return null;
853             }
854 
855             List<ObjectId> result = new ArrayList<ObjectId>(policyIds.size());
856             for (String pid : policyIds) {
857                 result.add(session.createObjectId(pid));
858             }
859 
860             return result;
861         } finally {
862             readUnlock();
863         }
864     }
865 
866     // --- relationships ---
867 
868     @Override
869     public List<Relationship> getRelationships() {
870         readLock();
871         try {
872             return this.relationships;
873         } finally {
874             readUnlock();
875         }
876     }
877 
878     // --- extensions ---
879 
880     @Override
881     public List<CmisExtensionElement> getExtensions(ExtensionLevel level) {
882         List<CmisExtensionElement> ext = extensions.get(level);
883         if (ext == null) {
884             return null;
885         }
886 
887         return Collections.unmodifiableList(ext);
888     }
889 
890     // --- adapters ---
891 
892     @Override
893     public <T> T getAdapter(Class<T> adapterInterface) {
894         return null;
895     }
896 
897     // --- other ---
898 
899     @Override
900     public long getRefreshTimestamp() {
901         readLock();
902         try {
903             return this.refreshTimestamp;
904         } finally {
905             readUnlock();
906         }
907     }
908 
909     @Override
910     public void refresh() {
911         writeLock();
912         try {
913             String objectId = getObjectId();
914 
915             OperationContext oc = getCreationContext();
916 
917             // get the latest data from the repository
918             ObjectData objectData = getSession().getBinding().getObjectService().getObject(getRepositoryId(), objectId,
919                     oc.getFilterString(), oc.isIncludeAllowableActions(), oc.getIncludeRelationships(),
920                     oc.getRenditionFilterString(), oc.isIncludePolicies(), oc.isIncludeAcls(), null);
921 
922             // reset this object
923             initialize(session, session.getTypeDefinition(objectType.getId()), objectData, creationContext);
924         } finally {
925             writeUnlock();
926         }
927     }
928 
929     @Override
930     public void refreshIfOld(long durationInMillis) {
931         writeLock();
932         try {
933             if (this.refreshTimestamp < System.currentTimeMillis() - durationInMillis) {
934                 refresh();
935             }
936         } finally {
937             writeUnlock();
938         }
939     }
940 
941     @Override
942     public String toString() {
943         readLock();
944         try {
945             if (objectType == null) {
946                 return "<unknown>";
947             }
948 
949             return objectType.getBaseTypeId() + " (" + objectType.getId() + "): " + getId();
950         } finally {
951             readUnlock();
952         }
953     }
954 }