This project has retired. For details please refer to its
Attic page.
InMemoryObjectServiceImpl 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.inmemory.server;
20
21 import java.math.BigInteger;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import org.apache.chemistry.opencmis.commons.PropertyIds;
29 import org.apache.chemistry.opencmis.commons.data.Acl;
30 import org.apache.chemistry.opencmis.commons.data.AllowableActions;
31 import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement;
32 import org.apache.chemistry.opencmis.commons.data.ContentStream;
33 import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
34 import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData;
35 import org.apache.chemistry.opencmis.commons.data.ObjectData;
36 import org.apache.chemistry.opencmis.commons.data.Properties;
37 import org.apache.chemistry.opencmis.commons.data.PropertyData;
38 import org.apache.chemistry.opencmis.commons.data.RenditionData;
39 import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
40 import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
41 import org.apache.chemistry.opencmis.commons.definitions.RelationshipTypeDefinition;
42 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
43 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
44 import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
45 import org.apache.chemistry.opencmis.commons.enums.Cardinality;
46 import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
47 import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
48 import org.apache.chemistry.opencmis.commons.enums.Updatability;
49 import org.apache.chemistry.opencmis.commons.enums.VersioningState;
50 import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
51 import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException;
52 import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
53 import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
54 import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
55 import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException;
56 import org.apache.chemistry.opencmis.commons.impl.dataobjects.CmisExtensionElementImpl;
57 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
58 import org.apache.chemistry.opencmis.commons.impl.dataobjects.FailedToDeleteDataImpl;
59 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl;
60 import org.apache.chemistry.opencmis.commons.impl.server.ObjectInfoImpl;
61 import org.apache.chemistry.opencmis.commons.server.CallContext;
62 import org.apache.chemistry.opencmis.commons.server.ObjectInfoHandler;
63 import org.apache.chemistry.opencmis.commons.spi.Holder;
64 import org.apache.chemistry.opencmis.inmemory.FilterParser;
65 import org.apache.chemistry.opencmis.inmemory.NameValidator;
66 import org.apache.chemistry.opencmis.inmemory.storedobj.api.Content;
67 import org.apache.chemistry.opencmis.inmemory.storedobj.api.Document;
68 import org.apache.chemistry.opencmis.inmemory.storedobj.api.DocumentVersion;
69 import org.apache.chemistry.opencmis.inmemory.storedobj.api.Filing;
70 import org.apache.chemistry.opencmis.inmemory.storedobj.api.Folder;
71 import org.apache.chemistry.opencmis.inmemory.storedobj.api.ObjectStore;
72 import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoreManager;
73 import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoredObject;
74 import org.apache.chemistry.opencmis.inmemory.storedobj.api.VersionedDocument;
75 import org.apache.chemistry.opencmis.inmemory.types.InMemoryDocumentTypeDefinition;
76 import org.apache.chemistry.opencmis.inmemory.types.InMemoryFolderTypeDefinition;
77 import org.apache.chemistry.opencmis.inmemory.types.InMemoryPolicyTypeDefinition;
78 import org.apache.chemistry.opencmis.inmemory.types.InMemoryRelationshipTypeDefinition;
79 import org.apache.chemistry.opencmis.inmemory.types.PropertyCreationHelper;
80 import org.apache.chemistry.opencmis.server.support.TypeValidator;
81 import org.apache.commons.logging.Log;
82 import org.apache.commons.logging.LogFactory;
83
84 public class InMemoryObjectServiceImpl extends InMemoryAbstractServiceImpl {
85 private static final Log LOG = LogFactory.getLog(InMemoryServiceFactoryImpl.class.getName());
86
87 final AtomLinkInfoProvider fAtomLinkProvider;
88
89 public InMemoryObjectServiceImpl(StoreManager storeManager) {
90 super(storeManager);
91 fAtomLinkProvider = new AtomLinkInfoProvider(fStoreManager);
92 }
93
94 public String createDocument(CallContext context, String repositoryId, Properties properties, String folderId,
95 ContentStream contentStream, VersioningState versioningState, List<String> policies, Acl addAces,
96 Acl removeAces, ExtensionsData extension) {
97
98 LOG.debug("start createDocument()");
99
100
101
102 StoredObject so = createDocumentIntern(context, repositoryId, properties, folderId, contentStream, versioningState,
103 policies, addAces, removeAces, extension);
104 LOG.debug("stop createDocument()");
105 return so.getId();
106 }
107
108 public String createDocumentFromSource(CallContext context, String repositoryId, String sourceId,
109 Properties properties, String folderId, VersioningState versioningState, List<String> policies,
110 Acl addAces, Acl removeAces, ExtensionsData extension) {
111
112 LOG.debug("start createDocumentFromSource()");
113 StoredObject so = validator.createDocumentFromSource(context, repositoryId, sourceId, folderId, extension);
114 TypeDefinition td = getTypeDefinition(repositoryId, so);
115
116 ContentStream content = getContentStream(context, repositoryId, sourceId, null, BigInteger.valueOf(-1),
117 BigInteger.valueOf(-1), null);
118
119 if (so == null) {
120 throw new CmisObjectNotFoundException("Unknown object id: " + sourceId);
121 }
122
123
124 List<String> requestedIds = FilterParser.getRequestedIdsFromFilter("*");
125
126 Properties existingProps = PropertyCreationHelper.getPropertiesFromObject(so, td, requestedIds, true);
127
128 PropertiesImpl newPD = new PropertiesImpl();
129
130 for (PropertyData<?> prop : existingProps.getProperties().values()) {
131 newPD.addProperty(prop);
132 }
133
134 if (null != properties)
135
136 for (PropertyData<?> prop : properties.getProperties().values()) {
137 newPD.addProperty(prop);
138 }
139
140 String res = createDocument(context, repositoryId, newPD, folderId, content, versioningState, policies,
141 addAces, removeAces, null);
142 LOG.debug("stop createDocumentFromSource()");
143 return res;
144 }
145
146 public String createFolder(CallContext context, String repositoryId, Properties properties, String folderId,
147 List<String> policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
148 LOG.debug("start createFolder()");
149
150 Folder folder = createFolderIntern(context, repositoryId, properties, folderId, policies, addAces, removeAces,
151 extension);
152 LOG.debug("stop createFolder()");
153 return folder.getId();
154 }
155
156 public String createPolicy(CallContext context, String repositoryId, Properties properties, String folderId,
157 List<String> policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
158
159
160 LOG.debug("start createPolicy()");
161 StoredObject so = createPolicyIntern(context, repositoryId, properties, folderId, policies, addAces, removeAces,
162 extension);
163 LOG.debug("stop createPolicy()");
164 return so == null ? null : so.getId();
165 }
166
167 public String createRelationship(CallContext context, String repositoryId, Properties properties,
168 List<String> policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
169
170
171 LOG.debug("start createRelationship()");
172 StoredObject so = createRelationshipIntern(context, repositoryId, properties, policies, addAces, removeAces, extension);
173 LOG.debug("stop createRelationship()");
174 return so == null ? null : so.getId();
175 }
176
177 @SuppressWarnings("unchecked")
178 public String create(CallContext context, String repositoryId, Properties properties, String folderId,
179 ContentStream contentStream, VersioningState versioningState, List<String> policies,
180 ExtensionsData extension, ObjectInfoHandler objectInfos) {
181
182 if (null == properties || null == properties.getProperties()) {
183 throw new CmisInvalidArgumentException("Cannot create object, without properties.");
184 }
185
186
187 PropertyData<String> pd = (PropertyData<String>) properties.getProperties().get(PropertyIds.OBJECT_TYPE_ID);
188 String typeId = pd == null ? null : pd.getFirstValue();
189 if (null == typeId) {
190 throw new CmisInvalidArgumentException(
191 "Cannot create object, without a type (no property with id CMIS_OBJECT_TYPE_ID).");
192 }
193
194 TypeDefinitionContainer typeDefC = fStoreManager.getTypeById(repositoryId, typeId);
195 if (typeDefC == null) {
196 throw new CmisInvalidArgumentException("Cannot create object, a type with id " + typeId + " is unknown");
197 }
198
199
200 BaseTypeId typeBaseId = typeDefC.getTypeDefinition().getBaseTypeId();
201 StoredObject so = null;
202 if (typeBaseId.equals(InMemoryDocumentTypeDefinition.getRootDocumentType().getBaseTypeId())) {
203 so = createDocumentIntern(context, repositoryId, properties, folderId, contentStream, versioningState, null, null,
204 null, null);
205 } else if (typeBaseId.equals(InMemoryFolderTypeDefinition.getRootFolderType().getBaseTypeId())) {
206 so = createFolderIntern(context, repositoryId, properties, folderId, null, null, null, null);
207 } else if (typeBaseId.equals(InMemoryPolicyTypeDefinition.getRootPolicyType().getBaseTypeId())) {
208 so = createPolicyIntern(context, repositoryId, properties, folderId, null, null, null, null);
209 } else if (typeBaseId.equals(InMemoryRelationshipTypeDefinition.getRootRelationshipType().getBaseTypeId())) {
210 so = createRelationshipIntern(context, repositoryId, properties, null, null, null, null);
211 } else {
212 LOG.error("The type contains an unknown base object id, object can't be created");
213 }
214
215
216
217 TypeDefinition td = typeDefC.getTypeDefinition();
218 ObjectData od = PropertyCreationHelper.getObjectData(td, so, null, context.getUsername(), false,
219 IncludeRelationships.NONE, null, false, false, extension);
220
221 if (context.isObjectInfoRequired()) {
222 ObjectInfoImpl objectInfo = new ObjectInfoImpl();
223 fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, od, objectInfo);
224 objectInfos.addObjectInfo(objectInfo);
225 }
226 return so != null ? so.getId() : null;
227 }
228
229 public void deleteContentStream(CallContext context, String repositoryId, Holder<String> objectId,
230 Holder<String> changeToken, ExtensionsData extension) {
231
232 LOG.debug("start deleteContentStream()");
233 StoredObject so = validator.deleteContentStream(context, repositoryId, objectId, extension);
234
235 if (so == null) {
236 throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
237 }
238
239 if ( so.getChangeToken() != null && ( changeToken == null || !so.getChangeToken().equals( changeToken.getValue() ) ) )
240 throw new CmisUpdateConflictException( "deleteContentStream failed, ChangeToken does not match." );
241
242 if (!(so instanceof Content)) {
243 throw new CmisObjectNotFoundException("Id" + objectId
244 + " does not refer to a document, but only documents can have content");
245 }
246
247 ((Content) so).setContent(null, true);
248 LOG.debug("stop deleteContentStream()");
249 }
250
251 public void deleteObject(CallContext context, String repositoryId, String objectId,
252 Boolean allVersions, ExtensionsData extension) {
253
254 LOG.debug("start deleteObject()");
255 validator.deleteObject(context, repositoryId, objectId, allVersions, extension);
256 ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
257 LOG.debug("delete object for id: " + objectId);
258
259
260 if (objectId.equals(objectStore.getRootFolder().getId())) {
261 throw new CmisNotSupportedException("You can't delete a root folder");
262 }
263
264 objectStore.deleteObject(objectId, allVersions, context.getUsername());
265 LOG.debug("stop deleteObject()");
266 }
267
268 public FailedToDeleteData deleteTree(CallContext context, String repositoryId, String folderId,
269 Boolean allVersions, UnfileObject unfileObjects, Boolean continueOnFailure, ExtensionsData extension) {
270
271 LOG.debug("start deleteTree()");
272 StoredObject so = validator.deleteTree(context, repositoryId, folderId, allVersions, unfileObjects, extension);
273 List<String> failedToDeleteIds = new ArrayList<String>();
274 FailedToDeleteDataImpl result = new FailedToDeleteDataImpl();
275
276 if (null == allVersions) {
277 allVersions = true;
278 }
279 if (null == unfileObjects) {
280 unfileObjects = UnfileObject.DELETE;
281 }
282 if (null == continueOnFailure) {
283 continueOnFailure = false;
284 }
285
286 ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
287
288 if (null == so) {
289 throw new CmisInvalidArgumentException("Cannot delete object with id " + folderId + ". Object does not exist.");
290 }
291
292 if (!(so instanceof Folder)) {
293 throw new CmisInvalidArgumentException("deleteTree can only be invoked on a folder, but id " + folderId
294 + " does not refer to a folder");
295 }
296
297 if (unfileObjects == UnfileObject.UNFILE) {
298 throw new CmisNotSupportedException("This repository does not support unfile operations.");
299 }
300
301
302 if (folderId.equals(objectStore.getRootFolder().getId())) {
303 throw new CmisNotSupportedException("You can't delete a root folder");
304 }
305
306
307 deleteRecursive(objectStore, (Folder) so, continueOnFailure, allVersions, failedToDeleteIds, context.getUsername());
308
309 result.setIds(failedToDeleteIds);
310 LOG.debug("stop deleteTree()");
311 return result;
312 }
313
314 public AllowableActions getAllowableActions(CallContext context, String repositoryId, String objectId,
315 ExtensionsData extension) {
316
317 LOG.debug("start getAllowableActions()");
318 StoredObject so = validator.getAllowableActions(context, repositoryId, objectId, extension);
319
320 fStoreManager.getObjectStore(repositoryId);
321
322 if (so == null) {
323 throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
324 }
325
326 String user = context.getUsername();
327
328 AllowableActions allowableActions = so.getAllowableActions(user);
329 LOG.debug("stop getAllowableActions()");
330 return allowableActions;
331 }
332
333 public ContentStream getContentStream(CallContext context, String repositoryId, String objectId, String streamId,
334 BigInteger offset, BigInteger length, ExtensionsData extension) {
335
336 LOG.debug("start getContentStream()");
337 StoredObject so = validator.getContentStream(context, repositoryId, objectId, streamId, extension);
338
339
340 if (so == null) {
341 throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
342 }
343
344 if (!(so instanceof Content)) {
345 throw new CmisConstraintException("Id" + objectId
346 + " does not refer to a document or version, but only those can have content");
347 }
348
349 ContentStream csd = getContentStream(so, streamId, offset, length);
350
351 if (null == csd) {
352 throw new CmisConstraintException("Object " + so.getId() + " does not have content.");
353 }
354
355 LOG.debug("stop getContentStream()");
356 return csd;
357 }
358
359 public ObjectData getObject(CallContext context, String repositoryId, String objectId, String filter,
360 Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
361 Boolean includePolicyIds, Boolean includeAcl, ExtensionsData extension, ObjectInfoHandler objectInfos) {
362
363 LOG.debug("start getObject()");
364
365 StoredObject so = validator.getObject(context, repositoryId, objectId, extension);
366
367 if (so == null) {
368 throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
369 }
370
371 String user = context.getUsername();
372 TypeDefinition td = fStoreManager.getTypeById(repositoryId, so.getTypeId()).getTypeDefinition();
373 ObjectData od = PropertyCreationHelper.getObjectData(td, so, filter, user, includeAllowableActions,
374 includeRelationships, renditionFilter, includePolicyIds, includeAcl, extension);
375
376 if (context.isObjectInfoRequired()) {
377 ObjectInfoImpl objectInfo = new ObjectInfoImpl();
378 fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfo);
379 objectInfos.addObjectInfo(objectInfo);
380 }
381
382
383 String ns = "http://apache.org/opencmis/inmemory";
384 List<CmisExtensionElement> extElements = new ArrayList<CmisExtensionElement>();
385
386 Map<String, String> attr = new HashMap<String, String>();
387 attr.put("type", so.getTypeId());
388
389 extElements.add(new CmisExtensionElementImpl(ns, "objectId", attr, objectId));
390 extElements.add(new CmisExtensionElementImpl(ns, "name", null, so.getName()));
391 od.setExtensions(Collections.singletonList(
392 (CmisExtensionElement) new CmisExtensionElementImpl(ns, "exampleExtension",null, extElements)));
393
394 LOG.debug("stop getObject()");
395
396 return od;
397 }
398
399 public ObjectData getObjectByPath(CallContext context, String repositoryId, String path, String filter,
400 Boolean includeAllowableActions, IncludeRelationships includeRelationships, String renditionFilter,
401 Boolean includePolicyIds, Boolean includeAcl, ExtensionsData extension, ObjectInfoHandler objectInfos) {
402
403 LOG.debug("start getObjectByPath()");
404 StoredObject so = validator.getObjectByPath(context, repositoryId, path, extension);
405 if (so instanceof VersionedDocument) {
406 VersionedDocument verDoc = (VersionedDocument) so;
407 so = verDoc.getLatestVersion(false);
408 }
409
410 String user = context.getUsername();
411
412 TypeDefinition td = fStoreManager.getTypeById(repositoryId, so.getTypeId()).getTypeDefinition();
413 ObjectData od = PropertyCreationHelper.getObjectData(td, so, filter, user, includeAllowableActions,
414 includeRelationships, renditionFilter, includePolicyIds, includeAcl, extension);
415
416 LOG.debug("stop getObjectByPath()");
417
418
419
420 if (context.isObjectInfoRequired()) {
421 ObjectInfoImpl objectInfo = new ObjectInfoImpl();
422 fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, objectInfo);
423 objectInfos.addObjectInfo(objectInfo);
424 }
425
426 return od;
427 }
428
429 public Properties getProperties(CallContext context, String repositoryId, String objectId, String filter,
430 ExtensionsData extension) {
431
432 LOG.debug("start getProperties()");
433 StoredObject so = validator.getProperties(context, repositoryId, objectId, extension);
434
435 if (so == null) {
436 throw new CmisObjectNotFoundException("Unknown object id: " + objectId);
437 }
438
439
440 List<String> requestedIds = FilterParser.getRequestedIdsFromFilter(filter);
441 TypeDefinition td = fStoreManager.getTypeById(repositoryId, so.getTypeId()).getTypeDefinition();
442 Properties props = PropertyCreationHelper.getPropertiesFromObject(so, td, requestedIds, true);
443 LOG.debug("stop getProperties()");
444 return props;
445 }
446
447 public List<RenditionData> getRenditions(CallContext context, String repositoryId, String objectId,
448 String renditionFilter, BigInteger maxItems, BigInteger skipCount, ExtensionsData extension) {
449
450
451 LOG.debug("start getRenditions()");
452 validator.getRenditions(context, repositoryId, objectId, extension);
453
454 LOG.debug("stop getRenditions()");
455 return null;
456 }
457
458 public ObjectData moveObject(CallContext context, String repositoryId, Holder<String> objectId,
459 String targetFolderId, String sourceFolderId, ExtensionsData extension, ObjectInfoHandler objectInfos) {
460
461 LOG.debug("start moveObject()");
462 StoredObject[] sos = validator.moveObject(context, repositoryId, objectId, targetFolderId, sourceFolderId, extension);
463 StoredObject so = sos[0];
464 Folder targetFolder = null;
465 Folder sourceFolder = null;
466 ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
467 Filing spo = null;
468 String user = context.getUsername();
469
470 if (null == so) {
471 throw new CmisObjectNotFoundException("Unknown object: " + objectId.getValue());
472 } else if (so instanceof Filing) {
473 spo = (Filing) so;
474 } else {
475 throw new CmisInvalidArgumentException("Object must be folder or document: " + objectId.getValue());
476 }
477
478 StoredObject soTarget = objectStore.getObjectById(targetFolderId);
479 if (null == soTarget) {
480 throw new CmisObjectNotFoundException("Unknown target folder: " + targetFolderId);
481 } else if (soTarget instanceof Folder) {
482 targetFolder = (Folder) soTarget;
483 } else {
484 throw new CmisNotSupportedException("Destination " + targetFolderId
485 + " of a move operation must be a folder");
486 }
487
488 StoredObject soSource = objectStore.getObjectById(sourceFolderId);
489 if (null == soSource) {
490 throw new CmisObjectNotFoundException("Unknown source folder: " + sourceFolderId);
491 } else if (soSource instanceof Folder) {
492 sourceFolder = (Folder) soSource;
493 } else {
494 throw new CmisNotSupportedException("Source " + sourceFolderId + " of a move operation must be a folder");
495 }
496
497 boolean foundOldParent = false;
498 for (Folder parent : spo.getParents(user)) {
499 if (parent.getId().equals(soSource.getId())) {
500 foundOldParent = true;
501 break;
502 }
503 }
504 if (!foundOldParent) {
505 throw new CmisNotSupportedException("Cannot move object, source folder " + sourceFolderId
506 + "is not a parent of object " + objectId.getValue());
507 }
508
509 if (so instanceof Folder && hasDescendant((Folder) so, targetFolder)) {
510 throw new CmisNotSupportedException("Destination of a move cannot be a subfolder of the source");
511 }
512
513 spo.move(sourceFolder, targetFolder);
514 objectId.setValue(so.getId());
515 LOG.debug("stop moveObject()");
516
517 TypeDefinition td = fStoreManager.getTypeById(repositoryId, so.getTypeId()).getTypeDefinition();
518 ObjectData od = PropertyCreationHelper.getObjectData(td, so, null, user, false,
519 IncludeRelationships.NONE, null, false, false, extension);
520
521
522
523 if (context.isObjectInfoRequired()) {
524 ObjectInfoImpl objectInfo = new ObjectInfoImpl();
525 fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, od, objectInfo);
526 objectInfos.addObjectInfo(objectInfo);
527 }
528
529 return od;
530 }
531
532 public void setContentStream(CallContext context, String repositoryId, Holder<String> objectId,
533 Boolean overwriteFlag, Holder<String> changeToken, ContentStream contentStream, ExtensionsData extension) {
534
535 LOG.debug("start setContentStream()");
536 Content content;
537 if ( null == overwriteFlag ) {
538 overwriteFlag = Boolean.TRUE;
539 }
540
541 StoredObject so = validator.setContentStream(context, repositoryId, objectId, overwriteFlag, extension);
542
543 if ( so.getChangeToken() != null && ( changeToken == null || !so.getChangeToken().equals( changeToken.getValue() ) ) )
544 throw new CmisUpdateConflictException( "setContentStream failed, ChangeToken does not match." );
545
546 if (!(so instanceof Document || so instanceof VersionedDocument || so instanceof DocumentVersion)) {
547 throw new CmisObjectNotFoundException("Id" + objectId
548 + " does not refer to a document, but only documents can have content");
549 }
550
551 if (so instanceof Document) {
552 content = ((Document) so);
553 } else if (so instanceof DocumentVersion) {
554
555
556 String user = context.getUsername();
557 testHasProperCheckedOutStatus(so, user);
558 content = (DocumentVersion) so;
559 } else {
560 throw new IllegalArgumentException("Content cannot be set on this object (must be document or version)");
561 }
562
563 if (!overwriteFlag && content.getContent(0, -1) != null) {
564 throw new CmisContentAlreadyExistsException("cannot overwrite existing content if overwrite flag is not set");
565 }
566
567 content.setContent(contentStream, true);
568 LOG.debug("stop setContentStream()");
569 }
570
571 public void updateProperties(CallContext context, String repositoryId, Holder<String> objectId,
572 Holder<String> changeToken, Properties properties, Acl acl, ExtensionsData extension,
573 ObjectInfoHandler objectInfos) {
574
575 LOG.debug("start updateProperties()");
576 StoredObject so = validator.updateProperties(context, repositoryId, objectId, extension);
577 String user = context.getUsername();
578
579
580 TypeDefinition typeDef = getTypeDefinition(repositoryId, so);
581 boolean isCheckedOut = false;
582
583 isCheckedOut = isCheckedOut(so, user);
584
585 Map<String, PropertyData<?>> oldProperties = so.getProperties();
586
587
588 TypeValidator.validateProperties(typeDef, properties, false);
589
590 if (changeToken != null && changeToken.getValue() != null
591 && Long.valueOf(so.getChangeToken()) > Long.valueOf(changeToken.getValue())) {
592 throw new CmisUpdateConflictException("updateProperties failed: changeToken does not match");
593 }
594
595
596 boolean hasUpdatedName = false;
597 boolean hasUpdatedOtherProps = false;
598
599 if(properties != null) {
600 for (String key : properties.getProperties().keySet()) {
601 if (key.equals(PropertyIds.NAME))
602 {
603 continue;
604 }
605
606 PropertyData<?> value = properties.getProperties().get(key);
607 PropertyDefinition<?> propDef = typeDef.getPropertyDefinitions().get(key);
608 if (value.getValues() == null || value.getFirstValue() == null) {
609
610
611 if (propDef.isRequired()) {
612 throw new CmisConstraintException(
613 "updateProperties failed, following property can't be deleted, because it is required: "
614 + key);
615 }
616 oldProperties.remove(key);
617 hasUpdatedOtherProps = true;
618 } else {
619 if (propDef.getUpdatability().equals(Updatability.WHENCHECKEDOUT)) {
620 if (!isCheckedOut)
621 throw new CmisUpdateConflictException(
622 "updateProperties failed, following property can't be updated, because it is not checked-out: "
623 + key);
624 } else if (!propDef.getUpdatability().equals(Updatability.READWRITE)) {
625 throw new CmisConstraintException(
626 "updateProperties failed, following property can't be updated, because it is not writable: "
627 + key);
628 }
629 oldProperties.put(key, value);
630 hasUpdatedOtherProps = true;
631 }
632 }
633
634
635
636 PropertyData<?> pd = properties.getProperties().get(PropertyIds.NAME);
637 if (pd != null && so instanceof Filing) {
638 String newName = (String) pd.getFirstValue();
639 List<Folder> parents = ((Filing) so).getParents(user);
640 if (so instanceof Folder && parents.isEmpty()) {
641 throw new CmisConstraintException("updateProperties failed, you cannot rename the root folder");
642 }
643 if (newName == null || newName.equals("")) {
644 throw new CmisConstraintException("updateProperties failed, name must not be empty.");
645 }
646
647 so.rename((String) pd.getFirstValue());
648 hasUpdatedName = true;
649 }
650 }
651
652 if (hasUpdatedOtherProps) {
653
654 if (user == null) {
655 user = "unknown";
656 }
657 so.updateSystemBasePropertiesWhenModified(properties.getProperties(), user);
658
659 so.persist();
660 }
661
662 if (hasUpdatedName || hasUpdatedOtherProps) {
663 objectId.setValue(so.getId());
664 if (null != changeToken) {
665 String changeTokenVal = so.getChangeToken();
666 LOG.debug("updateProperties(), new change token is: " + changeTokenVal);
667 changeToken.setValue(changeTokenVal);
668 }
669 }
670
671 if (null != acl) {
672 LOG.warn("Setting ACLs is currently not supported by this implementation, acl is ignored");
673
674
675
676
677 }
678
679 TypeDefinition td = fStoreManager.getTypeById(repositoryId, so.getTypeId()).getTypeDefinition();
680 ObjectData od = PropertyCreationHelper.getObjectData(td, so, null, user, false,
681 IncludeRelationships.NONE, null, false, false, extension);
682
683
684
685 if (context.isObjectInfoRequired()) {
686 ObjectInfoImpl objectInfo = new ObjectInfoImpl();
687 fAtomLinkProvider.fillInformationForAtomLinks(repositoryId, so, od, objectInfo);
688 objectInfos.addObjectInfo(objectInfo);
689 }
690
691 LOG.debug("stop updateProperties()");
692 }
693
694
695
696
697 private StoredObject createDocumentIntern(CallContext context, String repositoryId, Properties properties, String folderId,
698 ContentStream contentStream, VersioningState versioningState, List<String> policies, Acl addACEs,
699 Acl removeACEs, ExtensionsData extension) {
700
701 validator.createDocument(context, repositoryId, folderId, extension);
702
703
704 TypeValidator.validateRequiredSystemProperties(properties);
705
706 String user = context.getUsername();
707 TypeDefinition typeDef = getTypeDefinition(repositoryId, properties);
708
709 ObjectStore objectStore = fStoreManager.getObjectStore(repositoryId);
710 Map<String, PropertyData<?>> propMap = properties.getProperties();
711
712 PropertyData<?> pd = propMap.get(PropertyIds.NAME);
713 String name = (String) pd.getFirstValue();
714
715
716
717 TypeValidator.validateAcl(typeDef, addACEs, removeACEs);
718
719 Folder folder = null;
720 if (null != folderId) {
721 StoredObject so = objectStore.getObjectById(folderId);
722
723 if (null == so) {
724 throw new CmisInvalidArgumentException(" Cannot create document, folderId: " + folderId + " is invalid");
725 }
726
727 if (so instanceof Folder) {
728 folder = (Folder) so;
729 } else {
730 throw new CmisInvalidArgumentException("Can't creat document, folderId does not refer to a folder: "
731 + folderId);
732 }
733
734 TypeValidator.validateAllowedChildObjectTypes(typeDef, folder.getAllowedChildObjectTypeIds());
735 }
736
737
738 if (!typeDef.getBaseTypeId().equals(BaseTypeId.CMIS_DOCUMENT)) {
739 throw new CmisInvalidArgumentException("Cannot create a document, with a non-document type: " + typeDef.getId());
740 }
741
742
743 if (!NameValidator.isValidName(name)) {
744 throw new CmisInvalidArgumentException(NameValidator.ERROR_ILLEGAL_NAME);
745 }
746
747 TypeValidator.validateVersionStateForCreate((DocumentTypeDefinition) typeDef, versioningState);
748
749
750 Map<String, PropertyData<?>> propMapNew = setDefaultProperties(typeDef, propMap);
751 if (propMapNew != propMap) {
752 properties = new PropertiesImpl(propMapNew.values());
753 propMap = propMapNew;
754 }
755
756 TypeValidator.validateProperties(typeDef, properties, true);
757
758
759 if (user == null) {
760 user = "unknown";
761 }
762
763 StoredObject so = null;
764
765
766 if (null != contentStream && (contentStream.getFileName() == null || contentStream.getFileName().length() == 0 ||
767 contentStream.getMimeType() == null || contentStream.getMimeType().length() == 0)) {
768 ContentStreamImpl cs = new ContentStreamImpl();
769 cs.setStream(contentStream.getStream());
770 if (contentStream.getFileName() == null || contentStream.getFileName().length() == 0) {
771 cs.setFileName(name);
772 } else {
773 cs.setFileName(contentStream.getFileName());
774 }
775 cs.setLength(contentStream.getBigLength());
776 if (contentStream.getMimeType() == null || contentStream.getMimeType().length() == 0) {
777 cs.setMimeType("application/octet-stream");
778 } else {
779 cs.setMimeType(contentStream.getMimeType());
780 }
781 cs.setExtensions(contentStream.getExtensions());
782 contentStream = cs;
783 }
784
785
786 if (((DocumentTypeDefinition) typeDef).isVersionable()) {
787 DocumentVersion version = objectStore.createVersionedDocument(name, propMap,
788 user, folder, addACEs, removeACEs, contentStream, versioningState);
789 version.persist();
790 so = version;
791 } else {
792 Document doc = objectStore.createDocument(name, propMap, user, folder, addACEs, removeACEs);
793 doc.setContent(contentStream, false);
794 doc.persist();
795 so = doc;
796 }
797
798 return so;
799 }
800
801 private Folder createFolderIntern(CallContext context, String repositoryId, Properties properties, String folderId,
802 List<String> policies, Acl addACEs, Acl removeACEs, ExtensionsData extension) {
803
804 validator.createFolder(context, repositoryId, folderId, extension);
805 TypeValidator.validateRequiredSystemProperties(properties);
806 String user = context.getUsername();
807
808 ObjectStore fs = fStoreManager.getObjectStore(repositoryId);
809 StoredObject so = null;
810 Folder parent = null;
811
812
813 PropertyData<?> pd = properties.getProperties().get(PropertyIds.NAME);
814 String folderName = (String) pd.getFirstValue();
815 if (null == folderName || folderName.length() == 0) {
816 throw new CmisInvalidArgumentException("Cannot create a folder without a name.");
817 }
818
819
820 if (!NameValidator.isValidId(folderName)) {
821 throw new CmisInvalidArgumentException(NameValidator.ERROR_ILLEGAL_NAME);
822 }
823
824
825 TypeDefinition typeDef = getTypeDefinition(repositoryId, properties);
826
827
828 if (!typeDef.getBaseTypeId().equals(BaseTypeId.CMIS_FOLDER)) {
829 throw new CmisInvalidArgumentException("Cannot create a folder, with a non-folder type: " + typeDef.getId());
830 }
831
832 Map<String, PropertyData<?>> propMap = properties.getProperties();
833 Map<String, PropertyData<?>> propMapNew = setDefaultProperties(typeDef, propMap);
834 if (propMapNew != propMap) {
835 properties = new PropertiesImpl(propMapNew.values());
836 }
837
838 TypeValidator.validateProperties(typeDef, properties, true);
839
840
841 TypeValidator.validateAcl(typeDef, addACEs, removeACEs);
842
843
844 try {
845 LOG.debug("get folder for id: " + folderId);
846 so = fs.getObjectById(folderId);
847 } catch (Exception e) {
848 throw new CmisObjectNotFoundException("Failed to retrieve folder.", e);
849 }
850
851 if (so instanceof Folder) {
852 parent = (Folder) so;
853 } else {
854 throw new CmisInvalidArgumentException("Can't create folder, folderId does not refer to a folder: "
855 + folderId);
856 }
857
858 if (user == null) {
859 user = "unknown";
860 }
861
862 ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
863 Folder newFolder = objStore.createFolder(folderName, properties.getProperties(), user, parent,
864 addACEs, removeACEs);
865 LOG.debug("stop createFolder()");
866 newFolder.persist();
867 return newFolder;
868 }
869
870 private StoredObject createPolicyIntern(CallContext context, String repositoryId, Properties properties, String folderId,
871 List<String> policies, Acl addAces, Acl removeAces, ExtensionsData extension) {
872
873 validator.createPolicy(context, repositoryId, folderId, extension);
874 throw new CmisNotSupportedException("createPolicy is not supported.");
875 }
876
877 private StoredObject createRelationshipIntern(CallContext context, String repositoryId,
878 Properties properties, List<String> policies,
879 Acl addACEs, Acl removeACEs, ExtensionsData extension) {
880
881 TypeValidator.validateRequiredSystemProperties(properties);
882
883 String user = context.getUsername();
884
885
886 PropertyData<?> pd = properties.getProperties().get(PropertyIds.SOURCE_ID);
887 String sourceId = (String) pd.getFirstValue();
888 if (null == sourceId || sourceId.length() == 0)
889 throw new CmisInvalidArgumentException("Cannot create a relationship without a sourceId.");
890
891 pd = properties.getProperties().get(PropertyIds.TARGET_ID);
892 String targetId = (String) pd.getFirstValue();
893 if (null == targetId || targetId.length() == 0)
894 throw new CmisInvalidArgumentException("Cannot create a relationship without a targetId.");
895
896 RelationshipTypeDefinition typeDef = (RelationshipTypeDefinition) getTypeDefinition(repositoryId, properties);
897
898
899 if (!typeDef.getBaseTypeId().equals(BaseTypeId.CMIS_RELATIONSHIP))
900 throw new CmisInvalidArgumentException("Cannot create a relationship, with a non-relationship type: " + typeDef.getId());
901
902 StoredObject[] relationObjects = validator.createRelationship(context, repositoryId, sourceId, targetId, extension);
903
904
905
906 Map<String, PropertyData<?>> propMap = properties.getProperties();
907 Map<String, PropertyData<?>> propMapNew = setDefaultProperties(typeDef, propMap);
908 if (propMapNew != propMap) {
909 properties = new PropertiesImpl(propMapNew.values());
910 }
911
912 TypeValidator.validateProperties(typeDef, properties, true);
913
914
915 TypeValidator.validateAcl(typeDef, addACEs, removeACEs);
916
917
918 ObjectStore objStore = fStoreManager.getObjectStore(repositoryId);
919
920 TypeDefinition sourceTypeDef = fStoreManager.getTypeById(repositoryId, objStore.getObjectById(sourceId).getTypeId()).getTypeDefinition();
921 TypeDefinition targetTypeDef = fStoreManager.getTypeById(repositoryId, objStore.getObjectById(targetId).getTypeId()).getTypeDefinition();
922 TypeValidator.validateAllowedRelationshipTypes(typeDef, sourceTypeDef, targetTypeDef);
923
924 StoredObject storedObject = objStore.createRelationship( relationObjects[0], relationObjects[1],
925 propMap, user, addACEs, removeACEs);
926 return storedObject;
927 }
928
929
930 private static boolean hasDescendant(Folder sourceFolder, Folder targetFolder) {
931 String sourceId = sourceFolder.getId();
932 String targetId = targetFolder.getId();
933 while (targetId != null) {
934
935
936
937 if (targetId.equals(sourceId)) {
938 return true;
939 }
940 targetFolder = targetFolder.getParent();
941 if (null != targetFolder) {
942 targetId = targetFolder.getId();
943 } else {
944 targetId = null;
945 }
946 }
947 return false;
948 }
949
950
951
952
953
954
955
956
957
958
959
960
961
962 private boolean deleteRecursive(ObjectStore folderStore, Folder parentFolder, boolean continueOnFailure,
963 boolean allVersions, List<String> failedToDeleteIds, String user) {
964 List<StoredObject> children = parentFolder.getChildren(-1, -1, "Admin");
965
966 if (null == children) {
967 return true;
968 }
969
970 for (StoredObject child : children) {
971 if (child instanceof Folder) {
972 boolean mustContinue = deleteRecursive(folderStore, (Folder) child, continueOnFailure, allVersions,
973 failedToDeleteIds, user);
974 if (!mustContinue && !continueOnFailure)
975 {
976 return false;
977 }
978 } else {
979 try {
980 folderStore.deleteObject(child.getId(), allVersions, user);
981 } catch (Exception e) {
982 failedToDeleteIds.add(child.getId());
983 }
984 }
985 }
986 folderStore.deleteObject(parentFolder.getId(), allVersions, user);
987 return true;
988 }
989
990 private static ContentStream getContentStream(StoredObject so, String streamId, BigInteger offset, BigInteger length) {
991 if (streamId != null) {
992 return null;
993 }
994 long lOffset = offset == null ? 0 : offset.longValue();
995 long lLength = length == null ? -1 : length.longValue();
996 ContentStream csd = ((Content) so).getContent(lOffset, lLength);
997 return csd;
998 }
999
1000 private Map<String, PropertyData<?>> setDefaultProperties(TypeDefinition typeDef, Map<String, PropertyData<?>> properties) {
1001 Map<String, PropertyDefinition<?>> propDefs = typeDef.getPropertyDefinitions();
1002 boolean hasCopied = false;
1003
1004 for ( PropertyDefinition<?> propDef : propDefs.values()) {
1005 String propId = propDef.getId();
1006 List<?> defaultVal = propDef.getDefaultValue();
1007 if (defaultVal != null && null == properties.get(propId)) {
1008 if (!hasCopied) {
1009 properties = new HashMap<String, PropertyData<?>>(properties);
1010 hasCopied = true;
1011 }
1012 Object value = propDef.getCardinality() == Cardinality.SINGLE ? defaultVal.get(0)
1013 : defaultVal;
1014 PropertyData<?> pd = fStoreManager.getObjectFactory().createPropertyData(
1015 propDef, value);
1016
1017 properties.put(propId, pd);
1018 }
1019 }
1020 return properties;
1021 }
1022 }