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
6 * http://www.collectionspace.org
\r
7 * http://wiki.collectionspace.org
\r
9 * Copyright 2009 University of California at Berkeley
\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
14 * You may obtain a copy of the ECL 2.0 License at
\r
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
\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
24 package org.collectionspace.services.common.vocabulary;
\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
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.nuxeo.ecm.core.api.model.Property;
\r
37 import org.nuxeo.ecm.core.api.model.PropertyException;
\r
38 import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
\r
39 import org.nuxeo.ecm.core.api.model.impl.primitives.StringProperty;
\r
40 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
\r
41 import org.slf4j.Logger;
\r
42 import org.slf4j.LoggerFactory;
\r
44 import org.collectionspace.services.client.PoxPayloadIn;
\r
45 import org.collectionspace.services.client.PoxPayloadOut;
\r
46 import org.collectionspace.services.common.ServiceMain;
\r
47 import org.collectionspace.services.common.context.ServiceContext;
\r
48 import org.collectionspace.services.common.context.AbstractServiceContextImpl;
\r
49 import org.collectionspace.services.common.api.Tools;
\r
50 import org.collectionspace.services.common.authorityref.AuthorityRefDocList;
\r
51 import org.collectionspace.services.common.authorityref.AuthorityRefList;
\r
52 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
\r
53 import org.collectionspace.services.common.context.ServiceBindingUtils;
\r
54 import org.collectionspace.services.common.document.DocumentException;
\r
55 import org.collectionspace.services.common.document.DocumentNotFoundException;
\r
56 import org.collectionspace.services.common.document.DocumentUtils;
\r
57 import org.collectionspace.services.common.document.DocumentWrapper;
\r
58 import org.collectionspace.services.common.repository.RepositoryClient;
\r
59 import org.collectionspace.services.nuxeo.client.java.DocHandlerBase;
\r
60 import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;
\r
61 import org.collectionspace.services.common.service.ServiceBindingType;
\r
62 import org.collectionspace.services.jaxb.AbstractCommonList;
\r
63 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
\r
65 import com.sun.xml.bind.v2.runtime.unmarshaller.XsiNilLoader.Array;
\r
68 * RefNameServiceUtils is a collection of services utilities related to refName usage.
\r
70 * $LastChangedRevision: $
\r
71 * $LastChangedDate: $
\r
73 public class RefNameServiceUtils {
\r
75 public static class AuthRefConfigInfo {
\r
76 public String getQualifiedDisplayName() {
\r
77 return(Tools.isBlank(schema))?
\r
78 displayName:DocumentUtils.appendSchemaName(schema, displayName);
\r
80 public String getDisplayName() {
\r
83 public void setDisplayName(String displayName) {
\r
84 this.displayName = displayName;
\r
88 public String getSchema() {
\r
91 public void setSchema(String schema) {
\r
92 this.schema = schema;
\r
94 public String getFullPath() {
\r
97 public void setFullPath(String fullPath) {
\r
98 this.fullPath = fullPath;
\r
101 protected String[] pathEls;
\r
102 public AuthRefConfigInfo(AuthRefConfigInfo arci) {
\r
103 this.displayName = arci.displayName;
\r
104 this.schema = arci.schema;
\r
105 this.fullPath = arci.fullPath;
\r
106 this.pathEls = arci.pathEls;
\r
107 // Skip the pathElse check, since we are creatign from another (presumably valid) arci.
\r
110 public AuthRefConfigInfo(String displayName, String schema, String fullPath, String[] pathEls) {
\r
111 this.displayName = displayName;
\r
112 this.schema = schema;
\r
113 this.fullPath = fullPath;
\r
114 this.pathEls = pathEls;
\r
118 // Split a config value string like "intakes_common:collector", or
\r
119 // "collectionobjects_common:contentPeoples|contentPeople"
\r
120 // "collectionobjects_common:assocEventGroupList/*/assocEventPlace"
\r
121 // If has a pipe ('|') second part is a displayLabel, and first is path
\r
122 // Otherwise, entry is a path, and can use the last pathElement as displayName
\r
123 // Should be schema qualified.
\r
124 public AuthRefConfigInfo(String configString) {
\r
125 String[] pair = configString.split("\\|", 2);
\r
127 String displayName, fullPath;
\r
128 if(pair.length == 1) {
\r
129 // no label specifier, so we'll defer getting label
\r
130 fullPath = pair[0];
\r
131 pathEls = pair[0].split("/");
\r
132 displayName = pathEls[pathEls.length-1];
\r
134 fullPath = pair[0];
\r
135 pathEls = pair[0].split("/");
\r
136 displayName = pair[1];
\r
138 String[] schemaSplit = pathEls[0].split(":",2);
\r
140 if(schemaSplit.length==1) { // schema not specified
\r
143 schema = schemaSplit[0];
\r
144 if(pair.length == 1 && pathEls.length == 1) { // simplest case of field in top level schema, no labelll
\r
145 displayName = schemaSplit[1]; // Have to fix up displayName to have no schema
\r
148 this.displayName = displayName;
\r
149 this.schema = schema;
\r
150 this.fullPath = fullPath;
\r
151 this.pathEls = pathEls;
\r
155 protected void checkPathEls() {
\r
156 int len = pathEls.length;
\r
158 throw new InternalError("Bad values in authRef info - caller screwed up:"+fullPath);
\r
159 // Handle case of them putting a leading slash on the path
\r
160 if(len>1 && pathEls[0].endsWith(":")) {
\r
162 String[] newArray = new String[len];
\r
163 newArray[0] = pathEls[0]+pathEls[1];
\r
165 System.arraycopy(pathEls, 2, newArray, 1, len-1);
\r
167 pathEls = newArray;
\r
172 public static class AuthRefInfo extends AuthRefConfigInfo {
\r
173 public Property getProperty() {
\r
176 public void setProperty(Property property) {
\r
177 this.property = property;
\r
180 public AuthRefInfo(String displayName, String schema, String fullPath, String[] pathEls, Property prop) {
\r
181 super(displayName, schema, fullPath, pathEls);
\r
182 this.property = prop;
\r
184 public AuthRefInfo(AuthRefConfigInfo arci, Property prop) {
\r
186 this.property = prop;
\r
190 private static final Logger logger = LoggerFactory.getLogger(RefNameServiceUtils.class);
\r
192 private static ArrayList<String> refNameServiceTypes = null;
\r
194 public static List<AuthRefConfigInfo> getConfiguredAuthorityRefs(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
\r
195 List<String> authRefFields =
\r
196 ((AbstractServiceContextImpl) ctx).getAllPartsPropertyValues(
\r
197 ServiceBindingUtils.AUTH_REF_PROP, ServiceBindingUtils.QUALIFIED_PROP_NAMES);
\r
198 ArrayList<AuthRefConfigInfo> authRefsInfo = new ArrayList<AuthRefConfigInfo>(authRefFields.size());
\r
199 for(String spec:authRefFields) {
\r
200 AuthRefConfigInfo arci = new AuthRefConfigInfo(spec);
\r
201 authRefsInfo.add(arci);
\r
203 return authRefsInfo;
\r
206 public static AuthorityRefDocList getAuthorityRefDocs(
\r
207 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
\r
208 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient,
\r
209 List<String> serviceTypes,
\r
211 String refPropName,
\r
212 int pageSize, int pageNum, boolean computeTotal)
\r
213 throws DocumentException, DocumentNotFoundException {
\r
214 AuthorityRefDocList wrapperList = new AuthorityRefDocList();
\r
215 AbstractCommonList commonList = (AbstractCommonList) wrapperList;
\r
216 commonList.setPageNum(pageNum);
\r
217 commonList.setPageSize(pageSize);
\r
218 List<AuthorityRefDocList.AuthorityRefDocItem> list =
\r
219 wrapperList.getAuthorityRefDocItem();
\r
221 Map<String, ServiceBindingType> queriedServiceBindings = new HashMap<String, ServiceBindingType>();
\r
222 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService = new HashMap<String, List<AuthRefConfigInfo>>();
\r
224 RepositoryJavaClientImpl nuxeoRepoClient = (RepositoryJavaClientImpl)repoClient;
\r
225 RepositoryInstance repoSession = null;
\r
227 repoSession = nuxeoRepoClient.getRepositorySession();
\r
228 DocumentModelList docList = findAuthorityRefDocs(ctx, repoClient, repoSession,
\r
229 serviceTypes, refName, refPropName, queriedServiceBindings, authRefFieldsByService, pageSize, pageNum, computeTotal);
\r
231 if (docList == null) { // found no authRef fields - nothing to process
\r
232 return wrapperList;
\r
234 // Set num of items in list. this is useful to our testing framework.
\r
235 commonList.setItemsInPage(docList.size());
\r
236 // set the total result size
\r
237 commonList.setTotalItems(docList.totalSize());
\r
239 int nRefsFound = processRefObjsDocList(docList, refName, queriedServiceBindings, authRefFieldsByService,
\r
241 if(logger.isDebugEnabled() && (nRefsFound < docList.size())) {
\r
242 logger.debug("Internal curiosity: got fewer matches of refs than # docs matched...");
\r
244 } catch (Exception e) {
\r
245 logger.error("Could not retrieve the Nuxeo repository", e);
\r
246 wrapperList = null;
\r
248 if (repoSession != null) {
\r
249 nuxeoRepoClient.releaseRepositorySession(repoSession);
\r
253 return wrapperList;
\r
256 private static ArrayList<String> getRefNameServiceTypes() {
\r
257 if(refNameServiceTypes == null) {
\r
258 refNameServiceTypes = new ArrayList<String>();
\r
259 refNameServiceTypes.add(ServiceBindingUtils.SERVICE_TYPE_AUTHORITY);
\r
260 refNameServiceTypes.add(ServiceBindingUtils.SERVICE_TYPE_OBJECT);
\r
261 refNameServiceTypes.add(ServiceBindingUtils.SERVICE_TYPE_PROCEDURE);
\r
263 return refNameServiceTypes;
\r
266 // Seems like a good value - no real data to set this well.
\r
267 private static final int N_OBJS_TO_UPDATE_PER_LOOP = 100;
\r
269 public static int updateAuthorityRefDocs(
\r
270 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
\r
271 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient,
\r
272 RepositoryInstance repoSession,
\r
275 String refPropName ) {
\r
276 Map<String, ServiceBindingType> queriedServiceBindings = new HashMap<String, ServiceBindingType>();
\r
277 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService = new HashMap<String, List<AuthRefConfigInfo>>();
\r
278 int nRefsFound = 0;
\r
279 if(!(repoClient instanceof RepositoryJavaClientImpl)) {
\r
280 throw new InternalError("updateAuthorityRefDocs() called with unknown repoClient type!");
\r
283 final int pageSize = N_OBJS_TO_UPDATE_PER_LOOP;
\r
284 int pageNumProcessed = 1;
\r
285 while(true) { // Keep looping until we find all the refs.
\r
286 logger.debug("updateAuthorityRefDocs working on page: "+pageNumProcessed);
\r
287 // Note that we always ask the Repo for the first page, since each page we process
\r
288 // should not be found in successive searches. Slightly inefficient, but more
\r
289 // reliable (stateless).
\r
290 DocumentModelList docList = findAuthorityRefDocs(ctx, repoClient, repoSession,
\r
291 getRefNameServiceTypes(), oldRefName, refPropName,
\r
292 queriedServiceBindings, authRefFieldsByService, pageSize, 0, false);
\r
294 if((docList == null) // found no authRef fields - nothing to do
\r
295 || (docList.size() == 0)) { // No more to handle
\r
296 logger.debug("updateAuthorityRefDocs no more results");
\r
299 logger.debug("updateAuthorityRefDocs curr page result list size: "+docList.size());
\r
300 int nRefsFoundThisPage = processRefObjsDocList(docList, oldRefName, queriedServiceBindings, authRefFieldsByService,
\r
302 if(nRefsFoundThisPage>0) {
\r
303 ((RepositoryJavaClientImpl)repoClient).saveDocListWithoutHandlerProcessing(ctx, repoSession, docList, true);
\r
304 nRefsFound += nRefsFoundThisPage;
\r
306 pageNumProcessed++;
\r
308 } catch(Exception e) {
\r
309 logger.error("Internal error updating the AuthorityRefDocs: " + e.getLocalizedMessage());
\r
310 logger.debug(Tools.errorToString(e, true));
\r
312 logger.debug("updateAuthorityRefDocs replaced a total of: "+nRefsFound);
\r
316 private static DocumentModelList findAuthorityRefDocs(
\r
317 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
\r
318 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient,
\r
319 RepositoryInstance repoSession,
\r
320 List<String> serviceTypes,
\r
322 String refPropName,
\r
323 Map<String, ServiceBindingType> queriedServiceBindings,
\r
324 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService,
\r
325 int pageSize, int pageNum, boolean computeTotal) throws DocumentException, DocumentNotFoundException {
\r
327 // Get the service bindings for this tenant
\r
328 TenantBindingConfigReaderImpl tReader =
\r
329 ServiceMain.getInstance().getTenantBindingConfigReader();
\r
330 // We need to get all the procedures, authorities, and objects.
\r
331 List<ServiceBindingType> servicebindings = tReader.getServiceBindingsByType(ctx.getTenantId(), serviceTypes);
\r
332 if (servicebindings == null || servicebindings.isEmpty()) {
\r
333 logger.error("RefNameServiceUtils.getAuthorityRefDocs: No services bindings found, cannot proceed!");
\r
337 // Need to escape the quotes in the refName
\r
338 // TODO What if they are already escaped?
\r
339 String escapedRefName = refName.replaceAll("'", "\\\\'");
\r
340 ArrayList<String> docTypes = new ArrayList<String>();
\r
342 String query = computeWhereClauseForAuthorityRefDocs(escapedRefName, refPropName, docTypes, servicebindings,
\r
343 queriedServiceBindings, authRefFieldsByService );
\r
344 if (query == null) { // found no authRef fields - nothing to query
\r
347 // Now we have to issue the search
\r
348 RepositoryJavaClientImpl nuxeoRepoClient = (RepositoryJavaClientImpl)repoClient;
\r
349 DocumentWrapper<DocumentModelList> docListWrapper = nuxeoRepoClient.findDocs(ctx, repoSession,
\r
350 docTypes, query, pageSize, pageNum, computeTotal);
\r
351 // Now we gather the info for each document into the list and return
\r
352 DocumentModelList docList = docListWrapper.getWrappedObject();
\r
356 private static final boolean READY_FOR_COMPLEX_QUERY = false;
\r
358 private static String computeWhereClauseForAuthorityRefDocs(
\r
359 String escapedRefName,
\r
360 String refPropName,
\r
361 ArrayList<String> docTypes,
\r
362 List<ServiceBindingType> servicebindings,
\r
363 Map<String, ServiceBindingType> queriedServiceBindings,
\r
364 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService ) {
\r
365 StringBuilder whereClause = new StringBuilder();
\r
366 boolean fFirst = true;
\r
367 List<String> authRefFieldPaths;
\r
368 for (ServiceBindingType sb : servicebindings) {
\r
369 // Gets the property names for each part, qualified with the part label (which
\r
370 // is also the table name, the way that the repository works).
\r
371 authRefFieldPaths =
\r
372 ServiceBindingUtils.getAllPartsPropertyValues(sb,
\r
373 refPropName, ServiceBindingUtils.QUALIFIED_PROP_NAMES);
\r
374 if (authRefFieldPaths.isEmpty()) {
\r
377 ArrayList<AuthRefConfigInfo> authRefsInfo = new ArrayList<AuthRefConfigInfo>();
\r
378 for(String spec:authRefFieldPaths) {
\r
379 AuthRefConfigInfo arci = new AuthRefConfigInfo(spec);
\r
380 authRefsInfo.add(arci);
\r
383 String docType = sb.getObject().getName();
\r
384 queriedServiceBindings.put(docType, sb);
\r
385 authRefFieldsByService.put(docType, authRefsInfo);
\r
386 docTypes.add(docType);
\r
387 for (AuthRefConfigInfo arci : authRefsInfo) {
\r
388 // Build up the where clause for each authRef field
\r
389 if(!READY_FOR_COMPLEX_QUERY) { // filter complex field references
\r
390 if(arci.pathEls.length>1)
\r
391 continue; // skip this one
\r
396 whereClause.append(" OR ");
\r
398 //whereClause.append(prefix);
\r
399 whereClause.append(arci.getFullPath());
\r
400 whereClause.append("='");
\r
401 whereClause.append(escapedRefName);
\r
402 whereClause.append("'");
\r
406 String whereClauseStr = whereClause.toString(); // for debugging
\r
407 if (logger.isTraceEnabled()) {
\r
408 logger.trace("The 'where' clause of the xyz method is: ", whereClauseStr);
\r
411 if (fFirst) { // found no authRef fields - nothing to query
\r
414 return whereClause.toString();
\r
419 * Runs through the list of found docs, processing them.
\r
420 * If list is non-null, then processing means gather the info for items.
\r
421 * If list is null, and newRefName is non-null, then processing means replacing and updating.
\r
422 * If processing/updating, this must be called in teh context of an open session, and caller
\r
423 * must release Session after calling this.
\r
426 private static int processRefObjsDocList(
\r
427 DocumentModelList docList,
\r
429 Map<String, ServiceBindingType> queriedServiceBindings,
\r
430 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService,
\r
431 List<AuthorityRefDocList.AuthorityRefDocItem> list,
\r
432 String newAuthorityRefName) {
\r
433 Iterator<DocumentModel> iter = docList.iterator();
\r
434 int nRefsFoundTotal = 0;
\r
435 while (iter.hasNext()) {
\r
436 DocumentModel docModel = iter.next();
\r
437 AuthorityRefDocList.AuthorityRefDocItem ilistItem;
\r
439 String docType = docModel.getDocumentType().getName();
\r
440 ServiceBindingType sb = queriedServiceBindings.get(docType);
\r
442 throw new RuntimeException(
\r
443 "getAuthorityRefDocs: No Service Binding for docType: " + docType);
\r
445 String serviceContextPath = "/" + sb.getName().toLowerCase() + "/";
\r
447 if(list == null) { // no list - should be update refName case.
\r
448 if(newAuthorityRefName==null) {
\r
449 throw new InternalError("processRefObjsDocList() called with neither an itemList nor a new RefName!");
\r
452 } else { // Have a list - refObjs case
\r
453 if(newAuthorityRefName!=null) {
\r
454 throw new InternalError("processRefObjsDocList() called with both an itemList and a new RefName!");
\r
456 ilistItem = new AuthorityRefDocList.AuthorityRefDocItem();
\r
457 String csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
\r
458 ilistItem.setDocId(csid);
\r
459 ilistItem.setUri(serviceContextPath + csid);
\r
461 ilistItem.setUpdatedAt(DocHandlerBase.getUpdatedAtAsString(docModel));
\r
462 } catch(Exception e) {
\r
463 logger.error("Error getting udpatedAt value for doc ["+csid+"]: "+e.getLocalizedMessage());
\r
465 // The id and URI are the same on all doctypes
\r
466 ilistItem.setDocType(docType);
\r
467 ilistItem.setDocNumber(
\r
468 ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NUMBER_PROP, docModel));
\r
469 ilistItem.setDocName(
\r
470 ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NAME_PROP, docModel));
\r
472 // Now, we have to loop over the authRefFieldsByService to figure
\r
473 // out which field(s) matched this.
\r
474 List<AuthRefConfigInfo> matchingAuthRefFields = authRefFieldsByService.get(docType);
\r
475 if (matchingAuthRefFields == null || matchingAuthRefFields.isEmpty()) {
\r
476 throw new RuntimeException(
\r
477 "getAuthorityRefDocs: internal logic error: can't fetch authRefFields for DocType.");
\r
479 //String authRefAncestorField = "";
\r
480 //String authRefDescendantField = "";
\r
481 //String sourceField = "";
\r
482 int nRefsFoundInDoc = 0;
\r
484 ArrayList<RefNameServiceUtils.AuthRefInfo> foundProps
\r
485 = new ArrayList<RefNameServiceUtils.AuthRefInfo>();
\r
487 findAuthRefPropertiesInDoc(docModel, matchingAuthRefFields, refName, foundProps);
\r
488 for(RefNameServiceUtils.AuthRefInfo ari:foundProps) {
\r
489 if(ilistItem != null) {
\r
490 if(nRefsFoundInDoc == 0) { // First one?
\r
491 ilistItem.setSourceField(ari.getQualifiedDisplayName());
\r
492 } else { // duplicates from one object
\r
493 ilistItem = cloneAuthRefDocItem(ilistItem, ari.getQualifiedDisplayName());
\r
495 list.add(ilistItem);
\r
496 } else { // update refName case
\r
497 Property propToUpdate = ari.getProperty();
\r
498 propToUpdate.setValue(newAuthorityRefName);
\r
502 } catch (ClientException ce) {
\r
503 throw new RuntimeException(
\r
504 "getAuthorityRefDocs: Problem fetching values from repo: " + ce.getLocalizedMessage());
\r
506 if (nRefsFoundInDoc == 0) {
\r
507 throw new RuntimeException(
\r
508 "getAuthorityRefDocs: Could not find refname in object:"
\r
509 + docType + ":" + NuxeoUtils.getCsid(docModel));
\r
511 nRefsFoundTotal += nRefsFoundInDoc;
\r
513 return nRefsFoundTotal;
\r
516 private static AuthorityRefDocList.AuthorityRefDocItem cloneAuthRefDocItem(
\r
517 AuthorityRefDocList.AuthorityRefDocItem ilistItem, String sourceField) {
\r
518 AuthorityRefDocList.AuthorityRefDocItem newlistItem = new AuthorityRefDocList.AuthorityRefDocItem();
\r
519 newlistItem.setDocId(ilistItem.getDocId());
\r
520 newlistItem.setDocName(ilistItem.getDocName());
\r
521 newlistItem.setDocNumber(ilistItem.getDocNumber());
\r
522 newlistItem.setDocType(ilistItem.getDocType());
\r
523 newlistItem.setUri(ilistItem.getUri());
\r
524 newlistItem.setSourceField(sourceField);
\r
525 return newlistItem;
\r
528 public static List<AuthRefInfo> findAuthRefPropertiesInDoc(
\r
529 DocumentModel docModel,
\r
530 List<AuthRefConfigInfo> authRefFieldInfo,
\r
531 String refNameToMatch,
\r
532 List<AuthRefInfo> foundProps
\r
534 // Assume that authRefFieldInfo is keyed by the field name (possibly mapped for UI)
\r
535 // and the values are elPaths to the field, where intervening group structures in
\r
536 // lists of complex structures are replaced with "*". Thus, valid paths include
\r
537 // the following (note that the ServiceBindingUtils prepend schema names to configured values):
\r
538 // "schemaname:fieldname"
\r
539 // "schemaname:scalarlistname"
\r
540 // "schemaname:complexfieldname/fieldname"
\r
541 // "schemaname:complexlistname/*/fieldname"
\r
542 // "schemaname:complexlistname/*/scalarlistname"
\r
543 // "schemaname:complexlistname/*/complexfieldname/fieldname"
\r
544 // "schemaname:complexlistname/*/complexlistname/*/fieldname"
\r
546 for (AuthRefConfigInfo arci : authRefFieldInfo) {
\r
548 // Get first property and work down as needed.
\r
549 Property prop = docModel.getProperty(arci.pathEls[0]);
\r
550 findAuthRefPropertiesInProperty(foundProps, prop, arci, 0, refNameToMatch);
\r
551 } catch(Exception e) {
\r
552 logger.error("Problem fetching property: "+arci.pathEls[0]);
\r
558 public static List<AuthRefInfo> findAuthRefPropertiesInProperty(
\r
559 List<AuthRefInfo> foundProps,
\r
561 AuthRefConfigInfo arci,
\r
562 int pathStartIndex, // Supports recursion and we work down the path
\r
563 String refNameToMatch
\r
565 if (pathStartIndex >= arci.pathEls.length) {
\r
566 throw new ArrayIndexOutOfBoundsException("Index = "+pathStartIndex+" for path: "
\r
567 +arci.pathEls.toString());
\r
569 AuthRefInfo ari = null;
\r
570 if (prop == null) {
\r
574 if (prop instanceof StringProperty) { // scalar string
\r
575 addARIifMatches(refNameToMatch, arci, prop, foundProps);
\r
576 } else if(prop instanceof List) {
\r
577 List<Property> propList = (List<Property>)prop;
\r
578 // run through list. Must either be list of Strings, or Complex
\r
579 for (Property listItemProp : propList) {
\r
580 if(listItemProp instanceof StringProperty) {
\r
581 if(arci.pathEls.length-pathStartIndex != 1) {
\r
582 logger.error("Configuration for authRefs does not match schema structure: "
\r
583 +arci.pathEls.toString());
\r
586 addARIifMatches(refNameToMatch, arci, listItemProp, foundProps);
\r
588 } else if(listItemProp.isComplex()) {
\r
589 // Just recurse to handle this. Note that since this is a list of complex,
\r
590 // which should look like listName/*/... we add 2 to the path start index
\r
591 findAuthRefPropertiesInProperty(foundProps, listItemProp, arci,
\r
592 pathStartIndex+2, refNameToMatch);
\r
594 logger.error("Configuration for authRefs does not match schema structure: "
\r
595 +arci.pathEls.toString());
\r
599 } else if(prop.isComplex()) {
\r
600 String localPropName = arci.pathEls[pathStartIndex];
\r
602 Property localProp = prop.get(localPropName);
\r
603 // Now just recurse, pushing down the path 1 step
\r
604 findAuthRefPropertiesInProperty(foundProps, localProp, arci,
\r
605 pathStartIndex, refNameToMatch);
\r
606 } catch(PropertyNotFoundException pnfe) {
\r
607 logger.error("Could not find property: ["+localPropName+"] in path: "+
\r
608 arci.getFullPath());
\r
609 // Fall through - ari will be null and we will continue...
\r
612 logger.error("Configuration for authRefs does not match schema structure: "
\r
613 +arci.pathEls.toString());
\r
617 foundProps.add(ari); //FIXME: REM - This is dead code. 'ari' is never touched after being initalized to null. Why?
\r
623 private static void addARIifMatches(
\r
624 String refNameToMatch,
\r
625 AuthRefConfigInfo arci,
\r
627 List<AuthRefInfo> foundProps) {
\r
628 // Need to either match a passed refName
\r
629 // OR have no refName to match but be non-empty
\r
631 String value = (String)prop.getValue();
\r
632 if(((refNameToMatch!=null) && refNameToMatch.equals(value))
\r
633 || ((refNameToMatch==null) && Tools.notBlank(value))) {
\r
635 logger.debug("Found a match on property: "+prop.getPath()+" with value: ["+value+"]");
\r
636 AuthRefInfo ari = new AuthRefInfo(arci, prop);
\r
637 foundProps.add(ari);
\r
639 } catch(PropertyException pe) {
\r
640 logger.debug("PropertyException on: "+prop.getPath()+pe.getLocalizedMessage());
\r
645 * Identifies whether the refName was found in the supplied field.
\r
646 * If passed a new RefName, will set that into fields in which the old one was found.
\r
650 * * Repeatable scalar fields (aka multi-valued fields)
\r
652 * Does not work for:
\r
653 * * Structured fields (complexTypes)
\r
654 * * Repeatable structured fields (repeatable complexTypes)
\r
655 private static int refNameFoundInField(String oldRefName, Property fieldValue, String newRefName) {
\r
657 if (fieldValue instanceof List) {
\r
658 List<Property> fieldValueList = (List) fieldValue;
\r
659 for (Property listItemValue : fieldValueList) {
\r
661 if ((listItemValue instanceof StringProperty)
\r
662 && oldRefName.equalsIgnoreCase((String)listItemValue.getValue())) {
\r
664 if(newRefName!=null) {
\r
665 fieldValue.setValue(newRefName);
\r
667 // We cannot quit after the first, if we are replacing values.
\r
668 // If we are just looking (not replacing), finding one is enough.
\r
672 } catch( PropertyException pe ) {}
\r
676 if ((fieldValue instanceof StringProperty)
\r
677 && oldRefName.equalsIgnoreCase((String)fieldValue.getValue())) {
\r
679 if(newRefName!=null) {
\r
680 fieldValue.setValue(newRefName);
\r
683 } catch( PropertyException pe ) {}
\r