This project has retired. For details please refer to its
Attic page.
AbstractTransientCmisObject xref
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.chemistry.opencmis.client.runtime;
20
21 import java.io.Serializable;
22 import java.math.BigDecimal;
23 import java.math.BigInteger;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.GregorianCalendar;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.Iterator;
30 import java.util.LinkedHashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34
35 import org.apache.chemistry.opencmis.client.api.CmisObject;
36 import org.apache.chemistry.opencmis.client.api.ObjectFactory;
37 import org.apache.chemistry.opencmis.client.api.ObjectId;
38 import org.apache.chemistry.opencmis.client.api.ObjectType;
39 import org.apache.chemistry.opencmis.client.api.Policy;
40 import org.apache.chemistry.opencmis.client.api.Property;
41 import org.apache.chemistry.opencmis.client.api.Relationship;
42 import org.apache.chemistry.opencmis.client.api.Rendition;
43 import org.apache.chemistry.opencmis.client.api.Session;
44 import org.apache.chemistry.opencmis.client.api.TransientCmisObject;
45 import org.apache.chemistry.opencmis.commons.PropertyIds;
46 import org.apache.chemistry.opencmis.commons.data.Ace;
47 import org.apache.chemistry.opencmis.commons.data.Acl;
48 import org.apache.chemistry.opencmis.commons.data.AllowableActions;
49 import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement;
50 import org.apache.chemistry.opencmis.commons.data.Properties;
51 import org.apache.chemistry.opencmis.commons.data.PropertyData;
52 import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
53 import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
54 import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
55 import org.apache.chemistry.opencmis.commons.enums.Cardinality;
56 import org.apache.chemistry.opencmis.commons.enums.ExtensionLevel;
57 import org.apache.chemistry.opencmis.commons.enums.Updatability;
58 import org.apache.chemistry.opencmis.commons.spi.CmisBinding;
59 import org.apache.chemistry.opencmis.commons.spi.Holder;
60
61 public abstract class AbstractTransientCmisObject implements TransientCmisObject {
62
63 protected Session session;
64 protected CmisObject object;
65
66 protected Map<String, Property<?>> properties;
67 protected AllowableActions allowableActions;
68 protected List<Rendition> renditions;
69 protected Acl acl;
70 protected Map<AclPropagation, List<AceChangeHolder>> addAces;
71 protected Map<AclPropagation, List<AceChangeHolder>> removeAces;
72 protected List<Policy> policies;
73 protected Set<String> addPolicies;
74 protected Set<String> removePolicies;
75 protected List<Relationship> relationships;
76 protected Map<ExtensionLevel, List<CmisExtensionElement>> inputExtensions;
77 protected Map<ExtensionLevel, List<CmisExtensionElement>> ouputExtensions;
78
79 protected boolean isModified;
80 protected boolean isPropertyUpdateRequired;
81 protected boolean isMarkedForDelete;
82 protected boolean deleteAllVersions;
83
84 @SuppressWarnings({ "rawtypes", "unchecked" })
85 protected void initialize(Session session, CmisObject object) {
86 this.session = session;
87 this.object = object;
88
89 ObjectFactory of = getObjectFactory();
90
91
92
93
94 properties = new LinkedHashMap<String, Property<?>>();
95 for (Property<?> property : object.getProperties()) {
96 properties.put(property.getId(),
97 of.createProperty(property.getDefinition(), new ArrayList(property.getValues())));
98 }
99 isPropertyUpdateRequired = false;
100
101
102 allowableActions = object.getAllowableActions();
103
104
105 policies = new ArrayList<Policy>();
106 if (object.getPolicies() != null) {
107 policies.addAll(object.getPolicies());
108 }
109 addPolicies = new HashSet<String>();
110 removePolicies = new HashSet<String>();
111
112
113 acl = object.getAcl();
114 addAces = new HashMap<AclPropagation, List<AceChangeHolder>>();
115 removeAces = new HashMap<AclPropagation, List<AceChangeHolder>>();
116
117
118 relationships = object.getRelationships();
119
120
121 renditions = object.getRenditions();
122
123
124 inputExtensions = new HashMap<ExtensionLevel, List<CmisExtensionElement>>();
125 for (ExtensionLevel level : ExtensionLevel.values()) {
126 List<CmisExtensionElement> extension = object.getExtensions(level);
127 if (extension != null) {
128 inputExtensions.put(level, extension);
129 }
130 }
131
132
133 ouputExtensions = new HashMap<ExtensionLevel, List<CmisExtensionElement>>();
134
135 isModified = false;
136 deleteAllVersions = true;
137 isMarkedForDelete = false;
138 }
139
140 public CmisObject getCmisObject() {
141 return object;
142 }
143
144
145
146
147 protected Session getSession() {
148 return this.session;
149 }
150
151
152
153
154 protected String getRepositoryId() {
155 return getSession().getRepositoryInfo().getId();
156 }
157
158
159
160
161 protected CmisBinding getBinding() {
162 return getSession().getBinding();
163 }
164
165
166
167
168 protected ObjectFactory getObjectFactory() {
169 return getSession().getObjectFactory();
170 }
171
172 protected ObjectId getObjectId() {
173 return getSession().createObjectId(getId());
174 }
175
176 public ObjectType getBaseType() {
177 return object.getBaseType();
178 }
179
180 public BaseTypeId getBaseTypeId() {
181 return object.getBaseTypeId();
182 }
183
184 public ObjectType getType() {
185 return object.getType();
186 }
187
188 public String getChangeToken() {
189 return getPropertyValue(PropertyIds.CHANGE_TOKEN);
190 }
191
192 public String getCreatedBy() {
193 return getPropertyValue(PropertyIds.CREATED_BY);
194 }
195
196 public GregorianCalendar getCreationDate() {
197 return getPropertyValue(PropertyIds.CREATION_DATE);
198 }
199
200 public String getId() {
201 return getPropertyValue(PropertyIds.OBJECT_ID);
202 }
203
204 public GregorianCalendar getLastModificationDate() {
205 return getPropertyValue(PropertyIds.LAST_MODIFICATION_DATE);
206 }
207
208 public String getLastModifiedBy() {
209 return getPropertyValue(PropertyIds.LAST_MODIFIED_BY);
210 }
211
212 public String getName() {
213 return getPropertyValue(PropertyIds.NAME);
214 }
215
216 public void setName(String name) {
217 setPropertyValue(PropertyIds.NAME, name);
218 }
219
220 public List<Property<?>> getProperties() {
221 return Collections.unmodifiableList(new ArrayList<Property<?>>(this.properties.values()));
222 }
223
224 @SuppressWarnings("unchecked")
225 public <T> Property<T> getProperty(String id) {
226 return (Property<T>) this.properties.get(id);
227 }
228
229 @SuppressWarnings("unchecked")
230 public <T> T getPropertyValue(String id) {
231 Property<T> property = getProperty(id);
232 if (property == null) {
233 return null;
234 }
235
236 return (T) property.getValue();
237 }
238
239 @SuppressWarnings("unchecked")
240 public <T> void setPropertyValue(String id, Object value) {
241 PropertyDefinition<T> propertyDefinition = (PropertyDefinition<T>) getType().getPropertyDefinitions().get(id);
242 if (propertyDefinition == null) {
243 throw new IllegalArgumentException("Unknown property '" + id + "'!");
244 }
245
246 if (propertyDefinition.getUpdatability() == Updatability.READONLY) {
247 throw new IllegalArgumentException("Property is read-only!");
248 }
249
250 List<T> values = checkProperty(propertyDefinition, value);
251
252
253 Property<T> newProperty = getObjectFactory().createProperty(propertyDefinition, values);
254 properties.put(id, newProperty);
255
256 isPropertyUpdateRequired = true;
257 isModified = true;
258 }
259
260 public AllowableActions getAllowableActions() {
261 return allowableActions;
262 }
263
264 public List<Relationship> getRelationships() {
265 return relationships;
266 }
267
268 public List<Rendition> getRenditions() {
269 return renditions;
270 }
271
272 public void delete(boolean allVersions) {
273 deleteAllVersions = allVersions;
274 isMarkedForDelete = true;
275 isModified = true;
276 }
277
278 public void applyPolicy(Policy... policyIds) {
279 for (Policy policy : policyIds) {
280 if ((policy != null) && (policy.getId() != null)) {
281 addPolicies.add(policy.getId());
282 addPolicyToPolicyList(policy);
283 }
284 }
285 }
286
287 public void removePolicy(Policy... policyIds) {
288 for (Policy policy : policyIds) {
289 if ((policy != null) && (policy.getId() != null)) {
290 removePolicies.add(policy.getId());
291 removePolicyFromPolicyList(policy);
292 }
293 }
294 }
295
296 public List<Policy> getPolicies() {
297 return policies;
298 }
299
300 private void addPolicyToPolicyList(Policy policy) {
301 for (Policy p : policies) {
302 if (policy.getId().equals(p.getId())) {
303 return;
304 }
305 }
306
307 policies.add(policy);
308 }
309
310 private void removePolicyFromPolicyList(Policy policy) {
311 Iterator<Policy> iter = policies.iterator();
312 while (iter.hasNext()) {
313 Policy p = iter.next();
314 if (policy.getId().equals(p.getId())) {
315 iter.remove();
316 }
317 }
318 }
319
320 public Acl getOriginalAcl() {
321 return acl;
322 }
323
324 public void addAce(String principalId, List<String> permissions, AclPropagation aclPropagation) {
325 AceChangeHolder ach = new AceChangeHolder(principalId, permissions, aclPropagation);
326
327 List<AceChangeHolder> list = addAces.get(aclPropagation);
328 if (list == null) {
329 list = new ArrayList<AbstractTransientCmisObject.AceChangeHolder>();
330 addAces.put(aclPropagation, list);
331 }
332
333 list.add(ach);
334 }
335
336 public void removeAce(String principalId, List<String> permissions, AclPropagation aclPropagation) {
337 AceChangeHolder ach = new AceChangeHolder(principalId, permissions, aclPropagation);
338
339 List<AceChangeHolder> list = removeAces.get(aclPropagation);
340 if (list == null) {
341 list = new ArrayList<AbstractTransientCmisObject.AceChangeHolder>();
342 removeAces.put(aclPropagation, list);
343 }
344
345 list.add(ach);
346 }
347
348 public List<CmisExtensionElement> getInputExtensions(ExtensionLevel level) {
349 return inputExtensions.get(level);
350 }
351
352 public List<CmisExtensionElement> getOutputExtensions(ExtensionLevel level) {
353 return ouputExtensions.get(level);
354 }
355
356 public void setOutputExtensions(ExtensionLevel level, List<CmisExtensionElement> extensions) {
357 ouputExtensions.put(level, extensions);
358 }
359
360 public boolean isMarkedForDelete() {
361 return isMarkedForDelete;
362 }
363
364 public boolean isModified() {
365 return isModified;
366 }
367
368 public void reset() {
369 initialize(session, object);
370 }
371
372 public void refreshAndReset() {
373 object.refresh();
374 reset();
375 }
376
377 public ObjectId save() {
378 if (!isModified()) {
379
380 return getObjectId();
381 }
382
383 String objectId = getId();
384
385 if (saveDelete(objectId)) {
386
387
388 return null;
389 }
390 String newObjectId = saveProperties(getId(), getChangeToken());
391 saveACL(newObjectId);
392 savePolicies(newObjectId);
393
394 return getSession().createObjectId(newObjectId);
395 }
396
397
398
399
400 protected String getLatestChangeToken(String objectId) {
401
402 PropertyDefinition<?> objectIdPropDef = getCmisObject().getType().getPropertyDefinitions()
403 .get(PropertyIds.OBJECT_ID);
404 if (objectIdPropDef == null) {
405 return null;
406 }
407
408 String objectIdQueryName = objectIdPropDef.getQueryName();
409 if (objectIdQueryName == null) {
410 return null;
411 }
412
413
414 PropertyDefinition<?> changeTokenPropDef = getCmisObject().getType().getPropertyDefinitions()
415 .get(PropertyIds.CHANGE_TOKEN);
416 if (changeTokenPropDef == null) {
417 return null;
418 }
419
420 String changeTokenQueryName = changeTokenPropDef.getQueryName();
421 if (changeTokenQueryName == null) {
422 return null;
423 }
424
425
426 Properties properties = getBinding().getObjectService().getProperties(getRepositoryId(), objectId,
427 objectIdQueryName + "," + changeTokenQueryName, null);
428
429
430 PropertyData<?> changeToken = properties.getProperties().get(PropertyIds.CHANGE_TOKEN);
431
432 if ((changeToken == null) || (changeToken.getFirstValue() == null)) {
433 return null;
434 }
435
436 return changeToken.getFirstValue().toString();
437 }
438
439 protected boolean saveDelete(String objectId) {
440 if (isMarkedForDelete) {
441 getBinding().getObjectService().deleteObject(getRepositoryId(), objectId, deleteAllVersions, null);
442 return true;
443 }
444
445 return false;
446 }
447
448 protected Properties prepareProperties() {
449 Set<Updatability> updatebility = new HashSet<Updatability>();
450 updatebility.add(Updatability.READWRITE);
451
452
453 Boolean isCheckedOut = getPropertyValue(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT);
454 if ((isCheckedOut != null) && isCheckedOut.booleanValue()) {
455 updatebility.add(Updatability.WHENCHECKEDOUT);
456 }
457
458
459 Properties result = getObjectFactory().convertProperties(properties, getType(), updatebility);
460
461
462 List<CmisExtensionElement> extensions = ouputExtensions.get(ExtensionLevel.PROPERTIES);
463 if (extensions != null) {
464 result.setExtensions(extensions);
465 }
466
467 return result;
468 }
469
470 protected String saveProperties(String objectId, String changeToken) {
471 if (isPropertyUpdateRequired) {
472 Holder<String> objectIdHolder = new Holder<String>(objectId);
473 Holder<String> changeTokenHolder = new Holder<String>(changeToken);
474
475
476 Properties props = prepareProperties();
477
478
479 getBinding().getObjectService().updateProperties(getRepositoryId(), objectIdHolder, changeTokenHolder,
480 props, null);
481
482 if (objectIdHolder.getValue() != null) {
483 return objectIdHolder.getValue();
484 }
485 }
486
487 return objectId;
488 }
489
490 protected void savePolicies(String objectId) {
491
492 for (String policyId : addPolicies) {
493 getBinding().getPolicyService().applyPolicy(getRepositoryId(), policyId, objectId, null);
494 }
495
496
497 for (String policyId : removePolicies) {
498 getBinding().getPolicyService().removePolicy(getRepositoryId(), policyId, objectId, null);
499 }
500 }
501
502 protected Acl prepareAcl(List<AceChangeHolder> achList) {
503 if ((achList == null) || (achList.isEmpty())) {
504 return null;
505 }
506
507 ObjectFactory of = getObjectFactory();
508
509 List<Ace> aces = new ArrayList<Ace>();
510 for (AceChangeHolder ach : achList) {
511 aces.add(of.createAce(ach.getPrincipalId(), ach.getPermissions()));
512 }
513
514 return of.createAcl(aces);
515 }
516
517 protected void saveACL(String objectId) {
518 for (AclPropagation ap : AclPropagation.values()) {
519 if (!addAces.containsKey(ap) && !removeAces.containsKey(ap)) {
520 continue;
521 }
522
523 getBinding().getAclService().applyAcl(getRepositoryId(), objectId, prepareAcl(addAces.get(ap)),
524 prepareAcl(removeAces.get(ap)), ap, null);
525 }
526
527 if (addAces.containsKey(null) || removeAces.containsKey(null)) {
528 getBinding().getAclService().applyAcl(getRepositoryId(), objectId, prepareAcl(addAces.get(null)),
529 prepareAcl(removeAces.get(null)), null, null);
530 }
531 }
532
533
534
535
536
537
538
539
540 @SuppressWarnings("unchecked")
541 private static <T> List<T> checkProperty(PropertyDefinition<T> propertyDefinition, Object value) {
542
543
544 if (value == null) {
545 return null;
546 }
547
548
549 List<T> values = null;
550 if (value instanceof List<?>) {
551 if (propertyDefinition.getCardinality() != Cardinality.MULTI) {
552 throw new IllegalArgumentException("Property '" + propertyDefinition.getId()
553 + "' is not a multi value property!");
554 }
555
556 values = (List<T>) value;
557 if (values.isEmpty()) {
558 return values;
559 }
560 } else {
561 if (propertyDefinition.getCardinality() != Cardinality.SINGLE) {
562 throw new IllegalArgumentException("Property '" + propertyDefinition.getId()
563 + "' is not a single value property!");
564 }
565
566 values = Collections.singletonList((T) value);
567 }
568
569
570 for (Object o : values) {
571 if (o == null) {
572 throw new IllegalArgumentException("Property '" + propertyDefinition.getId()
573 + "' contains null values!");
574 }
575 }
576
577
578 boolean typeMatch = false;
579 Object firstValue = values.get(0);
580
581 switch (propertyDefinition.getPropertyType()) {
582 case STRING:
583 case ID:
584 case URI:
585 case HTML:
586 typeMatch = (firstValue instanceof String);
587 break;
588 case INTEGER:
589 typeMatch = (firstValue instanceof BigInteger) || (firstValue instanceof Byte)
590 || (firstValue instanceof Short) || (firstValue instanceof Integer) || (firstValue instanceof Long);
591 break;
592 case DECIMAL:
593 typeMatch = (firstValue instanceof BigDecimal);
594 break;
595 case BOOLEAN:
596 typeMatch = (firstValue instanceof Boolean);
597 break;
598 case DATETIME:
599 typeMatch = (firstValue instanceof GregorianCalendar);
600 break;
601 }
602
603 if (!typeMatch) {
604 throw new IllegalArgumentException("Value of property '" + propertyDefinition.getId()
605 + "' does not match property type!");
606 }
607
608 return values;
609 }
610
611
612
613 public static class AceChangeHolder implements Serializable {
614 private static final long serialVersionUID = 1L;
615
616 private final String principalId;
617 private final List<String> permissions;
618 private final AclPropagation aclPropagation;
619
620 public AceChangeHolder(String principalId, List<String> permissions, AclPropagation aclPropagation) {
621 if ((principalId == null) || (principalId.length() == 0)) {
622 throw new IllegalArgumentException("Principal id must be set!");
623 }
624
625 if ((permissions == null) || (permissions.size() == 0)) {
626 throw new IllegalArgumentException("Permissions id must be set!");
627 }
628
629 this.principalId = principalId;
630 this.permissions = permissions;
631 this.aclPropagation = aclPropagation;
632 }
633
634 public String getPrincipalId() {
635 return principalId;
636 }
637
638 public List<String> getPermissions() {
639 return permissions;
640 }
641
642 public AclPropagation getAclPropagation() {
643 return aclPropagation;
644 }
645 }
646 }