This project has retired. For details please refer to its
Attic page.
ObjectStoreImpl 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.storedobj.impl;
20
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.locks.Lock;
27 import java.util.concurrent.locks.ReentrantLock;
28
29 import org.apache.chemistry.opencmis.commons.data.Ace;
30 import org.apache.chemistry.opencmis.commons.data.Acl;
31 import org.apache.chemistry.opencmis.commons.data.ContentStream;
32 import org.apache.chemistry.opencmis.commons.data.PropertyData;
33 import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
34 import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
35 import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
36 import org.apache.chemistry.opencmis.commons.enums.VersioningState;
37 import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
38 import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
39 import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException;
40 import org.apache.chemistry.opencmis.inmemory.storedobj.api.Document;
41 import org.apache.chemistry.opencmis.inmemory.storedobj.api.DocumentVersion;
42 import org.apache.chemistry.opencmis.inmemory.storedobj.api.Folder;
43 import org.apache.chemistry.opencmis.inmemory.storedobj.api.MultiFiling;
44 import org.apache.chemistry.opencmis.inmemory.storedobj.api.ObjectStore;
45 import org.apache.chemistry.opencmis.inmemory.storedobj.api.SingleFiling;
46 import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoredObject;
47 import org.apache.chemistry.opencmis.inmemory.storedobj.api.VersionedDocument;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 public class ObjectStoreImpl implements ObjectStore {
75
76
77
78
79
80 public static final String ADMIN_PRINCIPAL_ID = "Admin";
81
82
83
84
85 private static int NEXT_UNUSED_ID = 100;
86
87
88
89
90 private final Map<String, StoredObject> fStoredObjectMap = new ConcurrentHashMap<String, StoredObject>();
91
92
93
94
95 private int nextUnusedAclId = 0;
96
97 private final List<InMemoryAcl> fAcls = new ArrayList<InMemoryAcl>();
98
99 private final Lock fLock = new ReentrantLock();
100
101 final String fRepositoryId;
102 FolderImpl fRootFolder = null;
103
104 public ObjectStoreImpl(String repositoryId) {
105 fRepositoryId = repositoryId;
106 createRootFolder();
107 }
108
109 private static synchronized Integer getNextId() {
110 return NEXT_UNUSED_ID++;
111 }
112
113 private synchronized Integer getNextAclId() {
114 return nextUnusedAclId++;
115 }
116
117 public void lock() {
118 fLock.lock();
119 }
120
121 public void unlock() {
122 fLock.unlock();
123 }
124
125 public Folder getRootFolder() {
126 return fRootFolder;
127 }
128
129 public StoredObject getObjectByPath(String path, String user) {
130 for (StoredObject so : fStoredObjectMap.values()) {
131 if (so instanceof SingleFiling) {
132 String soPath = ((SingleFiling) so).getPath();
133 if (soPath.equals(path)) {
134 return so;
135 }
136 } else if (so instanceof MultiFiling) {
137 MultiFiling mfo = (MultiFiling) so;
138 List<Folder> parents = mfo.getParents(user);
139 for (Folder parent : parents) {
140 String parentPath = parent.getPath();
141 String mfPath = parentPath.equals(Folder.PATH_SEPARATOR) ? parentPath + mfo.getPathSegment()
142 : parentPath + Folder.PATH_SEPARATOR + mfo.getPathSegment();
143 if (mfPath.equals(path)) {
144 return so;
145 }
146 }
147 } else {
148 return null;
149 }
150 }
151 return null;
152 }
153
154 public StoredObject getObjectById(String objectId) {
155
156 StoredObject so = fStoredObjectMap.get(objectId);
157 return so;
158 }
159
160 public void deleteObject(String objectId, Boolean allVersions, String user) {
161 StoredObject obj = fStoredObjectMap.get(objectId);
162
163 if (null == obj) {
164 throw new RuntimeException("Cannot delete object with id " + objectId + ". Object does not exist.");
165 }
166
167 if (obj instanceof FolderImpl) {
168 deleteFolder(objectId, user);
169 } else if (obj instanceof DocumentVersion) {
170 DocumentVersion vers = (DocumentVersion) obj;
171 VersionedDocument parentDoc = vers.getParentDocument();
172 boolean otherVersionsExists;
173 if (allVersions != null && allVersions) {
174 otherVersionsExists = false;
175 List<DocumentVersion> allVers = parentDoc.getAllVersions();
176 for (DocumentVersion ver : allVers) {
177 fStoredObjectMap.remove(ver.getId());
178 }
179 } else {
180 fStoredObjectMap.remove(objectId);
181 otherVersionsExists = parentDoc.deleteVersion(vers);
182 }
183
184 if (!otherVersionsExists) {
185 fStoredObjectMap.remove(parentDoc.getId());
186 }
187 } else {
188 fStoredObjectMap.remove(objectId);
189 }
190 }
191
192 public void removeVersion(DocumentVersion vers) {
193 StoredObject found = fStoredObjectMap.remove(vers.getId());
194
195 if (null == found) {
196 throw new CmisInvalidArgumentException("Cannot delete object with id " + vers.getId() + ". Object does not exist.");
197 }
198 }
199
200 public String storeObject(StoredObject so) {
201 String id = so.getId();
202
203 if (null == id) {
204 id = getNextId().toString();
205 }
206 fStoredObjectMap.put(id, so);
207 return id;
208 }
209
210 StoredObject getObject(String id) {
211 return fStoredObjectMap.get(id);
212 }
213
214 void removeObject(String id) {
215 fStoredObjectMap.remove(id);
216 }
217
218 public Set<String> getIds() {
219 Set<String> entries = fStoredObjectMap.keySet();
220 return entries;
221 }
222
223
224
225
226 public void clear() {
227 lock();
228 fStoredObjectMap.clear();
229 storeObject(fRootFolder);
230 unlock();
231 }
232
233 public long getObjectCount() {
234 return fStoredObjectMap.size();
235 }
236
237
238
239
240 private void createRootFolder() {
241 FolderImpl rootFolder = new FolderImpl(this);
242 rootFolder.setName("RootFolder");
243 rootFolder.setParent(null);
244 rootFolder.setTypeId(BaseTypeId.CMIS_FOLDER.value());
245 rootFolder.setCreatedBy("Admin");
246 rootFolder.setModifiedBy("Admin");
247 rootFolder.setModifiedAtNow();
248 rootFolder.setRepositoryId(fRepositoryId);
249 rootFolder.setAclId(addAcl(InMemoryAcl.getDefaultAcl()));
250 rootFolder.persist();
251 fRootFolder = rootFolder;
252 }
253
254 public Document createDocument(String name,
255 Map<String, PropertyData<?>> propMap, String user, Folder folder,
256 Acl addACEs, Acl removeACEs) {
257 DocumentImpl doc = new DocumentImpl(this);
258 doc.createSystemBasePropertiesWhenCreated(propMap, user);
259 doc.setCustomProperties(propMap);
260 doc.setRepositoryId(fRepositoryId);
261 doc.setName(name);
262 if (null != folder) {
263 ((FolderImpl)folder).addChildDocument(doc);
264 }
265 int aclId = getAclId(((FolderImpl)folder), addACEs, removeACEs);
266 doc.setAclId(aclId);
267 return doc;
268 }
269
270 public DocumentVersion createVersionedDocument(String name,
271 Map<String, PropertyData<?>> propMap, String user, Folder folder,
272 Acl addACEs, Acl removeACEs, ContentStream contentStream, VersioningState versioningState) {
273 VersionedDocumentImpl doc = new VersionedDocumentImpl(this);
274 doc.createSystemBasePropertiesWhenCreated(propMap, user);
275 doc.setCustomProperties(propMap);
276 doc.setRepositoryId(fRepositoryId);
277 doc.setName(name);
278 DocumentVersion version = doc.addVersion(contentStream, versioningState, user);
279 if (null != folder) {
280 ((FolderImpl)folder).addChildDocument(doc);
281 }
282 version.createSystemBasePropertiesWhenCreated(propMap, user);
283 version.setCustomProperties(propMap);
284 int aclId = getAclId(((FolderImpl)folder), addACEs, removeACEs);
285 doc.setAclId(aclId);
286 doc.persist();
287 return version;
288 }
289
290 public Folder createFolder(String name,
291 Map<String, PropertyData<?>> propMap, String user, Folder parent,
292 Acl addACEs, Acl removeACEs) {
293
294 FolderImpl folder = new FolderImpl(this, name, null);
295 if (null != propMap) {
296 folder.createSystemBasePropertiesWhenCreated(propMap, user);
297 folder.setCustomProperties(propMap);
298 }
299 folder.setRepositoryId(fRepositoryId);
300 if (null != parent) {
301 ((FolderImpl)parent).addChildFolder(folder);
302 }
303
304 int aclId = getAclId(((FolderImpl)parent), addACEs, removeACEs);
305 folder.setAclId(aclId);
306
307 return folder;
308 }
309
310 public Folder createFolder(String name) {
311 Folder folder = new FolderImpl(this, name, null);
312 folder.setRepositoryId(fRepositoryId);
313 return folder;
314 }
315
316 public List<StoredObject> getCheckedOutDocuments(String orderBy,
317 String user, IncludeRelationships includeRelationships) {
318 List<StoredObject> res = new ArrayList<StoredObject>();
319
320 for (StoredObject so : fStoredObjectMap.values()) {
321 if (so instanceof VersionedDocument) {
322 VersionedDocument verDoc = (VersionedDocument) so;
323 if (verDoc.isCheckedOut() && hasReadAccess(user, verDoc)) {
324 res.add(verDoc.getPwc());
325 }
326 }
327 }
328
329 return res;
330 }
331
332 public StoredObject createRelationship(StoredObject sourceObject,
333 StoredObject targetObject, Map<String, PropertyData<?>> propMap,
334 String user, Acl addACEs, Acl removeACEs) {
335
336 return null;
337 }
338
339 public Acl applyAcl(StoredObject so, Acl addAces, Acl removeAces, AclPropagation aclPropagation, String principalId) {
340 if (aclPropagation==AclPropagation.OBJECTONLY || !(so instanceof Folder)) {
341 return applyAcl(so, addAces, removeAces);
342 } else {
343 return applyAclRecursive(((Folder)so), addAces, removeAces, principalId);
344 }
345 }
346
347 public Acl applyAcl(StoredObject so, Acl acl, AclPropagation aclPropagation, String principalId) {
348 if (aclPropagation==AclPropagation.OBJECTONLY || !(so instanceof Folder)) {
349 return applyAcl(so, acl);
350 } else {
351 return applyAclRecursive(((Folder)so), acl, principalId);
352 }
353 }
354
355 public List<Integer> getAllAclsForUser(String principalId, Permission permission) {
356 List<Integer> acls = new ArrayList<Integer>();
357 for (InMemoryAcl acl: fAcls) {
358 if (acl.hasPermission(principalId, permission))
359 acls.add(acl.getId());
360 }
361 return acls;
362 }
363
364 public Acl getAcl(int aclId) {
365 InMemoryAcl acl = getInMemoryAcl(aclId);
366 return acl==null ? InMemoryAcl.getDefaultAcl().toCommonsAcl() : acl.toCommonsAcl();
367 }
368
369 public int getAclId(StoredObjectImpl so, Acl addACEs, Acl removeACEs) {
370 InMemoryAcl newAcl;
371 boolean removeDefaultAcl = false;
372 int aclId = 0;
373
374 if (so == null) {
375 newAcl = new InMemoryAcl();
376 } else {
377 aclId = so.getAclId();
378 newAcl = getInMemoryAcl(aclId);
379 if (null == newAcl)
380 newAcl = new InMemoryAcl();
381 else
382
383 newAcl = new InMemoryAcl(newAcl.getAces());
384 }
385
386 if (newAcl.size() == 0 && addACEs == null && removeACEs == null)
387 return 0;
388
389 if (null != removeACEs)
390 for (Ace ace: removeACEs.getAces()) {
391 InMemoryAce inMemAce = new InMemoryAce(ace);
392 if (inMemAce.equals(InMemoryAce.getDefaultAce()))
393 removeDefaultAcl = true;
394 }
395
396 if ( so!= null && 0 == aclId && !removeDefaultAcl)
397 return 0;
398
399
400 if (null != addACEs)
401 for (Ace ace: addACEs.getAces()) {
402 InMemoryAce inMemAce = new InMemoryAce(ace);
403 if (inMemAce.equals(InMemoryAce.getDefaultAce()))
404 return 0;
405 newAcl.addAce(inMemAce);
406 }
407
408
409 if (null != removeACEs)
410 for (Ace ace: removeACEs.getAces()) {
411 InMemoryAce inMemAce = new InMemoryAce(ace);
412 newAcl.removeAce(inMemAce);
413 }
414
415 if (newAcl.size() > 0)
416 return addAcl(newAcl);
417 else
418 return 0;
419 }
420
421 private void deleteFolder(String folderId, String user) {
422 StoredObject folder = fStoredObjectMap.get(folderId);
423 if (folder == null) {
424 throw new CmisInvalidArgumentException("Unknown object with id: " + folderId);
425 }
426
427 if (!(folder instanceof FolderImpl)) {
428 throw new CmisInvalidArgumentException("Cannot delete folder with id: " + folderId
429 + ". Object exists but is not a folder.");
430 }
431
432
433 List<StoredObject> children = ((Folder) folder).getChildren(-1, -1, user);
434 if (children != null && !children.isEmpty()) {
435 throw new CmisConstraintException("Cannot delete folder with id: " + folderId + ". Folder is not empty.");
436 }
437
438 fStoredObjectMap.remove(folderId);
439 }
440
441 public boolean hasReadAccess(String principalId, StoredObject so) {
442 return hasAccess(principalId, so, Permission.READ);
443 }
444
445
446 public boolean hasWriteAccess(String principalId, StoredObject so) {
447 return hasAccess(principalId, so, Permission.WRITE);
448 }
449
450
451 public boolean hasAllAccess(String principalId, StoredObject so) {
452 return hasAccess(principalId, so, Permission.ALL);
453 }
454
455
456 public void checkReadAccess(String principalId, StoredObject so) {
457 checkAccess(principalId, so, Permission.READ);
458 }
459
460 public void checkWriteAccess(String principalId, StoredObject so) {
461 checkAccess(principalId, so, Permission.WRITE);
462 }
463
464 public void checkAllAccess(String principalId, StoredObject so) {
465 checkAccess(principalId, so, Permission.ALL);
466 }
467
468 private void checkAccess(String principalId, StoredObject so, Permission permission) {
469 if (!hasAccess(principalId, so, permission))
470 throw new CmisPermissionDeniedException("Object with id " + so.getId() + " and name " + so.getName()
471 + " does not grant " + permission.toString() + " access to principal " + principalId);
472 }
473
474 private boolean hasAccess(String principalId, StoredObject so, Permission permission) {
475 if (null != principalId && principalId.equals(ADMIN_PRINCIPAL_ID))
476 return true;
477 List<Integer> aclIds = getAllAclsForUser(principalId, permission);
478 return aclIds.contains(((StoredObjectImpl)so).getAclId());
479 }
480
481 private InMemoryAcl getInMemoryAcl(int aclId) {
482
483 for (InMemoryAcl acl : fAcls) {
484 if (aclId == acl.getId())
485 return acl;
486 }
487 return null;
488 }
489
490 private int setAcl(StoredObjectImpl so, Acl acl) {
491 int aclId;
492 if (null == acl || acl.getAces().isEmpty())
493 aclId = 0;
494 else {
495 aclId = getAclId(null, acl, null);
496 }
497 so.setAclId(aclId);
498 return aclId;
499 }
500
501
502
503
504
505
506
507
508 private int hasAcl(InMemoryAcl acl) {
509 for (InMemoryAcl acl2: fAcls) {
510 if (acl2.equals(acl))
511 return acl2.getId();
512 }
513 return -1;
514 }
515
516 private int addAcl(InMemoryAcl acl) {
517 int aclId = -1;
518
519 if (null == acl)
520 return 0;
521
522 lock();
523 try {
524 aclId = hasAcl(acl);
525 if (aclId < 0) {
526 aclId = getNextAclId();
527 acl.setId(aclId);
528 fAcls.add(acl);
529 }
530 } finally {
531 unlock();
532 }
533 return aclId;
534 }
535
536 private Acl applyAcl(StoredObject so, Acl acl) {
537 int aclId = setAcl((StoredObjectImpl) so, acl);
538 return getAcl(aclId);
539 }
540
541 private Acl applyAcl(StoredObject so, Acl addAces, Acl removeAces) {
542 int aclId = getAclId((StoredObjectImpl) so, addAces, removeAces);
543 ((StoredObjectImpl) so).setAclId(aclId);
544 return getAcl(aclId);
545 }
546
547 private Acl applyAclRecursive(Folder folder, Acl addAces, Acl removeAces, String principalId) {
548 List<StoredObject> children = folder.getChildren(-1, -1, ADMIN_PRINCIPAL_ID);
549
550 Acl result = applyAcl(folder, addAces, removeAces);
551
552 if (null == children) {
553 return result;
554 }
555
556 for (StoredObject child : children) {
557 if (hasAllAccess(principalId, child)) {
558 if (child instanceof Folder) {
559 applyAclRecursive((Folder) child, addAces, removeAces, principalId);
560 } else {
561 applyAcl(child, addAces, removeAces);
562 }
563 }
564 }
565
566 return result;
567 }
568
569 private Acl applyAclRecursive(Folder folder, Acl acl, String principalId) {
570 List<StoredObject> children = folder.getChildren(-1, -1, ADMIN_PRINCIPAL_ID);
571
572 Acl result = applyAcl(folder, acl);
573
574 if (null == children) {
575 return result;
576 }
577
578 for (StoredObject child : children) {
579 if (hasAllAccess(principalId, child)) {
580 if (child instanceof Folder) {
581 applyAclRecursive((Folder) child, acl, principalId);
582 } else {
583 applyAcl(child, acl);
584 }
585 }
586 }
587
588 return result;
589 }
590
591 public boolean isTypeInUse(String typeId) {
592
593 for (String objectId : getIds()) {
594 StoredObject so = getObjectById(objectId);
595 if (so.getTypeId().equals(typeId))
596 return true;
597 }
598 return false;
599 }
600
601 }