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 java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.ListIterator;
33 import org.collectionspace.services.client.PayloadInputPart;
34 import org.collectionspace.services.client.PayloadOutputPart;
35 import org.collectionspace.services.client.PoxPayloadIn;
36 import org.collectionspace.services.client.PoxPayloadOut;
37 import org.collectionspace.services.client.RelationClient;
38 //import org.collectionspace.services.common.authority.AuthorityItemRelations;
39 import org.collectionspace.services.common.api.Tools;
40 import org.collectionspace.services.common.context.MultipartServiceContext;
41 import org.collectionspace.services.common.context.ServiceContext;
42 import org.collectionspace.services.common.document.DocumentWrapper;
43 import org.collectionspace.services.common.relation.IRelationsManager;
44 import org.collectionspace.services.common.service.ObjectPartType;
45 import org.collectionspace.services.common.vocabulary.AuthorityItemJAXBSchema;
46 import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
47 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
48 import org.collectionspace.services.relation.RelationResource;
49 import org.collectionspace.services.relation.RelationsCommon;
50 import org.collectionspace.services.relation.RelationsCommonList;
51 import org.collectionspace.services.relation.RelationsDocListItem;
52 import org.collectionspace.services.relation.RelationshipType;
53 import org.nuxeo.ecm.core.api.DocumentModel;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 import javax.ws.rs.core.MultivaluedMap;
58 import javax.ws.rs.core.UriInfo;
61 * AuthorityItemDocumentModelHandler
63 * $LastChangedRevision: $
66 public abstract class AuthorityItemDocumentModelHandler<AICommon, AICommonList>
67 extends RemoteDocumentModelHandlerImpl<AICommon, AICommonList> {
69 private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
71 private String authorityItemCommonSchemaName;
73 //private final Logger logger = LoggerFactory.getLogger(AuthorityItemDocumentModelHandler.class);
75 * item is used to stash JAXB object to use when handle is called
76 * for Action.CREATE, Action.UPDATE or Action.GET
78 protected AICommon item;
80 * itemList is stashed when handle is called
83 protected AICommonList itemList;
86 * inVocabulary is the parent Authority for this context
88 protected String inAuthority;
90 public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) {
91 this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
94 public String getInAuthority() {
98 public void setInAuthority(String inAuthority) {
99 this.inAuthority = inAuthority;
103 * @see org.collectionspace.services.nuxeo.client.java.DocumentModelHandler#handleCreate(org.collectionspace.services.common.document.DocumentWrapper)
106 public void handleCreate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
107 // first fill all the parts of the document
108 super.handleCreate(wrapDoc);
109 handleInAuthority(wrapDoc.getWrappedObject());
113 * Check the logic around the parent pointer. Note that we only need do this on
114 * create, since we have logic to make this read-only on update.
118 * @throws Exception the exception
120 private void handleInAuthority(DocumentModel docModel) throws Exception {
121 docModel.setProperty(authorityItemCommonSchemaName,
122 AuthorityItemJAXBSchema.IN_AUTHORITY, inAuthority);
127 * getCommonPart get associated item
131 public AICommon getCommonPart() {
136 public void setCommonPart(AICommon item) {
141 * getCommonPartList get associated item (for index/GET_ALL)
145 public AICommonList getCommonPartList() {
150 public void setCommonPartList(AICommonList itemList) {
151 this.itemList = itemList;
155 public AICommon extractCommonPart(DocumentWrapper<DocumentModel> wrapDoc)
157 throw new UnsupportedOperationException();
161 public void fillCommonPart(AICommon itemObject, DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
162 throw new UnsupportedOperationException();
166 * @see org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl#extractPart(org.nuxeo.ecm.core.api.DocumentModel, java.lang.String, org.collectionspace.services.common.service.ObjectPartType)
169 protected Map<String, Object> extractPart(DocumentModel docModel, String schema, ObjectPartType partMeta)
171 Map<String, Object> unQObjectProperties = super.extractPart(docModel, schema, partMeta);
173 // Add the CSID to the common part
174 if (partMeta.getLabel().equalsIgnoreCase(authorityItemCommonSchemaName)) {
175 String csid = getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
176 unQObjectProperties.put("csid", csid);
179 return unQObjectProperties;
183 * Filters out AuthorityItemJAXBSchema.IN_AUTHORITY, to ensure that
184 * the parent link remains untouched.
185 * @param objectProps the properties parsed from the update payload
186 * @param partMeta metadata for the object to fill
189 public void filterReadOnlyPropertiesForPart(
190 Map<String, Object> objectProps, ObjectPartType partMeta) {
191 super.filterReadOnlyPropertiesForPart(objectProps, partMeta);
192 objectProps.remove(AuthorityItemJAXBSchema.IN_AUTHORITY);
193 objectProps.remove(AuthorityItemJAXBSchema.CSID);
197 public void extractAllParts(DocumentWrapper<DocumentModel> wrapDoc)
199 MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
200 super.extractAllParts(wrapDoc);
202 String thisCSID = NuxeoUtils.getCsid(wrapDoc.getWrappedObject());
204 //TODO: add broader, etc. here.
205 String predicate = RelationshipType.HAS_BROADER.value();
206 RelationsCommonList relationsCommonList = getRelations(thisCSID, null, predicate);
207 if (relationsCommonList.getTotalItems() == 0){
208 relationsCommonList = getRelations(null, thisCSID, predicate); //for development... try switching subject and object. This is not correct, though.
210 PayloadOutputPart relationsPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
211 ctx.addOutputPart(relationsPart);
214 public void fillAllParts(DocumentWrapper<DocumentModel> wrapDoc, Action action) throws Exception {
215 super.fillAllParts(wrapDoc, action);
216 ServiceContext ctx = getServiceContext();
217 PoxPayloadIn input = (PoxPayloadIn)ctx.getInput();
218 DocumentModel documentModel = (wrapDoc.getWrappedObject());
219 String itemCsid = documentModel.getName();
221 //TODO: create all relations.... UPDATE and CREATE will call. Updates AuthorityItem part
222 RelationsCommonList relationsCommonList = updateRelations(itemCsid, input);
223 PayloadOutputPart payloadOutputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMON_LIST_NAME, relationsCommonList);
224 ctx.setProperty(RelationClient.SERVICE_COMMON_LIST_NAME, payloadOutputPart);
227 public void completeUpdate(DocumentWrapper<DocumentModel> wrapDoc) throws Exception {
228 super.completeUpdate(wrapDoc);
229 //now we add part for relations list
230 ServiceContext ctx = getServiceContext();
231 PayloadOutputPart foo = (PayloadOutputPart)ctx.getProperty(RelationClient.SERVICE_COMMON_LIST_NAME);
232 ((PoxPayloadOut)ctx.getOutput()).addPart(foo);
235 //===================================================================
237 for (RelationsCommonList.RelationListItem parentListItem : parentList.getRelationListItem()) {
238 System.out.println(" parentListItems " + parentListItem);
239 //todo: if num-parents > 1 then complain.
240 //todo: if not found in update list, remove from system
241 //todo: if update list item not found in parent list, add to system.
243 for (RelationsCommonList.RelationListItem childListItem : childList.getRelationListItem()) {
244 System.out.println(" childListItem: " + childListItem);
245 //todo: if not found in update list, remove from system
246 //todo: if update list item not found in child list, add to system.
252 public RelationsCommonList updateRelations(String itemCSID, PoxPayloadIn input) throws Exception {
253 PayloadInputPart part = input.getPart(RelationClient.SERVICE_COMMON_LIST_NAME); //input.getPart("relations_common");
255 System.out.println("Nothing to do in updateRelations: " + input);
258 RelationsCommonList relationsCommonListBody = (RelationsCommonList) part.getBody();
260 ServiceContext ctx = getServiceContext();
261 MultivaluedMap queryParams = ctx.getQueryParams();
262 String predicate = RelationshipType.HAS_BROADER.value();
263 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
264 queryParams.putSingle(IRelationsManager.SUBJECT_QP, null);
265 queryParams.putSingle(IRelationsManager.SUBJECT_TYPE_QP, null);
266 queryParams.putSingle(IRelationsManager.OBJECT_QP, itemCSID);
267 queryParams.putSingle(IRelationsManager.OBJECT_TYPE_QP, null);
269 RelationsCommonList childListOuter = (new RelationResource()).getList(ctx.getUriInfo()); //magically knows all query params because they are in the context.
271 //Leave predicate, swap subject and object.
272 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
273 queryParams.putSingle(IRelationsManager.SUBJECT_QP, itemCSID);
274 queryParams.putSingle(IRelationsManager.OBJECT_QP, null);
276 RelationsCommonList parentListOuter = (new RelationResource()).getList(ctx.getUriInfo());
278 go through inboundList, remove anything from childList that matches from childList
279 go through inboundList, remove anything from parentList that matches from parentList
280 go through parentList, delete all remaining
281 go through childList, delete all remaining
282 go through actionList, add all remaining.
283 check for duplicate children
284 check for more than one parent.
286 inboundList parentList childList actionList
287 ---------------- --------------- ---------------- ----------------
288 child-a parent-c child-a child-b
289 child-b parent-d child-c
292 String HAS_BROADER = RelationshipType.HAS_BROADER.value();
294 List<RelationsCommonList.RelationListItem> inboundList = relationsCommonListBody.getRelationListItem();
295 List<RelationsCommonList.RelationListItem> actionList = newList();
296 List<RelationsCommonList.RelationListItem> childList = childListOuter.getRelationListItem();
297 List<RelationsCommonList.RelationListItem> parentList = parentListOuter.getRelationListItem();
299 for (RelationsCommonList.RelationListItem inboundItem : inboundList) {
300 if (inboundItem.getObjectCsid().equals(itemCSID) && inboundItem.getPredicate().equals(HAS_BROADER)){
301 //then this is an item that says we have a child.
302 RelationsCommonList.RelationListItem childItem = findInList(childList, inboundItem);
303 if (childItem != null){
304 removeFromList(childList, childItem); //exists, just take it off delete list
306 actionList.add(inboundItem); //doesn't exist as a child, but is a child. Add to additions list
308 } else if (inboundItem.getSubjectCsid().equals(itemCSID) && inboundItem.getPredicate().equals(HAS_BROADER)) {
309 //then this is an item that says we have a parent
310 RelationsCommonList.RelationListItem parentItem = findInList(parentList, inboundItem);
311 if (parentItem != null){
312 removeFromList(parentList, parentItem); //exists, just take it off delete list
314 actionList.add(inboundItem); //doesn't exist as a parent, but is a parent. Add to additions list
317 System.out.println("\r\n\r\n================\r\n Element didn't match parent or child, but may have partial fields that match. inboundItem: "+inboundItem);
318 //not dealing with: hasNarrower or any other predicate.
322 deleteRelations(parentList, ctx);
323 deleteRelations(childList, ctx);
324 createRelations(actionList, ctx);
326 return relationsCommonListBody;
329 private void createRelations(List<RelationsCommonList.RelationListItem> inboundList, ServiceContext ctx){
330 for (RelationsCommonList.RelationListItem item : inboundList) {
331 RelationsCommon rc = new RelationsCommon();
332 //rc.setCsid(item.getCsid());
333 rc.setDocumentId1(item.getSubjectCsid());
334 rc.setDocumentId2(item.getObjectCsid());
335 rc.setRelationshipType(item.getPredicate());
336 //todo: is an enum: rc.setPredicate(item.getPredicate());
337 rc.setDocumentType1(item.getSubject().getDocumentType());
338 rc.setDocumentType2(item.getObject().getDocumentType());
340 PoxPayloadOut payloadOut = new PoxPayloadOut(RelationClient.SERVICE_PAYLOAD_NAME);
341 PayloadOutputPart outputPart = new PayloadOutputPart(RelationClient.SERVICE_COMMONPART_NAME, rc);
342 payloadOut.addPart(outputPart);
343 System.out.println("\r\n==== TO CREATE: "+rc.getDocumentId1()+"==>"+rc.getPredicate()+"==>"+rc.getDocumentId2());
344 RelationResource relationResource = new RelationResource();
345 Object res = relationResource.create(ctx.getUriInfo(), payloadOut.toXML()); //NOTE ui recycled from above to pass in unknown query params.
348 private void deleteRelations(List<RelationsCommonList.RelationListItem> list,ServiceContext ctx){
350 for (RelationsCommonList.RelationListItem inboundItem : list) {
351 RelationResource relationResource = new RelationResource();
352 System.out.println("\r\n==== TO DELETE: "+inboundItem.getCsid());
353 Object res = relationResource.delete(inboundItem.getCsid());
355 } catch (Throwable t){
356 String msg = "Unable to deleteRelations: "+ Tools.errorToString(t, true);
361 private List<RelationsCommonList.RelationListItem> newList(){
362 List<RelationsCommonList.RelationListItem> result = new ArrayList<RelationsCommonList.RelationListItem>();
365 protected List<RelationsCommonList.RelationListItem> cloneList(List<RelationsCommonList.RelationListItem> inboundList){
366 List<RelationsCommonList.RelationListItem> result = newList();
367 for (RelationsCommonList.RelationListItem item: inboundList){
372 private RelationsCommonList.RelationListItem findInList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item){
373 for (RelationsCommonList.RelationListItem listItem : list) {
374 if (itemsEqual(listItem, item)){ //equals must be defined, else
381 private boolean itemsEqual(RelationsCommonList.RelationListItem item, RelationsCommonList.RelationListItem item2){
382 if (item==null || item2==null){
385 return (item.getSubjectCsid().equals(item2.getSubjectCsid()))
386 && (item.getObjectCsid().equals(item2.getObjectCsid()))
387 && ( (item.getPredicate().equals(item2.getPredicate()))
388 && (item.getRelationshipType().equals(item2.getRelationshipType())) )
389 && (item.getObject().getDocumentType().equals(item2.getObject().getDocumentType()))
390 && (item.getSubject().getDocumentType().equals(item2.getSubject().getDocumentType())) ;
393 private void removeFromList(List<RelationsCommonList.RelationListItem> list, RelationsCommonList.RelationListItem item){
396 //================= TODO: move this to common, refactoring this and CollectionObjectResource.java
398 public RelationsCommonList getRelations(String subjectCSID, String objectCSID, String predicate) throws Exception {
399 ServiceContext ctx = getServiceContext();
400 MultivaluedMap queryParams = ctx.getQueryParams();
401 queryParams.putSingle(IRelationsManager.PREDICATE_QP, predicate);
402 queryParams.putSingle(IRelationsManager.SUBJECT_QP, subjectCSID);
403 queryParams.putSingle(IRelationsManager.OBJECT_QP, objectCSID);
405 RelationResource relationResource = new RelationResource();
406 RelationsCommonList relationsCommonList = relationResource.getList(ctx.getUriInfo());
407 return relationsCommonList;
410 //============================= END refactor ==========================