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 RepositoryInstance repoSession,
\r
208 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
\r
209 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient,
\r
210 List<String> serviceTypes,
\r
212 String refPropName,
\r
213 int pageSize, int pageNum, boolean computeTotal)
\r
214 throws DocumentException, DocumentNotFoundException {
\r
215 AuthorityRefDocList wrapperList = new AuthorityRefDocList();
\r
216 AbstractCommonList commonList = (AbstractCommonList) wrapperList;
\r
217 commonList.setPageNum(pageNum);
\r
218 commonList.setPageSize(pageSize);
\r
219 List<AuthorityRefDocList.AuthorityRefDocItem> list =
\r
220 wrapperList.getAuthorityRefDocItem();
\r
222 Map<String, ServiceBindingType> queriedServiceBindings = new HashMap<String, ServiceBindingType>();
\r
223 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService = new HashMap<String, List<AuthRefConfigInfo>>();
\r
225 RepositoryJavaClientImpl nuxeoRepoClient = (RepositoryJavaClientImpl)repoClient;
\r
227 DocumentModelList docList = findAuthorityRefDocs(ctx, repoClient, repoSession,
\r
228 serviceTypes, refName, refPropName, queriedServiceBindings, authRefFieldsByService, pageSize, pageNum, computeTotal);
\r
230 if (docList == null) { // found no authRef fields - nothing to process
\r
231 return wrapperList;
\r
233 // Set num of items in list. this is useful to our testing framework.
\r
234 commonList.setItemsInPage(docList.size());
\r
235 // set the total result size
\r
236 commonList.setTotalItems(docList.totalSize());
\r
238 int nRefsFound = processRefObjsDocList(docList, refName, queriedServiceBindings, authRefFieldsByService,
\r
240 if(logger.isDebugEnabled() && (nRefsFound < docList.size())) {
\r
241 logger.debug("Internal curiosity: got fewer matches of refs than # docs matched...");
\r
243 } catch (Exception e) {
\r
244 logger.error("Could not retrieve the Nuxeo repository", e);
\r
245 wrapperList = null;
\r
248 return wrapperList;
\r
251 private static ArrayList<String> getRefNameServiceTypes() {
\r
252 if(refNameServiceTypes == null) {
\r
253 refNameServiceTypes = new ArrayList<String>();
\r
254 refNameServiceTypes.add(ServiceBindingUtils.SERVICE_TYPE_AUTHORITY);
\r
255 refNameServiceTypes.add(ServiceBindingUtils.SERVICE_TYPE_OBJECT);
\r
256 refNameServiceTypes.add(ServiceBindingUtils.SERVICE_TYPE_PROCEDURE);
\r
258 return refNameServiceTypes;
\r
261 // Seems like a good value - no real data to set this well.
\r
262 private static final int N_OBJS_TO_UPDATE_PER_LOOP = 100;
\r
264 public static int updateAuthorityRefDocs(
\r
265 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
\r
266 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient,
\r
267 RepositoryInstance repoSession,
\r
270 String refPropName ) {
\r
271 Map<String, ServiceBindingType> queriedServiceBindings = new HashMap<String, ServiceBindingType>();
\r
272 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService = new HashMap<String, List<AuthRefConfigInfo>>();
\r
273 int nRefsFound = 0;
\r
274 if(!(repoClient instanceof RepositoryJavaClientImpl)) {
\r
275 throw new InternalError("updateAuthorityRefDocs() called with unknown repoClient type!");
\r
278 final int pageSize = N_OBJS_TO_UPDATE_PER_LOOP;
\r
279 int pageNumProcessed = 1;
\r
280 while(true) { // Keep looping until we find all the refs.
\r
281 logger.debug("updateAuthorityRefDocs working on page: "+pageNumProcessed);
\r
282 // Note that we always ask the Repo for the first page, since each page we process
\r
283 // should not be found in successive searches. Slightly inefficient, but more
\r
284 // reliable (stateless).
\r
285 DocumentModelList docList = findAuthorityRefDocs(ctx, repoClient, repoSession,
\r
286 getRefNameServiceTypes(), oldRefName, refPropName,
\r
287 queriedServiceBindings, authRefFieldsByService, pageSize, 0, false);
\r
289 if((docList == null) // found no authRef fields - nothing to do
\r
290 || (docList.size() == 0)) { // No more to handle
\r
291 logger.debug("updateAuthorityRefDocs no more results");
\r
294 logger.debug("updateAuthorityRefDocs curr page result list size: "+docList.size());
\r
295 int nRefsFoundThisPage = processRefObjsDocList(docList, oldRefName, queriedServiceBindings, authRefFieldsByService,
\r
297 if(nRefsFoundThisPage>0) {
\r
298 ((RepositoryJavaClientImpl)repoClient).saveDocListWithoutHandlerProcessing(ctx, repoSession, docList, true);
\r
299 nRefsFound += nRefsFoundThisPage;
\r
301 pageNumProcessed++;
\r
303 } catch(Exception e) {
\r
304 logger.error("Internal error updating the AuthorityRefDocs: " + e.getLocalizedMessage());
\r
305 logger.debug(Tools.errorToString(e, true));
\r
307 logger.debug("updateAuthorityRefDocs replaced a total of: "+nRefsFound);
\r
311 private static DocumentModelList findAuthorityRefDocs(
\r
312 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
\r
313 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient,
\r
314 RepositoryInstance repoSession,
\r
315 List<String> serviceTypes,
\r
317 String refPropName,
\r
318 Map<String, ServiceBindingType> queriedServiceBindings,
\r
319 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService,
\r
320 int pageSize, int pageNum, boolean computeTotal) throws DocumentException, DocumentNotFoundException {
\r
322 // Get the service bindings for this tenant
\r
323 TenantBindingConfigReaderImpl tReader =
\r
324 ServiceMain.getInstance().getTenantBindingConfigReader();
\r
325 // We need to get all the procedures, authorities, and objects.
\r
326 List<ServiceBindingType> servicebindings = tReader.getServiceBindingsByType(ctx.getTenantId(), serviceTypes);
\r
327 if (servicebindings == null || servicebindings.isEmpty()) {
\r
328 logger.error("RefNameServiceUtils.getAuthorityRefDocs: No services bindings found, cannot proceed!");
\r
332 // Need to escape the quotes in the refName
\r
333 // TODO What if they are already escaped?
\r
334 String escapedRefName = refName.replaceAll("'", "\\\\'");
\r
335 ArrayList<String> docTypes = new ArrayList<String>();
\r
337 String query = computeWhereClauseForAuthorityRefDocs(escapedRefName, refPropName, docTypes, servicebindings,
\r
338 queriedServiceBindings, authRefFieldsByService );
\r
339 if (query == null) { // found no authRef fields - nothing to query
\r
342 // Now we have to issue the search
\r
343 RepositoryJavaClientImpl nuxeoRepoClient = (RepositoryJavaClientImpl)repoClient;
\r
344 DocumentWrapper<DocumentModelList> docListWrapper = nuxeoRepoClient.findDocs(ctx, repoSession,
\r
345 docTypes, query, pageSize, pageNum, computeTotal);
\r
346 // Now we gather the info for each document into the list and return
\r
347 DocumentModelList docList = docListWrapper.getWrappedObject();
\r
351 private static final boolean READY_FOR_COMPLEX_QUERY = true;
\r
353 private static String computeWhereClauseForAuthorityRefDocs(
\r
354 String escapedRefName,
\r
355 String refPropName,
\r
356 ArrayList<String> docTypes,
\r
357 List<ServiceBindingType> servicebindings,
\r
358 Map<String, ServiceBindingType> queriedServiceBindings,
\r
359 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService ) {
\r
360 StringBuilder whereClause = new StringBuilder();
\r
361 boolean fFirst = true;
\r
362 List<String> authRefFieldPaths;
\r
363 for (ServiceBindingType sb : servicebindings) {
\r
364 // Gets the property names for each part, qualified with the part label (which
\r
365 // is also the table name, the way that the repository works).
\r
366 authRefFieldPaths =
\r
367 ServiceBindingUtils.getAllPartsPropertyValues(sb,
\r
368 refPropName, ServiceBindingUtils.QUALIFIED_PROP_NAMES);
\r
369 if (authRefFieldPaths.isEmpty()) {
\r
372 ArrayList<AuthRefConfigInfo> authRefsInfo = new ArrayList<AuthRefConfigInfo>();
\r
373 for(String spec:authRefFieldPaths) {
\r
374 AuthRefConfigInfo arci = new AuthRefConfigInfo(spec);
\r
375 authRefsInfo.add(arci);
\r
378 String docType = sb.getObject().getName();
\r
379 queriedServiceBindings.put(docType, sb);
\r
380 authRefFieldsByService.put(docType, authRefsInfo);
\r
381 docTypes.add(docType);
\r
382 for (AuthRefConfigInfo arci : authRefsInfo) {
\r
383 // Build up the where clause for each authRef field
\r
384 if(!READY_FOR_COMPLEX_QUERY) { // filter complex field references
\r
385 if(arci.pathEls.length>1)
\r
386 continue; // skip this one
\r
391 whereClause.append(" OR ");
\r
393 //whereClause.append(prefix);
\r
394 whereClause.append(arci.getFullPath());
\r
395 whereClause.append("='");
\r
396 whereClause.append(escapedRefName);
\r
397 whereClause.append("'");
\r
401 String whereClauseStr = whereClause.toString(); // for debugging
\r
402 if (logger.isTraceEnabled()) {
\r
403 logger.trace("The 'where' clause of the xyz method is: ", whereClauseStr);
\r
406 if (fFirst) { // found no authRef fields - nothing to query
\r
409 return whereClause.toString();
\r
414 * Runs through the list of found docs, processing them.
\r
415 * If list is non-null, then processing means gather the info for items.
\r
416 * If list is null, and newRefName is non-null, then processing means replacing and updating.
\r
417 * If processing/updating, this must be called in teh context of an open session, and caller
\r
418 * must release Session after calling this.
\r
421 private static int processRefObjsDocList(
\r
422 DocumentModelList docList,
\r
424 Map<String, ServiceBindingType> queriedServiceBindings,
\r
425 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService,
\r
426 List<AuthorityRefDocList.AuthorityRefDocItem> list,
\r
427 String newAuthorityRefName) {
\r
428 Iterator<DocumentModel> iter = docList.iterator();
\r
429 int nRefsFoundTotal = 0;
\r
430 while (iter.hasNext()) {
\r
431 DocumentModel docModel = iter.next();
\r
432 AuthorityRefDocList.AuthorityRefDocItem ilistItem;
\r
434 String docType = docModel.getDocumentType().getName();
\r
435 ServiceBindingType sb = queriedServiceBindings.get(docType);
\r
437 throw new RuntimeException(
\r
438 "getAuthorityRefDocs: No Service Binding for docType: " + docType);
\r
440 String serviceContextPath = "/" + sb.getName().toLowerCase() + "/";
\r
442 if(list == null) { // no list - should be update refName case.
\r
443 if(newAuthorityRefName==null) {
\r
444 throw new InternalError("processRefObjsDocList() called with neither an itemList nor a new RefName!");
\r
447 } else { // Have a list - refObjs case
\r
448 if(newAuthorityRefName!=null) {
\r
449 throw new InternalError("processRefObjsDocList() called with both an itemList and a new RefName!");
\r
451 ilistItem = new AuthorityRefDocList.AuthorityRefDocItem();
\r
452 String csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
\r
453 ilistItem.setDocId(csid);
\r
454 ilistItem.setUri(serviceContextPath + csid);
\r
456 ilistItem.setUpdatedAt(DocHandlerBase.getUpdatedAtAsString(docModel));
\r
457 } catch(Exception e) {
\r
458 logger.error("Error getting udpatedAt value for doc ["+csid+"]: "+e.getLocalizedMessage());
\r
460 // The id and URI are the same on all doctypes
\r
461 ilistItem.setDocType(docType);
\r
462 ilistItem.setDocNumber(
\r
463 ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NUMBER_PROP, docModel));
\r
464 ilistItem.setDocName(
\r
465 ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NAME_PROP, docModel));
\r
467 // Now, we have to loop over the authRefFieldsByService to figure
\r
468 // out which field(s) matched this.
\r
469 List<AuthRefConfigInfo> matchingAuthRefFields = authRefFieldsByService.get(docType);
\r
470 if (matchingAuthRefFields == null || matchingAuthRefFields.isEmpty()) {
\r
471 throw new RuntimeException(
\r
472 "getAuthorityRefDocs: internal logic error: can't fetch authRefFields for DocType.");
\r
474 //String authRefAncestorField = "";
\r
475 //String authRefDescendantField = "";
\r
476 //String sourceField = "";
\r
477 int nRefsFoundInDoc = 0;
\r
479 ArrayList<RefNameServiceUtils.AuthRefInfo> foundProps
\r
480 = new ArrayList<RefNameServiceUtils.AuthRefInfo>();
\r
482 findAuthRefPropertiesInDoc(docModel, matchingAuthRefFields, refName, foundProps);
\r
483 for(RefNameServiceUtils.AuthRefInfo ari:foundProps) {
\r
484 if(ilistItem != null) {
\r
485 if(nRefsFoundInDoc == 0) { // First one?
\r
486 ilistItem.setSourceField(ari.getQualifiedDisplayName());
\r
487 } else { // duplicates from one object
\r
488 ilistItem = cloneAuthRefDocItem(ilistItem, ari.getQualifiedDisplayName());
\r
490 list.add(ilistItem);
\r
491 } else { // update refName case
\r
492 Property propToUpdate = ari.getProperty();
\r
493 propToUpdate.setValue(newAuthorityRefName);
\r
497 } catch (ClientException ce) {
\r
498 throw new RuntimeException(
\r
499 "getAuthorityRefDocs: Problem fetching values from repo: " + ce.getLocalizedMessage());
\r
501 if (nRefsFoundInDoc == 0) {
\r
502 throw new RuntimeException(
\r
503 "getAuthorityRefDocs: Could not find refname in object:"
\r
504 + docType + ":" + NuxeoUtils.getCsid(docModel));
\r
506 nRefsFoundTotal += nRefsFoundInDoc;
\r
508 return nRefsFoundTotal;
\r
511 private static AuthorityRefDocList.AuthorityRefDocItem cloneAuthRefDocItem(
\r
512 AuthorityRefDocList.AuthorityRefDocItem ilistItem, String sourceField) {
\r
513 AuthorityRefDocList.AuthorityRefDocItem newlistItem = new AuthorityRefDocList.AuthorityRefDocItem();
\r
514 newlistItem.setDocId(ilistItem.getDocId());
\r
515 newlistItem.setDocName(ilistItem.getDocName());
\r
516 newlistItem.setDocNumber(ilistItem.getDocNumber());
\r
517 newlistItem.setDocType(ilistItem.getDocType());
\r
518 newlistItem.setUri(ilistItem.getUri());
\r
519 newlistItem.setSourceField(sourceField);
\r
520 return newlistItem;
\r
523 public static List<AuthRefInfo> findAuthRefPropertiesInDoc(
\r
524 DocumentModel docModel,
\r
525 List<AuthRefConfigInfo> authRefFieldInfo,
\r
526 String refNameToMatch,
\r
527 List<AuthRefInfo> foundProps
\r
529 // Assume that authRefFieldInfo is keyed by the field name (possibly mapped for UI)
\r
530 // and the values are elPaths to the field, where intervening group structures in
\r
531 // lists of complex structures are replaced with "*". Thus, valid paths include
\r
532 // the following (note that the ServiceBindingUtils prepend schema names to configured values):
\r
533 // "schemaname:fieldname"
\r
534 // "schemaname:scalarlistname"
\r
535 // "schemaname:complexfieldname/fieldname"
\r
536 // "schemaname:complexlistname/*/fieldname"
\r
537 // "schemaname:complexlistname/*/scalarlistname"
\r
538 // "schemaname:complexlistname/*/complexfieldname/fieldname"
\r
539 // "schemaname:complexlistname/*/complexlistname/*/fieldname"
\r
541 for (AuthRefConfigInfo arci : authRefFieldInfo) {
\r
543 // Get first property and work down as needed.
\r
544 Property prop = docModel.getProperty(arci.pathEls[0]);
\r
545 findAuthRefPropertiesInProperty(foundProps, prop, arci, 0, refNameToMatch);
\r
546 } catch(Exception e) {
\r
547 logger.error("Problem fetching property: "+arci.pathEls[0]);
\r
553 public static List<AuthRefInfo> findAuthRefPropertiesInProperty(
\r
554 List<AuthRefInfo> foundProps,
\r
556 AuthRefConfigInfo arci,
\r
557 int pathStartIndex, // Supports recursion and we work down the path
\r
558 String refNameToMatch
\r
560 if (pathStartIndex >= arci.pathEls.length) {
\r
561 throw new ArrayIndexOutOfBoundsException("Index = "+pathStartIndex+" for path: "
\r
562 +arci.pathEls.toString());
\r
564 AuthRefInfo ari = null;
\r
565 if (prop == null) {
\r
569 if (prop instanceof StringProperty) { // scalar string
\r
570 addARIifMatches(refNameToMatch, arci, prop, foundProps);
\r
571 } else if(prop instanceof List) {
\r
572 List<Property> propList = (List<Property>)prop;
\r
573 // run through list. Must either be list of Strings, or Complex
\r
574 for (Property listItemProp : propList) {
\r
575 if(listItemProp instanceof StringProperty) {
\r
576 if(arci.pathEls.length-pathStartIndex != 1) {
\r
577 logger.error("Configuration for authRefs does not match schema structure: "
\r
578 +arci.pathEls.toString());
\r
581 addARIifMatches(refNameToMatch, arci, listItemProp, foundProps);
\r
583 } else if(listItemProp.isComplex()) {
\r
584 // Just recurse to handle this. Note that since this is a list of complex,
\r
585 // which should look like listName/*/... we add 2 to the path start index
\r
586 findAuthRefPropertiesInProperty(foundProps, listItemProp, arci,
\r
587 pathStartIndex+2, refNameToMatch);
\r
589 logger.error("Configuration for authRefs does not match schema structure: "
\r
590 +arci.pathEls.toString());
\r
594 } else if(prop.isComplex()) {
\r
595 String localPropName = arci.pathEls[pathStartIndex];
\r
597 Property localProp = prop.get(localPropName);
\r
598 // Now just recurse, pushing down the path 1 step
\r
599 findAuthRefPropertiesInProperty(foundProps, localProp, arci,
\r
600 pathStartIndex, refNameToMatch);
\r
601 } catch(PropertyNotFoundException pnfe) {
\r
602 logger.error("Could not find property: ["+localPropName+"] in path: "+
\r
603 arci.getFullPath());
\r
604 // Fall through - ari will be null and we will continue...
\r
607 logger.error("Configuration for authRefs does not match schema structure: "
\r
608 +arci.pathEls.toString());
\r
612 foundProps.add(ari); //FIXME: REM - This is dead code. 'ari' is never touched after being initalized to null. Why?
\r
618 private static void addARIifMatches(
\r
619 String refNameToMatch,
\r
620 AuthRefConfigInfo arci,
\r
622 List<AuthRefInfo> foundProps) {
\r
623 // Need to either match a passed refName
\r
624 // OR have no refName to match but be non-empty
\r
626 String value = (String)prop.getValue();
\r
627 if(((refNameToMatch!=null) && refNameToMatch.equals(value))
\r
628 || ((refNameToMatch==null) && Tools.notBlank(value))) {
\r
630 logger.debug("Found a match on property: "+prop.getPath()+" with value: ["+value+"]");
\r
631 AuthRefInfo ari = new AuthRefInfo(arci, prop);
\r
632 foundProps.add(ari);
\r
634 } catch(PropertyException pe) {
\r
635 logger.debug("PropertyException on: "+prop.getPath()+pe.getLocalizedMessage());
\r
640 * Identifies whether the refName was found in the supplied field.
\r
641 * If passed a new RefName, will set that into fields in which the old one was found.
\r
645 * * Repeatable scalar fields (aka multi-valued fields)
\r
647 * Does not work for:
\r
648 * * Structured fields (complexTypes)
\r
649 * * Repeatable structured fields (repeatable complexTypes)
\r
650 private static int refNameFoundInField(String oldRefName, Property fieldValue, String newRefName) {
\r
652 if (fieldValue instanceof List) {
\r
653 List<Property> fieldValueList = (List) fieldValue;
\r
654 for (Property listItemValue : fieldValueList) {
\r
656 if ((listItemValue instanceof StringProperty)
\r
657 && oldRefName.equalsIgnoreCase((String)listItemValue.getValue())) {
\r
659 if(newRefName!=null) {
\r
660 fieldValue.setValue(newRefName);
\r
662 // We cannot quit after the first, if we are replacing values.
\r
663 // If we are just looking (not replacing), finding one is enough.
\r
667 } catch( PropertyException pe ) {}
\r
671 if ((fieldValue instanceof StringProperty)
\r
672 && oldRefName.equalsIgnoreCase((String)fieldValue.getValue())) {
\r
674 if(newRefName!=null) {
\r
675 fieldValue.setValue(newRefName);
\r
678 } catch( PropertyException pe ) {}
\r