]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
56fb517791ec1f7a6162b293f369514b3f801393
[tmp/jakarta-migration.git] /
1 /**\r
2  *  This document is a part of the source code and related artifacts\r
3  *  for CollectionSpace, an open source collections management system\r
4  *  for museums and related institutions:\r
5 \r
6  *  http://www.collectionspace.org\r
7  *  http://wiki.collectionspace.org\r
8 \r
9  *  Copyright 2009 University of California at Berkeley\r
10 \r
11  *  Licensed under the Educational Community License (ECL), Version 2.0.\r
12  *  You may not use this file except in compliance with this License.\r
13 \r
14  *  You may obtain a copy of the ECL 2.0 License at\r
15 \r
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt\r
17 \r
18  *  Unless required by applicable law or agreed to in writing, software\r
19  *  distributed under the License is distributed on an "AS IS" BASIS,\r
20  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
21  *  See the License for the specific language governing permissions and\r
22  *  limitations under the License.\r
23  */\r
24 package org.collectionspace.services.common.vocabulary;\r
25 \r
26 import java.util.ArrayList;\r
27 import java.util.Collection;\r
28 import java.util.HashMap;\r
29 import java.util.Iterator;\r
30 import java.util.List;\r
31 import java.util.Map;\r
32 \r
33 import org.nuxeo.ecm.core.api.ClientException;\r
34 import org.nuxeo.ecm.core.api.DocumentModel;\r
35 import org.nuxeo.ecm.core.api.DocumentModelList;\r
36 import org.slf4j.Logger;\r
37 import org.slf4j.LoggerFactory;\r
38 \r
39 import org.collectionspace.services.common.ServiceMain;\r
40 import org.collectionspace.services.common.context.ServiceContext;\r
41 import org.collectionspace.services.common.authorityref.AuthorityRefDocList;\r
42 import org.collectionspace.services.common.authorityref.AuthorityRefList;\r
43 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;\r
44 import org.collectionspace.services.common.context.ServiceBindingUtils;\r
45 import org.collectionspace.services.common.document.DocumentException;\r
46 import org.collectionspace.services.common.document.DocumentNotFoundException;\r
47 import org.collectionspace.services.common.document.DocumentUtils;\r
48 import org.collectionspace.services.common.document.DocumentWrapper;\r
49 import org.collectionspace.services.common.repository.RepositoryClient;\r
50 import org.collectionspace.services.common.service.ServiceBindingType;\r
51 import org.collectionspace.services.jaxb.AbstractCommonList;\r
52 import org.collectionspace.services.nuxeo.util.NuxeoUtils;\r
53 \r
54 /**\r
55  * RefNameServiceUtils is a collection of services utilities related to refName usage.\r
56  *\r
57  * $LastChangedRevision: $\r
58  * $LastChangedDate: $\r
59  */\r
60 public class RefNameServiceUtils {\r
61 \r
62     private static final Logger logger = LoggerFactory.getLogger(RefNameServiceUtils.class);\r
63 \r
64     public static AuthorityRefDocList getAuthorityRefDocs(ServiceContext ctx,\r
65             RepositoryClient repoClient,\r
66             String serviceType,\r
67             String refName,\r
68             String refPropName,\r
69             int pageSize, int pageNum, boolean computeTotal) throws DocumentException, DocumentNotFoundException {\r
70         AuthorityRefDocList wrapperList = new AuthorityRefDocList();\r
71         AbstractCommonList commonList = (AbstractCommonList) wrapperList;\r
72         commonList.setPageNum(pageNum);\r
73         commonList.setPageSize(pageSize);\r
74         List<AuthorityRefDocList.AuthorityRefDocItem> list =\r
75                 wrapperList.getAuthorityRefDocItem();\r
76 \r
77         // Get the service bindings for this tenant\r
78         TenantBindingConfigReaderImpl tReader =\r
79                 ServiceMain.getInstance().getTenantBindingConfigReader();\r
80         List<ServiceBindingType> servicebindings = tReader.getServiceBindingsByType(ctx.getTenantId(), serviceType);\r
81         if (servicebindings == null || servicebindings.isEmpty()) {\r
82                 logger.error("RefNameServiceUtils.getAuthorityRefDocs: No services bindings found, cannot proceed!");\r
83             return null;\r
84         }\r
85         \r
86         // Need to escape the quotes in the refName\r
87         // TODO What if they are already escaped?\r
88         String escapedRefName = refName.replaceAll("'", "\\\\'");\r
89         ArrayList<String> docTypes = new ArrayList<String>();\r
90         Map<String, ServiceBindingType> queriedServiceBindings = new HashMap<String, ServiceBindingType>();\r
91         Map<String, Map<String, String>> authRefFieldsByService = new HashMap<String, Map<String, String>>();\r
92         \r
93         String query = computeWhereClauseForAuthorityRefDocs(escapedRefName, refPropName, docTypes, servicebindings, \r
94                                                                                                 queriedServiceBindings, authRefFieldsByService );\r
95         if (query == null) { // found no authRef fields - nothing to query\r
96             return wrapperList;\r
97         }\r
98         // Now we have to issue the search\r
99         DocumentWrapper<DocumentModelList> docListWrapper = repoClient.findDocs(ctx,\r
100                 docTypes, query, pageSize, pageNum, computeTotal);\r
101         // Now we gather the info for each document into the list and return\r
102         DocumentModelList docList = docListWrapper.getWrappedObject();\r
103         // Set num of items in list. this is useful to our testing framework.\r
104         commonList.setItemsInPage(docList.size());\r
105         // set the total result size\r
106         commonList.setTotalItems(docList.totalSize());\r
107         \r
108         processRefObjsDocList(docList, refName, servicebindings,\r
109                                                         queriedServiceBindings, authRefFieldsByService,\r
110                                                         list, null);\r
111         return wrapperList;\r
112     }\r
113     \r
114     private static String computeWhereClauseForAuthorityRefDocs(\r
115                 String escapedRefName,\r
116                 String refPropName,\r
117                 ArrayList<String> docTypes,\r
118                 List<ServiceBindingType> servicebindings,\r
119                 Map<String, ServiceBindingType> queriedServiceBindings,\r
120                 Map<String, Map<String, String>> authRefFieldsByService ) {\r
121         StringBuilder whereClause = new StringBuilder();\r
122         boolean fFirst = true;\r
123         List<String> authRefFieldPaths = new ArrayList<String>();\r
124         for (ServiceBindingType sb : servicebindings) {\r
125                 // Gets the property names for each part, qualified with the part label (which\r
126                 // is also the table name, the way that the repository works).\r
127             authRefFieldPaths =\r
128                     ServiceBindingUtils.getAllPartsPropertyValues(sb,\r
129                                 refPropName, ServiceBindingUtils.QUALIFIED_PROP_NAMES);\r
130             if (authRefFieldPaths.isEmpty()) {\r
131                 continue;\r
132             }\r
133             String authRefPath = "";\r
134             String ancestorAuthRefFieldName = "";\r
135             Map<String, String> authRefFields = new HashMap<String, String>();\r
136             for (int i = 0; i < authRefFieldPaths.size(); i++) {\r
137                 // fieldName = DocumentUtils.getDescendantOrAncestor(authRefFields.get(i));\r
138                 // For simple field values, we just search on the item.\r
139                 // For simple repeating scalars, we just search the group field \r
140                 // For repeating complex types, we will need to do more.\r
141                 authRefPath = authRefFieldPaths.get(i);\r
142                 ancestorAuthRefFieldName = DocumentUtils.getAncestorAuthRefFieldName(authRefFieldPaths.get(i));\r
143                 authRefFields.put(authRefPath, ancestorAuthRefFieldName);\r
144             }\r
145 \r
146             String docType = sb.getObject().getName();\r
147             queriedServiceBindings.put(docType, sb);\r
148             authRefFieldsByService.put(docType, authRefFields);\r
149             docTypes.add(docType);\r
150             Collection<String> fields = authRefFields.values();\r
151             for (String field : fields) {\r
152                 // Build up the where clause for each authRef field\r
153                 if (fFirst) {\r
154                     fFirst = false;\r
155                 } else {\r
156                     whereClause.append(" OR ");\r
157                 }\r
158                 //whereClause.append(prefix);\r
159                 whereClause.append(field);\r
160                 whereClause.append("='");\r
161                 whereClause.append(escapedRefName);\r
162                 whereClause.append("'");\r
163             }\r
164         }\r
165         String whereClauseStr = whereClause.toString(); // for debugging\r
166         if (fFirst) { // found no authRef fields - nothing to query\r
167             return null;\r
168         } else {\r
169                 return whereClause.toString(); \r
170         }\r
171     }\r
172     \r
173     /*\r
174      * Runs through the list of found docs, processing them. \r
175      * If list is non-null, then processing means gather the info for items.\r
176      * If list is null, and newRefName is non-null, then processing means replacing and updating.\r
177      */\r
178     private static void processRefObjsDocList(DocumentModelList docList,\r
179                 String refName,\r
180                 List<ServiceBindingType> servicebindings,\r
181                 Map<String, ServiceBindingType> queriedServiceBindings,\r
182                 Map<String, Map<String, String>> authRefFieldsByService,\r
183                         List<AuthorityRefDocList.AuthorityRefDocItem> list, \r
184                         String newAuthorityRefName) {\r
185         Iterator<DocumentModel> iter = docList.iterator();\r
186         while (iter.hasNext()) {\r
187             DocumentModel docModel = iter.next();\r
188             AuthorityRefDocList.AuthorityRefDocItem ilistItem;\r
189 \r
190             String docType = docModel.getDocumentType().getName();\r
191             ServiceBindingType sb = queriedServiceBindings.get(docType);\r
192             if (sb == null) {\r
193                 throw new RuntimeException(\r
194                         "getAuthorityRefDocs: No Service Binding for docType: " + docType);\r
195             }\r
196             String serviceContextPath = "/" + sb.getName().toLowerCase() + "/";\r
197             \r
198             if(list == null) {\r
199                 ilistItem = null;\r
200             } else {\r
201                 ilistItem = new AuthorityRefDocList.AuthorityRefDocItem();\r
202                 String csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());\r
203                 ilistItem.setDocId(csid);\r
204                 ilistItem.setUri(serviceContextPath + csid);\r
205                 // The id and URI are the same on all doctypes\r
206                 ilistItem.setDocType(docType);\r
207                 ilistItem.setDocNumber(\r
208                         ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NUMBER_PROP, docModel));\r
209                 ilistItem.setDocName(\r
210                         ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NAME_PROP, docModel));\r
211             }\r
212             // Now, we have to loop over the authRefFieldsByService to figure\r
213             // out which field matched this. Ignore multiple matches.\r
214             Map<String,String> matchingAuthRefFields = authRefFieldsByService.get(docType);\r
215             if (matchingAuthRefFields == null || matchingAuthRefFields.isEmpty()) {\r
216                 throw new RuntimeException(\r
217                         "getAuthorityRefDocs: internal logic error: can't fetch authRefFields for DocType.");\r
218             }\r
219             String authRefAncestorField = "";\r
220             String authRefDescendantField = "";\r
221             String sourceField = "";\r
222             boolean fRefFound = false;\r
223             // Use this if we go to qualified field names\r
224             for (String path : matchingAuthRefFields.keySet()) {\r
225                 try {\r
226                         // This is the field name we show in the return info\r
227                     authRefAncestorField = (String) matchingAuthRefFields.get(path);\r
228                     // This is the qualified field we have to get from the doc model\r
229                     authRefDescendantField = DocumentUtils.getDescendantOrAncestor(path);\r
230                     // The ancestor field is part-schema (tablename) qualified\r
231                     String[] strings = authRefAncestorField.split(":");\r
232                     if (strings.length != 2) {\r
233                         throw new RuntimeException(\r
234                                 "getAuthorityRefDocs: Bad configuration of path to authority reference field.");\r
235                     }\r
236                     // strings[0] holds a schema name, such as "intakes_common"\r
237                     //\r
238                     // strings[1] holds:\r
239                     // * The name of an authority reference field, such as "depositor";\r
240                     //   or\r
241                     // * The name of an ancestor (e.g. parent, grandparent ...) field,\r
242                     //   such as "fieldCollectors", of a repeatable authority reference\r
243                     //   field, such as "fieldCollector".\r
244                     // TODO - if the value is not simple, or repeating scalar, need a more\r
245                     // sophisticated fetch. \r
246                     Object fieldValue = docModel.getProperty(strings[0], strings[1]);\r
247                     // We cannot be sure why we have this doc, so look for matches\r
248                     boolean fRefMatches = refNameFoundInField(refName, fieldValue);\r
249                     if (fRefMatches) {\r
250                         sourceField = authRefDescendantField;\r
251                         // Handle multiple fields matching in one Doc. See CSPACE-2863.\r
252                         if(fRefFound) {\r
253                                 // We already added ilistItem, so we need to clone that and add again\r
254                                 if(ilistItem != null) {\r
255                                         ilistItem = cloneAuthRefDocItem(ilistItem, sourceField);\r
256                                 }\r
257                         } else {\r
258                                 if(ilistItem != null) {\r
259                                         ilistItem.setSourceField(sourceField);\r
260                                 }\r
261                             fRefFound = true;\r
262                         }\r
263                                 if(ilistItem != null) {\r
264                                         list.add(ilistItem);\r
265                                 }\r
266                     }\r
267 \r
268                 } catch (ClientException ce) {\r
269                     throw new RuntimeException(\r
270                             "getAuthorityRefDocs: Problem fetching: " + sourceField, ce);\r
271                 }\r
272             }\r
273             if (!fRefFound) {\r
274                 throw new RuntimeException(\r
275                         "getAuthorityRefDocs: Could not find refname in object:"\r
276                         + docType + ":" + NuxeoUtils.getCsid(docModel));\r
277             }\r
278         }\r
279 \r
280     }\r
281     \r
282     private static AuthorityRefDocList.AuthorityRefDocItem cloneAuthRefDocItem(\r
283                 AuthorityRefDocList.AuthorityRefDocItem ilistItem, String sourceField) {\r
284         AuthorityRefDocList.AuthorityRefDocItem newlistItem = new AuthorityRefDocList.AuthorityRefDocItem();\r
285         newlistItem.setDocId(ilistItem.getDocId());\r
286         newlistItem.setDocName(ilistItem.getDocName());\r
287         newlistItem.setDocNumber(ilistItem.getDocNumber());\r
288         newlistItem.setDocType(ilistItem.getDocType());\r
289         newlistItem.setUri(ilistItem.getUri());\r
290         newlistItem.setSourceField(sourceField);\r
291         return newlistItem;\r
292     }\r
293 \r
294     /*\r
295      * Identifies whether the refName was found in the supplied field.\r
296      *\r
297      * Only works for:\r
298      * * Scalar fields\r
299      * * Repeatable scalar fields (aka multi-valued fields)\r
300      *\r
301      * Does not work for:\r
302      * * Structured fields (complexTypes)\r
303      * * Repeatable structured fields (repeatable complexTypes)\r
304      */\r
305     private static boolean refNameFoundInField(String refName, Object fieldValue) {\r
306 \r
307         boolean result = false;\r
308         if (fieldValue instanceof List) {\r
309             List<String> fieldValueList = (List) fieldValue;\r
310             for (String listItemValue : fieldValueList) {\r
311                 if (refName.equalsIgnoreCase(listItemValue)) {\r
312                     result = true;\r
313                     break;\r
314                 }\r
315 \r
316             }\r
317         } else if (fieldValue instanceof String){\r
318             if (refName.equalsIgnoreCase((String)fieldValue)) {\r
319                 result = true;\r
320             }\r
321         }\r
322         return result;\r
323     }\r
324 }\r
325 \r