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 ) throws Exception {
\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
308 logger.debug("updateAuthorityRefDocs replaced a total of: "+nRefsFound);
\r
312 private static DocumentModelList findAuthorityRefDocs(
\r
313 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
\r
314 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient,
\r
315 RepositoryInstance repoSession,
\r
316 List<String> serviceTypes,
\r
318 String refPropName,
\r
319 Map<String, ServiceBindingType> queriedServiceBindings,
\r
320 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService,
\r
321 int pageSize, int pageNum, boolean computeTotal) throws DocumentException, DocumentNotFoundException {
\r
323 // Get the service bindings for this tenant
\r
324 TenantBindingConfigReaderImpl tReader =
\r
325 ServiceMain.getInstance().getTenantBindingConfigReader();
\r
326 // We need to get all the procedures, authorities, and objects.
\r
327 List<ServiceBindingType> servicebindings = tReader.getServiceBindingsByType(ctx.getTenantId(), serviceTypes);
\r
328 if (servicebindings == null || servicebindings.isEmpty()) {
\r
329 logger.error("RefNameServiceUtils.getAuthorityRefDocs: No services bindings found, cannot proceed!");
\r
333 // Need to escape the quotes in the refName
\r
334 // TODO What if they are already escaped?
\r
335 String escapedRefName = refName.replaceAll("'", "\\\\'");
\r
336 ArrayList<String> docTypes = new ArrayList<String>();
\r
338 String query = computeWhereClauseForAuthorityRefDocs(escapedRefName, refPropName, docTypes, servicebindings,
\r
339 queriedServiceBindings, authRefFieldsByService );
\r
340 if (query == null) { // found no authRef fields - nothing to query
\r
343 // Now we have to issue the search
\r
344 RepositoryJavaClientImpl nuxeoRepoClient = (RepositoryJavaClientImpl)repoClient;
\r
345 DocumentWrapper<DocumentModelList> docListWrapper = nuxeoRepoClient.findDocs(ctx, repoSession,
\r
346 docTypes, query, pageSize, pageNum, computeTotal);
\r
347 // Now we gather the info for each document into the list and return
\r
348 DocumentModelList docList = docListWrapper.getWrappedObject();
\r
352 private static final boolean READY_FOR_COMPLEX_QUERY = true;
\r
354 private static String computeWhereClauseForAuthorityRefDocs(
\r
355 String escapedRefName,
\r
356 String refPropName,
\r
357 ArrayList<String> docTypes,
\r
358 List<ServiceBindingType> servicebindings,
\r
359 Map<String, ServiceBindingType> queriedServiceBindings,
\r
360 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService ) {
\r
361 StringBuilder whereClause = new StringBuilder();
\r
362 boolean fFirst = true;
\r
363 List<String> authRefFieldPaths;
\r
364 for (ServiceBindingType sb : servicebindings) {
\r
365 // Gets the property names for each part, qualified with the part label (which
\r
366 // is also the table name, the way that the repository works).
\r
367 authRefFieldPaths =
\r
368 ServiceBindingUtils.getAllPartsPropertyValues(sb,
\r
369 refPropName, ServiceBindingUtils.QUALIFIED_PROP_NAMES);
\r
370 if (authRefFieldPaths.isEmpty()) {
\r
373 ArrayList<AuthRefConfigInfo> authRefsInfo = new ArrayList<AuthRefConfigInfo>();
\r
374 for(String spec:authRefFieldPaths) {
\r
375 AuthRefConfigInfo arci = new AuthRefConfigInfo(spec);
\r
376 authRefsInfo.add(arci);
\r
379 String docType = sb.getObject().getName();
\r
380 queriedServiceBindings.put(docType, sb);
\r
381 authRefFieldsByService.put(docType, authRefsInfo);
\r
382 docTypes.add(docType);
\r
383 for (AuthRefConfigInfo arci : authRefsInfo) {
\r
384 // Build up the where clause for each authRef field
\r
385 if(!READY_FOR_COMPLEX_QUERY) { // filter complex field references
\r
386 if(arci.pathEls.length>1)
\r
387 continue; // skip this one
\r
392 whereClause.append(" OR ");
\r
394 //whereClause.append(prefix);
\r
395 whereClause.append(arci.getFullPath());
\r
396 whereClause.append("='");
\r
397 whereClause.append(escapedRefName);
\r
398 whereClause.append("'");
\r
402 String whereClauseStr = whereClause.toString(); // for debugging
\r
403 if (logger.isTraceEnabled()) {
\r
404 logger.trace("The 'where' clause of the xyz method is: ", whereClauseStr);
\r
407 if (fFirst) { // found no authRef fields - nothing to query
\r
410 return whereClause.toString();
\r
415 * Runs through the list of found docs, processing them.
\r
416 * If list is non-null, then processing means gather the info for items.
\r
417 * If list is null, and newRefName is non-null, then processing means replacing and updating.
\r
418 * If processing/updating, this must be called in teh context of an open session, and caller
\r
419 * must release Session after calling this.
\r
422 private static int processRefObjsDocList(
\r
423 DocumentModelList docList,
\r
425 Map<String, ServiceBindingType> queriedServiceBindings,
\r
426 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService,
\r
427 List<AuthorityRefDocList.AuthorityRefDocItem> list,
\r
428 String newAuthorityRefName) {
\r
429 Iterator<DocumentModel> iter = docList.iterator();
\r
430 int nRefsFoundTotal = 0;
\r
431 while (iter.hasNext()) {
\r
432 DocumentModel docModel = iter.next();
\r
433 AuthorityRefDocList.AuthorityRefDocItem ilistItem;
\r
435 String docType = docModel.getDocumentType().getName();
\r
436 ServiceBindingType sb = queriedServiceBindings.get(docType);
\r
438 throw new RuntimeException(
\r
439 "getAuthorityRefDocs: No Service Binding for docType: " + docType);
\r
441 String serviceContextPath = "/" + sb.getName().toLowerCase() + "/";
\r
443 if(list == null) { // no list - should be update refName case.
\r
444 if(newAuthorityRefName==null) {
\r
445 throw new InternalError("processRefObjsDocList() called with neither an itemList nor a new RefName!");
\r
448 } else { // Have a list - refObjs case
\r
449 if(newAuthorityRefName!=null) {
\r
450 throw new InternalError("processRefObjsDocList() called with both an itemList and a new RefName!");
\r
452 ilistItem = new AuthorityRefDocList.AuthorityRefDocItem();
\r
453 String csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
\r
454 ilistItem.setDocId(csid);
\r
455 ilistItem.setUri(serviceContextPath + csid);
\r
457 ilistItem.setUpdatedAt(DocHandlerBase.getUpdatedAtAsString(docModel));
\r
458 } catch(Exception e) {
\r
459 logger.error("Error getting udpatedAt value for doc ["+csid+"]: "+e.getLocalizedMessage());
\r
461 // The id and URI are the same on all doctypes
\r
462 ilistItem.setDocType(docType);
\r
463 ilistItem.setDocNumber(
\r
464 ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NUMBER_PROP, docModel));
\r
465 ilistItem.setDocName(
\r
466 ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NAME_PROP, docModel));
\r
468 // Now, we have to loop over the authRefFieldsByService to figure
\r
469 // out which field(s) matched this.
\r
470 List<AuthRefConfigInfo> matchingAuthRefFields = authRefFieldsByService.get(docType);
\r
471 if (matchingAuthRefFields == null || matchingAuthRefFields.isEmpty()) {
\r
472 throw new RuntimeException(
\r
473 "getAuthorityRefDocs: internal logic error: can't fetch authRefFields for DocType.");
\r
475 //String authRefAncestorField = "";
\r
476 //String authRefDescendantField = "";
\r
477 //String sourceField = "";
\r
478 int nRefsFoundInDoc = 0;
\r
480 ArrayList<RefNameServiceUtils.AuthRefInfo> foundProps
\r
481 = new ArrayList<RefNameServiceUtils.AuthRefInfo>();
\r
483 findAuthRefPropertiesInDoc(docModel, matchingAuthRefFields, refName, foundProps);
\r
484 for(RefNameServiceUtils.AuthRefInfo ari:foundProps) {
\r
485 if(ilistItem != null) {
\r
486 if(nRefsFoundInDoc == 0) { // First one?
\r
487 ilistItem.setSourceField(ari.getQualifiedDisplayName());
\r
488 } else { // duplicates from one object
\r
489 ilistItem = cloneAuthRefDocItem(ilistItem, ari.getQualifiedDisplayName());
\r
491 list.add(ilistItem);
\r
492 } else { // update refName case
\r
493 Property propToUpdate = ari.getProperty();
\r
494 propToUpdate.setValue(newAuthorityRefName);
\r
498 } catch (ClientException ce) {
\r
499 throw new RuntimeException(
\r
500 "getAuthorityRefDocs: Problem fetching values from repo: " + ce.getLocalizedMessage());
\r
502 if (nRefsFoundInDoc == 0) {
\r
503 throw new RuntimeException(
\r
504 "getAuthorityRefDocs: Could not find refname in object:"
\r
505 + docType + ":" + NuxeoUtils.getCsid(docModel));
\r
507 nRefsFoundTotal += nRefsFoundInDoc;
\r
509 return nRefsFoundTotal;
\r
512 private static AuthorityRefDocList.AuthorityRefDocItem cloneAuthRefDocItem(
\r
513 AuthorityRefDocList.AuthorityRefDocItem ilistItem, String sourceField) {
\r
514 AuthorityRefDocList.AuthorityRefDocItem newlistItem = new AuthorityRefDocList.AuthorityRefDocItem();
\r
515 newlistItem.setDocId(ilistItem.getDocId());
\r
516 newlistItem.setDocName(ilistItem.getDocName());
\r
517 newlistItem.setDocNumber(ilistItem.getDocNumber());
\r
518 newlistItem.setDocType(ilistItem.getDocType());
\r
519 newlistItem.setUri(ilistItem.getUri());
\r
520 newlistItem.setSourceField(sourceField);
\r
521 return newlistItem;
\r
524 public static List<AuthRefInfo> findAuthRefPropertiesInDoc(
\r
525 DocumentModel docModel,
\r
526 List<AuthRefConfigInfo> authRefFieldInfo,
\r
527 String refNameToMatch,
\r
528 List<AuthRefInfo> foundProps
\r
530 // Assume that authRefFieldInfo is keyed by the field name (possibly mapped for UI)
\r
531 // and the values are elPaths to the field, where intervening group structures in
\r
532 // lists of complex structures are replaced with "*". Thus, valid paths include
\r
533 // the following (note that the ServiceBindingUtils prepend schema names to configured values):
\r
534 // "schemaname:fieldname"
\r
535 // "schemaname:scalarlistname"
\r
536 // "schemaname:complexfieldname/fieldname"
\r
537 // "schemaname:complexlistname/*/fieldname"
\r
538 // "schemaname:complexlistname/*/scalarlistname"
\r
539 // "schemaname:complexlistname/*/complexfieldname/fieldname"
\r
540 // "schemaname:complexlistname/*/complexlistname/*/fieldname"
\r
542 for (AuthRefConfigInfo arci : authRefFieldInfo) {
\r
544 // Get first property and work down as needed.
\r
545 Property prop = docModel.getProperty(arci.pathEls[0]);
\r
546 findAuthRefPropertiesInProperty(foundProps, prop, arci, 0, refNameToMatch);
\r
547 } catch(Exception e) {
\r
548 logger.error("Problem fetching property: "+arci.pathEls[0]);
\r
554 public static List<AuthRefInfo> findAuthRefPropertiesInProperty(
\r
555 List<AuthRefInfo> foundProps,
\r
557 AuthRefConfigInfo arci,
\r
558 int pathStartIndex, // Supports recursion and we work down the path
\r
559 String refNameToMatch
\r
561 if (pathStartIndex >= arci.pathEls.length) {
\r
562 throw new ArrayIndexOutOfBoundsException("Index = "+pathStartIndex+" for path: "
\r
563 +arci.pathEls.toString());
\r
565 AuthRefInfo ari = null;
\r
566 if (prop == null) {
\r
570 if (prop instanceof StringProperty) { // scalar string
\r
571 addARIifMatches(refNameToMatch, arci, prop, foundProps);
\r
572 } else if(prop instanceof List) {
\r
573 List<Property> propList = (List<Property>)prop;
\r
574 // run through list. Must either be list of Strings, or Complex
\r
575 for (Property listItemProp : propList) {
\r
576 if(listItemProp instanceof StringProperty) {
\r
577 if(arci.pathEls.length-pathStartIndex != 1) {
\r
578 logger.error("Configuration for authRefs does not match schema structure: "
\r
579 +arci.pathEls.toString());
\r
582 addARIifMatches(refNameToMatch, arci, listItemProp, foundProps);
\r
584 } else if(listItemProp.isComplex()) {
\r
585 // Just recurse to handle this. Note that since this is a list of complex,
\r
586 // which should look like listName/*/... we add 2 to the path start index
\r
587 findAuthRefPropertiesInProperty(foundProps, listItemProp, arci,
\r
588 pathStartIndex+2, refNameToMatch);
\r
590 logger.error("Configuration for authRefs does not match schema structure: "
\r
591 +arci.pathEls.toString());
\r
595 } else if(prop.isComplex()) {
\r
596 String localPropName = arci.pathEls[pathStartIndex];
\r
598 Property localProp = prop.get(localPropName);
\r
599 // Now just recurse, pushing down the path 1 step
\r
600 findAuthRefPropertiesInProperty(foundProps, localProp, arci,
\r
601 pathStartIndex, refNameToMatch);
\r
602 } catch(PropertyNotFoundException pnfe) {
\r
603 logger.error("Could not find property: ["+localPropName+"] in path: "+
\r
604 arci.getFullPath());
\r
605 // Fall through - ari will be null and we will continue...
\r
608 logger.error("Configuration for authRefs does not match schema structure: "
\r
609 +arci.pathEls.toString());
\r
613 foundProps.add(ari); //FIXME: REM - This is dead code. 'ari' is never touched after being initalized to null. Why?
\r
619 private static void addARIifMatches(
\r
620 String refNameToMatch,
\r
621 AuthRefConfigInfo arci,
\r
623 List<AuthRefInfo> foundProps) {
\r
624 // Need to either match a passed refName
\r
625 // OR have no refName to match but be non-empty
\r
627 String value = (String)prop.getValue();
\r
628 if(((refNameToMatch!=null) && refNameToMatch.equals(value))
\r
629 || ((refNameToMatch==null) && Tools.notBlank(value))) {
\r
631 logger.debug("Found a match on property: "+prop.getPath()+" with value: ["+value+"]");
\r
632 AuthRefInfo ari = new AuthRefInfo(arci, prop);
\r
633 foundProps.add(ari);
\r
635 } catch(PropertyException pe) {
\r
636 logger.debug("PropertyException on: "+prop.getPath()+pe.getLocalizedMessage());
\r
641 * Identifies whether the refName was found in the supplied field.
\r
642 * If passed a new RefName, will set that into fields in which the old one was found.
\r
646 * * Repeatable scalar fields (aka multi-valued fields)
\r
648 * Does not work for:
\r
649 * * Structured fields (complexTypes)
\r
650 * * Repeatable structured fields (repeatable complexTypes)
\r
651 private static int refNameFoundInField(String oldRefName, Property fieldValue, String newRefName) {
\r
653 if (fieldValue instanceof List) {
\r
654 List<Property> fieldValueList = (List) fieldValue;
\r
655 for (Property listItemValue : fieldValueList) {
\r
657 if ((listItemValue instanceof StringProperty)
\r
658 && oldRefName.equalsIgnoreCase((String)listItemValue.getValue())) {
\r
660 if(newRefName!=null) {
\r
661 fieldValue.setValue(newRefName);
\r
663 // We cannot quit after the first, if we are replacing values.
\r
664 // If we are just looking (not replacing), finding one is enough.
\r
668 } catch( PropertyException pe ) {}
\r
672 if ((fieldValue instanceof StringProperty)
\r
673 && oldRefName.equalsIgnoreCase((String)fieldValue.getValue())) {
\r
675 if(newRefName!=null) {
\r
676 fieldValue.setValue(newRefName);
\r
679 } catch( PropertyException pe ) {}
\r