2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
24 package org.collectionspace.services.common.vocabulary.nuxeo;
26 import org.collectionspace.services.client.AuthorityClient;
27 import org.collectionspace.services.client.PayloadInputPart;
28 import org.collectionspace.services.client.PayloadOutputPart;
29 import org.collectionspace.services.client.PoxPayloadIn;
30 import org.collectionspace.services.client.PoxPayloadOut;
31 import org.collectionspace.services.client.RelationClient;
32 import org.collectionspace.services.common.api.CommonAPI;
33 import org.collectionspace.services.common.api.RefName;
34 import org.collectionspace.services.common.api.Tools;
35 import org.collectionspace.services.common.context.MultipartServiceContext;
36 import org.collectionspace.services.common.context.ServiceContext;
37 import org.collectionspace.services.common.document.DocumentWrapper;
38 import org.collectionspace.services.common.document.DocumentWrapperImpl;
39 import org.collectionspace.services.common.relation.IRelationsManager;
40 import org.collectionspace.services.common.repository.RepositoryClient;
41 import org.collectionspace.services.common.repository.RepositoryClientFactory;
42 import org.collectionspace.services.common.service.ObjectPartType;
43 import org.collectionspace.services.common.vocabulary.AuthorityJAXBSchema;
44 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
45 import org.collectionspace.services.nuxeo.client.java.DocHandlerBase;
46 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
47 import org.collectionspace.services.relation.RelationResource;
48 import org.collectionspace.services.relation.RelationsCommon;
49 import org.collectionspace.services.relation.RelationsCommonList;
50 import org.collectionspace.services.relation.RelationsDocListItem;
51 import org.collectionspace.services.relation.RelationshipType;
52 import org.nuxeo.ecm.core.api.DocumentModel;
53 import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 import javax.ws.rs.core.MultivaluedMap;
58 import javax.ws.rs.core.UriInfo;
59 import java.util.ArrayList;
60 import java.util.List;
62 import java.util.regex.Matcher;
63 import java.util.regex.Pattern;
65 //import org.collectionspace.services.common.authority.AuthorityItemRelations;
67 * AuthorityItemDocumentModelHandler
69 * $LastChangedRevision: $
72 public abstract class AuthorityItemDocumentModelHandler<AICommon>
73 extends DocHandlerBase<AICommon> {
75 private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
76 private String authorityItemCommonSchemaName;
78 * inVocabulary is the parent Authority for this context
80 protected String inAuthority;
81 protected String authorityRefNameBase;
83 public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) {
84 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
87 public String getInAuthority() {
91 public void setInAuthority(String inAuthority) {
92 this.inAuthority = inAuthority;
95 /** Subclasses may override this to customize the URI segment. */
96 public String getAuthorityServicePath() {
97 return getServiceContext().getServiceName().toLowerCase(); // Laramie20110510 CSPACE-3932
101 public String getUri(DocumentModel docModel) {
102 // Laramie20110510 CSPACE-3932
103 String authorityServicePath = getAuthorityServicePath();
104 return "/" + authorityServicePath + '/' + inAuthority + '/' + AuthorityClient.ITEMS + '/' + getCsid(docModel);
107 public String getAuthorityRefNameBase() {
108 return this.authorityRefNameBase;
111 public void setAuthorityRefNameBase(String value) {
112 this.authorityRefNameBase = value;
116 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
119 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
120 // first fill all the parts of the document
121 super.handleCreate(wrapDoc);
122 handleInAuthority(wrapDoc.getWrappedObject());
123 handleComputedDisplayNames(wrapDoc.getWrappedObject());
125 // Uncomment once debugged and App layer is read to integrate
126 // Experimenting with these uncommented now ...
127 handleDisplayNameAsShortIdentifier(wrapDoc.getWrappedObject(), authorityItemCommonSchemaName);
128 updateRefnameForAuthorityItem(wrapDoc, authorityItemCommonSchemaName, getAuthorityRefNameBase());
132 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleUpdate(org.collectionspace.services.common.document.DocumentWrapper)
135 public void handleUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
136 super.handleUpdate(wrapDoc);
137 handleComputedDisplayNames(wrapDoc.getWrappedObject());
141 * Handle display name.
143 * @param docModel the doc model
144 * @throws Exception the exception
146 protected void handleComputedDisplayNames(DocumentModel docModel) throws Exception {
147 // Do nothing by default.
150 private void handleDisplayNameAsShortIdentifier(DocumentModel docModel, String schemaName) throws Exception {
151 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
152 String displayName = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.DISPLAY_NAME);
153 String shortDisplayName = "";
155 shortDisplayName = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_DISPLAY_NAME);
156 } catch (PropertyNotFoundException pnfe) {
157 // Do nothing on exception. Some vocabulary schemas may not include a short display name.
159 if (Tools.isEmpty(shortIdentifier)) {
160 String generatedShortIdentifier = AuthorityIdentifierUtils.generateShortIdentifierFromDisplayName(displayName, shortDisplayName);
161 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER, generatedShortIdentifier);
165 protected void updateRefnameForAuthorityItem(DocumentWrapper<DocumentModel> wrapDoc,
167 String authorityRefBaseName) throws Exception {
168 DocumentModel docModel = wrapDoc.getWrappedObject();
169 String suppliedRefName = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME);
171 // Temporarily accept client-supplied refName values, rather than always generating such values.
172 // Remove the surrounding 'if' statement when clients should no longer supply refName values.
173 if (suppliedRefName == null || suppliedRefName.isEmpty()) {
174 String shortIdentifier = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.SHORT_IDENTIFIER);
175 String displayName = (String) docModel.getProperty(schemaName, AuthorityItemJAXBSchema.DISPLAY_NAME);
176 if (Tools.isEmpty(authorityRefBaseName)) {
177 throw new Exception("Could not create the refName for this authority term, because the refName for its authority parent was empty.");
179 RefName.Authority authority = RefName.Authority.parse(authorityRefBaseName);
180 String refName = RefName.buildAuthorityItem(authority, shortIdentifier, displayName).toString();
181 docModel.setProperty(schemaName, AuthorityItemJAXBSchema.REF_NAME, refName);
186 * Check the logic around the parent pointer. Note that we only need do this on
187 * create, since we have logic to make this read-only on update.
191 * @throws Exception the exception
193 private void handleInAuthority(DocumentModel docModel) throws Exception {
194 docModel.setProperty(authorityItemCommonSchemaName,
195 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
200 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
203 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
205 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
207 // Add the CSID to the common part
208 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
209 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
210 unQObjectProperties.put("csid", csid);
213 return unQObjectProperties;
217 * Filters out selected values supplied in an update request.
219 * For example, filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure
220 * that the link to the item's parent remains untouched.
222 * @param objectProps the properties filtered out from the update payload
223 * @param partMeta metadata for the object to fill
226 public void filterReadOnlyPropertiesForPart(
227 Map<String, Object> objectProps, ObjectPartType partMeta) {
228 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
229 String commonPartLabel = getServiceContext().getCommonPartLabel();
230 if (partMeta.getLabel().equalsIgnoreCase(commonPartLabel)) {
231 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
232 objectProps.remove(AuthorityItemJAXBSchema.CSID);
233 objectProps.remove(AuthorityJAXBSchema.SHORT_IDENTIFIER);
234 // Enable when clients should no longer supply refName values
235 // objectProps.remove(AuthorityItemJAXBSchema.REF_NAME); // CSPACE-3178
241 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
242 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
243 super.extractAllParts(wrapDoc);
245 String showSiblings = ctx.getQueryParams().getFirst(CommonAPI.showSiblings_QP);
246 if (Tools.isTrue(showSiblings)) {
247 showSiblings(wrapDoc, ctx);
248 return; // actual result is returned on ctx.addOutputPart();
251 String showRelations = ctx.getQueryParams().getFirst(CommonAPI.showRelations_QP);
252 if (Tools.isTrue(showRelations)) {
253 showRelations(wrapDoc, ctx);
254 return; // actual result is returned on ctx.addOutputPart();
257 String showAllRelations = ctx.getQueryParams().getFirst(CommonAPI.showAllRelations_QP);
258 if (Tools.isTrue(showAllRelations)) {
259 showAllRelations(wrapDoc, ctx);
260 return; // actual result is returned on ctx.addOutputPart();
264 /** @return null on parent not found
266 protected String getParentCSID(String thisCSID) throws Exception {
267 String parentCSID = null;
269 String predicate = RelationshipType.HAS_BROADER.value();
270 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
271 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
272 if (parentList != null) {
273 if (parentList.size() == 0) {
276 RelationsCommonList.RelationListItem relationListItem = parentList.get(0);
277 parentCSID = relationListItem.getObjectCsid();
280 } catch (Exception e) {
281 logger.error("Could not find parent for this: " + thisCSID, e);
286 public void showRelations(DocumentWrapper<DocumentModel> wrapDoc,
287 MultipartServiceContext ctx) throws Exception {
288 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
290 String predicate = RelationshipType.HAS_BROADER.value();
291 RelationsCommonList parentListOuter = getRelations(thisCSID, null, predicate);
292 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
294 RelationsCommonList childrenListOuter = getRelations(null, thisCSID, predicate);
295 List<RelationsCommonList.RelationListItem> childrenList = childrenListOuter.getRelationListItem();
297 //Assume that there are more children than parents. Will be true for parent/child, but maybe not for other relations.
298 //Now add all parents to our childrenList, to be able to return just one list of consolidated results.
299 //Not optimal, but that's the current design spec.
301 for (RelationsCommonList.RelationListItem parent : parentList) {
302 childrenList.add(parent);
305 long childrenSize = childrenList.size();
306 childrenListOuter.setTotalItems(childrenSize);
307 childrenListOuter.setItemsInPage(childrenListOuter.getItemsInPage() + added);
309 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, childrenListOuter);
310 ctx.addOutputPart(relationsPart);
313 public void showSiblings(DocumentWrapper<DocumentModel> wrapDoc,
314 MultipartServiceContext ctx) throws Exception {
315 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
316 String parentCSID = getParentCSID(thisCSID);
317 if (parentCSID == null) {
318 logger.warn("~~~~~\r\n~~~~ Could not find parent for this: " + thisCSID);
322 String predicate = RelationshipType.HAS_BROADER.value();
323 RelationsCommonList siblingListOuter = getRelations(null, parentCSID, predicate);
324 List<RelationsCommonList.RelationListItem> siblingList = siblingListOuter.getRelationListItem();
326 List<RelationsCommonList.RelationListItem> toRemoveList = newList();
329 RelationsCommonList.RelationListItem item = null;
330 for (RelationsCommonList.RelationListItem sibling : siblingList) {
331 if (thisCSID.equals(sibling.getSubjectCsid())) {
332 toRemoveList.add(sibling); //IS_A copy of the main item, i.e. I have a parent that is my parent, so I'm in the list from the above query.
335 //rather than create an immutable iterator, I'm just putting the items to remove on a separate list, then looping over that list and removing.
336 for (RelationsCommonList.RelationListItem self : toRemoveList) {
337 removeFromList(siblingList, self);
340 long siblingSize = siblingList.size();
341 siblingListOuter.setTotalItems(siblingSize);
342 siblingListOuter.setItemsInPage(siblingSize);
344 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, siblingListOuter);
345 ctx.addOutputPart(relationsPart);
348 public void showAllRelations(DocumentWrapper<DocumentModel> wrapDoc, MultipartServiceContext ctx) throws Exception {
349 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
351 RelationsCommonList subjectListOuter = getRelations(thisCSID, null, null); // nulls are wildcards: predicate=*, and object=*
352 List<RelationsCommonList.RelationListItem> subjectList = subjectListOuter.getRelationListItem();
354 RelationsCommonList objectListOuter = getRelations(null, thisCSID, null); // nulls are wildcards: subject=*, and predicate=*
355 List<RelationsCommonList.RelationListItem> objectList = objectListOuter.getRelationListItem();
358 subjectList.addAll(objectList);
360 //now subjectList actually has records BOTH where thisCSID is subject and object.
361 long relatedSize = subjectList.size();
362 subjectListOuter.setTotalItems(relatedSize);
363 subjectListOuter.setItemsInPage(relatedSize);
365 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, subjectListOuter);
366 ctx.addOutputPart(relationsPart);
369 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
370 super.fillAllParts(wrapDoc, action);
371 ServiceContext ctx = getServiceContext();
372 PoxPayloadIn input = (PoxPayloadIn) ctx.getInput();
373 DocumentModel documentModel = (wrapDoc.getWrappedObject());
374 String itemCsid = documentModel.getName();
376 //UPDATE and CREATE will call. Updates relations part
377 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input, wrapDoc);
379 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
380 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
383 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
384 super.completeUpdate(wrapDoc);
385 //now we add part for relations list
386 ServiceContext ctx = getServiceContext();
387 PayloadOutputPart foo = (PayloadOutputPart) ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
388 ((PoxPayloadOut) ctx.getOutput()).addPart(foo);
391 /** updateRelations strategy:
393 go through inboundList, remove anything from childList that matches from childList
394 go through inboundList, remove anything from parentList that matches from parentList
395 go through parentList, delete all remaining
396 go through childList, delete all remaining
397 go through actionList, add all remaining.
398 check for duplicate children
399 check for more than one parent.
401 inboundList parentList childList actionList
402 ---------------- --------------- ---------------- ----------------
403 child-a parent-c child-a child-b
404 child-b parent-d child-c
407 public RelationsCommonList updateRelations(String itemCSID, PoxPayloadIn input, DocumentWrapper<DocumentModel> wrapDoc)
409 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
411 return null; //nothing to do--they didn't send a list of relations.
413 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
415 ServiceContext ctx = getServiceContext();
416 UriInfo uriInfo = ctx.getUriInfo();
417 MultivaluedMap queryParams = uriInfo.getQueryParameters();
419 //Run getList() once as sent to get childListOuter:
420 String predicate = RelationshipType.HAS_BROADER.value();
421 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
422 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
423 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
424 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
425 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
426 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
428 //Now run getList() again, leaving predicate, swapping subject and object, to get parentListOuter.
429 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
430 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
431 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
432 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
434 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
436 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
437 List<RelationsCommonList.RelationListItem> actionList = newList();
438 List<RelationsCommonList.RelationListItem> childList = childListOuter.getRelationListItem();
439 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
441 if (parentList.size() > 1) {
442 throw new Exception("Too many parents for object: " + itemCSID + " list: " + dumpList(parentList, "parentList"));
445 DocumentModel docModel = wrapDoc.getWrappedObject();
447 //Do magic replacement of ${itemCSID} and fix URI's.
448 fixupInboundListItems(ctx, inboundList, docModel, itemCSID);
450 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
451 if (inboundItem.getObject().getCsid().equals(itemCSID) && inboundItem.getPredicate().equals(HAS_BROADER)) {
452 //then this is an item that says we have a child. That child is inboundItem
453 RelationsCommonList.RelationListItem childItem = findInList(childList, inboundItem);
454 if (childItem != null) {
455 removeFromList(childList, childItem); //exists, just take it off delete list
457 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
459 ensureChildHasNoOtherParents(ctx, queryParams, inboundItem.getSubject().getCsid());
461 } else if (inboundItem.getSubject().getCsid().equals(itemCSID) && inboundItem.getPredicate().equals(HAS_BROADER)) {
462 //then this is an item that says we have a parent. inboundItem is that parent.
463 RelationsCommonList.RelationListItem parentItem = findInList(parentList, inboundItem);
464 if (parentItem != null) {
465 removeFromList(parentList, parentItem); //exists, just take it off delete list
467 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
470 logger.warn("Element didn't match parent or child, but may have partial fields that match. inboundItem: " + inboundItem);
471 //not dealing with: hasNarrower or any other predicate.
474 String dump = dumpLists(itemCSID, parentList, childList, actionList);
475 //System.out.println("====dump====="+CR+dump);
476 logger.info("~~~~~~~~~~~~~~~~~~~~~~dump~~~~~~~~~~~~~~~~~~~~~~~~" + CR + dump);
477 deleteRelations(parentList, ctx, "parentList"); //todo: there are items appearing on both lists....april 20.
478 deleteRelations(childList, ctx, "childList");
479 createRelations(actionList, ctx);
480 //We return all elements on the inbound list, since we have just worked to make them exist in the system
481 // and be non-redundant, etc. That list came from relationsCommonListBody, so it is still attached to it, just pass that back.
482 return relationsCommonListBody;
485 private void ensureChildHasNoOtherParents(ServiceContext ctx, MultivaluedMap queryParams, String childCSID) {
486 queryParams.putSingle(IRelationsManager.SUBJECT_QP, childCSID);
487 queryParams.putSingle(IRelationsManager.PREDICATE_QP, RelationshipType.HAS_BROADER.value());
488 queryParams.putSingle(IRelationsManager.OBJECT_QP, null); //null means ANY
489 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
490 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
491 //logger.warn("ensureChildHasNoOtherParents preparing to delete relations on "+childCSID+"\'s parent list: \r\n"+dumpList(parentList, "duplicate parent list"));
492 deleteRelations(parentList, ctx, "parentList-delete");
495 private String dumpLists(String itemCSID,
496 List<RelationsCommonList.RelationListItem> parentList,
497 List<RelationsCommonList.RelationListItem> childList,
498 List<RelationsCommonList.RelationListItem> actionList) {
499 StringBuffer sb = new StringBuffer();
500 sb.append("itemCSID: " + itemCSID + CR);
501 sb.append(dumpList(parentList, "parentList"));
502 sb.append(dumpList(childList, "childList"));
503 sb.append(dumpList(actionList, "actionList"));
504 return sb.toString();
506 private final static String CR = "\r\n";
507 private final static String T = " ";
509 private String dumpList(List<RelationsCommonList.RelationListItem> list, String label) {
510 StringBuffer sb = new StringBuffer();
512 if (list.size() > 0) {
513 sb.append("=========== " + label + " ==========" + CR);
515 for (RelationsCommonList.RelationListItem item : list) {
517 T + item.getSubject().getCsid() //+T4 + item.getSubject().getUri()
518 + T + item.getPredicate()
519 + T + item.getObject().getCsid() //+T4 + item.getObject().getUri()
520 + CR //+"subject:{"+item.getSubject()+"}\r\n object:{"+item.getObject()+"}"
521 //+ CR + "relation-record: {"+item+"}"
526 return sb.toString();
529 /** Performs substitution for ${itemCSID} (see CommonAPI.AuthorityItemCSID_REPLACE for constant)
530 * and sets URI correctly for related items.
531 * Operates directly on the items in the list. Does not change the list ordering, does not add or remove any items.
533 protected void fixupInboundListItems(ServiceContext ctx,
534 List<RelationsCommonList.RelationListItem> inboundList,
535 DocumentModel docModel,
536 String itemCSID) throws Exception {
537 String thisURI = this.getUri(docModel);
538 // WARNING: the two code blocks below are almost identical and seem to ask to be put in a generic method.
539 // beware of the little diffs in inboundItem.setObjectCsid(itemCSID); and inboundItem.setSubjectCsid(itemCSID); in the two blocks.
540 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
541 RelationsDocListItem inboundItemObject = inboundItem.getObject();
542 RelationsDocListItem inboundItemSubject = inboundItem.getSubject();
544 if (inboundItemObject.getCsid().equalsIgnoreCase(CommonAPI.AuthorityItemCSID_REPLACE)) {
545 inboundItem.setObjectCsid(itemCSID);
546 inboundItemObject.setCsid(itemCSID);
547 inboundItemObject.setUri(getUri(docModel));
549 String objectCsid = inboundItemObject.getCsid();
550 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, objectCsid); //null if not found.
551 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
552 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
553 inboundItemObject.setUri(uri); //CSPACE-4037
555 uriPointsToSameAuthority(thisURI, inboundItemObject.getUri()); //CSPACE-4042
557 if (inboundItemSubject.getCsid().equalsIgnoreCase(CommonAPI.AuthorityItemCSID_REPLACE)) {
558 inboundItem.setSubjectCsid(itemCSID);
559 inboundItemSubject.setCsid(itemCSID);
560 inboundItemSubject.setUri(getUri(docModel));
562 String subjectCsid = inboundItemSubject.getCsid();
563 DocumentModel itemDocModel = NuxeoUtils.getDocFromCsid(getRepositorySession(), ctx, subjectCsid); //null if not found.
564 DocumentWrapper wrapper = new DocumentWrapperImpl(itemDocModel);
565 String uri = this.getRepositoryClient(ctx).getDocURI(wrapper);
566 inboundItemSubject.setUri(uri); //CSPACE-4037
568 uriPointsToSameAuthority(thisURI, inboundItemSubject.getUri()); //CSPACE-4042
573 public RepositoryClient getRepositoryClient(ServiceContext ctx) {
574 RepositoryClient repositoryClient = RepositoryClientFactory.getInstance().getClient(ctx.getRepositoryClientName());
575 return repositoryClient;
578 // this method calls the RelationResource to have it create the relations and persist them.
579 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx) {
580 for (RelationsCommonList.RelationListItem item : inboundList) {
581 RelationsCommon rc = new RelationsCommon();
582 //rc.setCsid(item.getCsid());
583 //todo: assignTo(item, rc);
584 RelationsDocListItem itemSubject = item.getSubject();
585 RelationsDocListItem itemObject = item.getObject();
587 String subjectCsid = itemSubject.getCsid();
588 rc.setDocumentId1(subjectCsid);
589 rc.setSubjectCsid(subjectCsid);
591 String objCsid = item.getObject().getCsid();
592 rc.setDocumentId2(objCsid);
593 rc.setObjectCsid(objCsid);
595 rc.setRelationshipType(item.getPredicate());
596 //RelationshipType foo = (RelationshipType.valueOf(item.getPredicate())) ;
597 //rc.setPredicate(foo); //this must be one of the type found in the enum in services/jaxb/src/main/resources/relations_common.xsd
599 rc.setDocumentType1(itemSubject.getDocumentType());
600 rc.setDocumentType2(itemObject.getDocumentType());
602 rc.setSubjectUri(itemSubject.getUri());
603 rc.setObjectUri(itemObject.getUri());
606 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
607 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
608 payloadOut.addPart(outputPart);
609 //System.out.println("\r\n==== TO CREATE: "+rc.getDocumentId1()+"==>"+rc.getPredicate()+"==>"+rc.getDocumentId2());
610 RelationResource relationResource = new RelationResource();
611 Object res = relationResource.create(ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
615 private void deleteRelations(List<RelationsCommonList.RelationListItem> list, ServiceContext ctx, String listName) {
617 //if (list.size()>0){ logger.info("==== deleteRelations from : "+listName); }
618 for (RelationsCommonList.RelationListItem item : list) {
619 RelationResource relationResource = new RelationResource();
620 //logger.info("==== TO DELETE: " + item.getCsid() + ": " + item.getSubject().getCsid() + "--" + item.getPredicate() + "-->" + item.getObject().getCsid());
621 Object res = relationResource.delete(item.getCsid());
623 } catch (Throwable t) {
624 String msg = "Unable to deleteRelations: " + Tools.errorToString(t, true);
629 private List<RelationsCommonList.RelationListItem> newList() {
630 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
634 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList) {
635 List<RelationsCommonList.RelationListItem> result = newList();
636 for (RelationsCommonList.RelationListItem item : inboundList) {
642 private RelationsCommonList.RelationListItem findInList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
643 for (RelationsCommonList.RelationListItem listItem : list) {
644 if (itemsEqual(listItem, item)) { //equals must be defined, else
651 private boolean itemsEqual(RelationsCommonList.RelationListItem item, RelationsCommonList.RelationListItem item2) {
652 if (item == null || item2 == null) {
655 RelationsDocListItem subj1 = item.getSubject();
656 RelationsDocListItem subj2 = item2.getSubject();
657 RelationsDocListItem obj1 = item.getObject();
658 RelationsDocListItem obj2 = item2.getObject();
660 return (subj1.getCsid().equals(subj2.getCsid()))
661 && (obj1.getCsid().equals(obj1.getCsid()))
662 && ((item.getPredicate().equals(item2.getPredicate()))
663 && (item.getRelationshipType().equals(item2.getRelationshipType())))
664 && (obj1.getDocumentType().equals(obj2.getDocumentType()))
665 && (subj1.getDocumentType().equals(subj2.getDocumentType()));
668 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item) {
672 /* don't even THINK of re-using this method.
673 * String example_uri = "/locationauthorities/7ec60f01-84ab-4908-9a6a/items/a5466530-713f-43b4-bc05";
675 private String extractInAuthorityCSID(String uri) {
676 String IN_AUTHORITY_REGEX = "/(.*?)/(.*?)/(.*)";
677 Pattern p = Pattern.compile(IN_AUTHORITY_REGEX);
678 Matcher m = p.matcher(uri);
680 if (m.groupCount() < 3) {
681 logger.warn("REGEX-WRONG-GROUPCOUNT looking in " + uri);
684 //String service = m.group(1);
685 String inauth = m.group(2);
686 //String theRest = m.group(3);
688 //print("service:"+service+", inauth:"+inauth+", rest:"+rest);
691 logger.warn("REGEX-NOT-MATCHED looking in " + uri);
696 //ensures CSPACE-4042
697 protected void uriPointsToSameAuthority(String thisURI, String inboundItemURI) throws Exception {
698 String authorityCSID = extractInAuthorityCSID(thisURI);
699 String authorityCSIDForInbound = extractInAuthorityCSID(inboundItemURI);
700 if (Tools.isBlank(authorityCSID)
701 || Tools.isBlank(authorityCSIDForInbound)
702 || (!authorityCSID.equalsIgnoreCase(authorityCSIDForInbound))) {
703 throw new Exception("Item URI " + thisURI + " must point to same authority as related item: " + inboundItemURI);
707 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
708 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
709 ServiceContext ctx = getServiceContext();
710 MultivaluedMap queryParams = ctx.getQueryParams();
711 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
712 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
713 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
715 RelationResource relationResource = new RelationResource();
716 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
717 return relationsCommonList;
719 //============================= END TODO refactor ==========================