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.security.SecurityUtils;
\r
62 import org.collectionspace.services.common.service.ServiceBindingType;
\r
63 import org.collectionspace.services.jaxb.AbstractCommonList;
\r
64 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
\r
66 import com.sun.xml.bind.v2.runtime.unmarshaller.XsiNilLoader.Array;
\r
69 * RefNameServiceUtils is a collection of services utilities related to refName usage.
\r
71 * $LastChangedRevision: $
\r
72 * $LastChangedDate: $
\r
74 public class RefNameServiceUtils {
\r
76 public static class AuthRefConfigInfo {
\r
77 public String getQualifiedDisplayName() {
\r
78 return(Tools.isBlank(schema))?
\r
79 displayName:DocumentUtils.appendSchemaName(schema, displayName);
\r
81 public String getDisplayName() {
\r
84 public void setDisplayName(String displayName) {
\r
85 this.displayName = displayName;
\r
89 public String getSchema() {
\r
92 public void setSchema(String schema) {
\r
93 this.schema = schema;
\r
95 public String getFullPath() {
\r
98 public void setFullPath(String fullPath) {
\r
99 this.fullPath = fullPath;
\r
102 protected String[] pathEls;
\r
103 public AuthRefConfigInfo(AuthRefConfigInfo arci) {
\r
104 this.displayName = arci.displayName;
\r
105 this.schema = arci.schema;
\r
106 this.fullPath = arci.fullPath;
\r
107 this.pathEls = arci.pathEls;
\r
108 // Skip the pathElse check, since we are creatign from another (presumably valid) arci.
\r
111 public AuthRefConfigInfo(String displayName, String schema, String fullPath, String[] pathEls) {
\r
112 this.displayName = displayName;
\r
113 this.schema = schema;
\r
114 this.fullPath = fullPath;
\r
115 this.pathEls = pathEls;
\r
119 // Split a config value string like "intakes_common:collector", or
\r
120 // "collectionobjects_common:contentPeoples|contentPeople"
\r
121 // "collectionobjects_common:assocEventGroupList/*/assocEventPlace"
\r
122 // If has a pipe ('|') second part is a displayLabel, and first is path
\r
123 // Otherwise, entry is a path, and can use the last pathElement as displayName
\r
124 // Should be schema qualified.
\r
125 public AuthRefConfigInfo(String configString) {
\r
126 String[] pair = configString.split("\\|", 2);
\r
128 String displayName, fullPath;
\r
129 if(pair.length == 1) {
\r
130 // no label specifier, so we'll defer getting label
\r
131 fullPath = pair[0];
\r
132 pathEls = pair[0].split("/");
\r
133 displayName = pathEls[pathEls.length-1];
\r
135 fullPath = pair[0];
\r
136 pathEls = pair[0].split("/");
\r
137 displayName = pair[1];
\r
139 String[] schemaSplit = pathEls[0].split(":",2);
\r
141 if(schemaSplit.length==1) { // schema not specified
\r
144 schema = schemaSplit[0];
\r
145 if(pair.length == 1 && pathEls.length == 1) { // simplest case of field in top level schema, no labelll
\r
146 displayName = schemaSplit[1]; // Have to fix up displayName to have no schema
\r
149 this.displayName = displayName;
\r
150 this.schema = schema;
\r
151 this.fullPath = fullPath;
\r
152 this.pathEls = pathEls;
\r
156 protected void checkPathEls() {
\r
157 int len = pathEls.length;
\r
159 throw new InternalError("Bad values in authRef info - caller screwed up:"+fullPath);
\r
160 // Handle case of them putting a leading slash on the path
\r
161 if(len>1 && pathEls[0].endsWith(":")) {
\r
163 String[] newArray = new String[len];
\r
164 newArray[0] = pathEls[0]+pathEls[1];
\r
166 System.arraycopy(pathEls, 2, newArray, 1, len-1);
\r
168 pathEls = newArray;
\r
173 public static class AuthRefInfo extends AuthRefConfigInfo {
\r
174 public Property getProperty() {
\r
177 public void setProperty(Property property) {
\r
178 this.property = property;
\r
181 public AuthRefInfo(String displayName, String schema, String fullPath, String[] pathEls, Property prop) {
\r
182 super(displayName, schema, fullPath, pathEls);
\r
183 this.property = prop;
\r
185 public AuthRefInfo(AuthRefConfigInfo arci, Property prop) {
\r
187 this.property = prop;
\r
191 private static final Logger logger = LoggerFactory.getLogger(RefNameServiceUtils.class);
\r
193 private static ArrayList<String> refNameServiceTypes = null;
\r
195 public static List<AuthRefConfigInfo> getConfiguredAuthorityRefs(ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx) {
\r
196 List<String> authRefFields =
\r
197 ((AbstractServiceContextImpl) ctx).getAllPartsPropertyValues(
\r
198 ServiceBindingUtils.AUTH_REF_PROP, ServiceBindingUtils.QUALIFIED_PROP_NAMES);
\r
199 ArrayList<AuthRefConfigInfo> authRefsInfo = new ArrayList<AuthRefConfigInfo>(authRefFields.size());
\r
200 for(String spec:authRefFields) {
\r
201 AuthRefConfigInfo arci = new AuthRefConfigInfo(spec);
\r
202 authRefsInfo.add(arci);
\r
204 return authRefsInfo;
\r
207 public static AuthorityRefDocList getAuthorityRefDocs(
\r
208 RepositoryInstance repoSession,
\r
209 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
\r
210 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient,
\r
211 List<String> serviceTypes,
\r
213 String refPropName,
\r
214 int pageSize, int pageNum, boolean computeTotal)
\r
215 throws DocumentException, DocumentNotFoundException {
\r
216 AuthorityRefDocList wrapperList = new AuthorityRefDocList();
\r
217 AbstractCommonList commonList = (AbstractCommonList) wrapperList;
\r
218 commonList.setPageNum(pageNum);
\r
219 commonList.setPageSize(pageSize);
\r
220 List<AuthorityRefDocList.AuthorityRefDocItem> list =
\r
221 wrapperList.getAuthorityRefDocItem();
\r
223 Map<String, ServiceBindingType> queriedServiceBindings = new HashMap<String, ServiceBindingType>();
\r
224 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService = new HashMap<String, List<AuthRefConfigInfo>>();
\r
226 RepositoryJavaClientImpl nuxeoRepoClient = (RepositoryJavaClientImpl)repoClient;
\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
249 return wrapperList;
\r
252 private static ArrayList<String> getRefNameServiceTypes() {
\r
253 if(refNameServiceTypes == null) {
\r
254 refNameServiceTypes = new ArrayList<String>();
\r
255 refNameServiceTypes.add(ServiceBindingUtils.SERVICE_TYPE_AUTHORITY);
\r
256 refNameServiceTypes.add(ServiceBindingUtils.SERVICE_TYPE_OBJECT);
\r
257 refNameServiceTypes.add(ServiceBindingUtils.SERVICE_TYPE_PROCEDURE);
\r
259 return refNameServiceTypes;
\r
262 // Seems like a good value - no real data to set this well.
\r
263 private static final int N_OBJS_TO_UPDATE_PER_LOOP = 100;
\r
265 public static int updateAuthorityRefDocs(
\r
266 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
\r
267 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient,
\r
268 RepositoryInstance repoSession,
\r
271 String refPropName ) throws Exception {
\r
272 Map<String, ServiceBindingType> queriedServiceBindings = new HashMap<String, ServiceBindingType>();
\r
273 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService = new HashMap<String, List<AuthRefConfigInfo>>();
\r
274 int nRefsFound = 0;
\r
275 if(!(repoClient instanceof RepositoryJavaClientImpl)) {
\r
276 throw new InternalError("updateAuthorityRefDocs() called with unknown repoClient type!");
\r
279 final int pageSize = N_OBJS_TO_UPDATE_PER_LOOP;
\r
280 int pageNumProcessed = 1;
\r
281 while(true) { // Keep looping until we find all the refs.
\r
282 logger.debug("updateAuthorityRefDocs working on page: "+pageNumProcessed);
\r
283 // Note that we always ask the Repo for the first page, since each page we process
\r
284 // should not be found in successive searches. Slightly inefficient, but more
\r
285 // reliable (stateless).
\r
286 DocumentModelList docList = findAuthorityRefDocs(ctx, repoClient, repoSession,
\r
287 getRefNameServiceTypes(), oldRefName, refPropName,
\r
288 queriedServiceBindings, authRefFieldsByService, pageSize, 0, false);
\r
290 if((docList == null) // found no authRef fields - nothing to do
\r
291 || (docList.size() == 0)) { // No more to handle
\r
292 logger.debug("updateAuthorityRefDocs no more results");
\r
295 logger.debug("updateAuthorityRefDocs curr page result list size: "+docList.size());
\r
296 int nRefsFoundThisPage = processRefObjsDocList(docList, oldRefName, queriedServiceBindings, authRefFieldsByService,
\r
298 if(nRefsFoundThisPage>0) {
\r
299 ((RepositoryJavaClientImpl)repoClient).saveDocListWithoutHandlerProcessing(ctx, repoSession, docList, true);
\r
300 nRefsFound += nRefsFoundThisPage;
\r
302 pageNumProcessed++;
\r
304 } catch (Exception e) {
\r
305 logger.error("Internal error updating the AuthorityRefDocs: " + e.getLocalizedMessage());
\r
306 logger.debug(Tools.errorToString(e, true));
\r
309 logger.debug("updateAuthorityRefDocs replaced a total of: "+nRefsFound);
\r
313 private static DocumentModelList findAuthorityRefDocs(
\r
314 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
\r
315 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient,
\r
316 RepositoryInstance repoSession,
\r
317 List<String> serviceTypes,
\r
319 String refPropName,
\r
320 Map<String, ServiceBindingType> queriedServiceBindings,
\r
321 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService,
\r
322 int pageSize, int pageNum, boolean computeTotal) throws DocumentException, DocumentNotFoundException {
\r
324 // Get the service bindings for this tenant
\r
325 TenantBindingConfigReaderImpl tReader =
\r
326 ServiceMain.getInstance().getTenantBindingConfigReader();
\r
327 // We need to get all the procedures, authorities, and objects.
\r
328 List<ServiceBindingType> servicebindings = tReader.getServiceBindingsByType(ctx.getTenantId(), serviceTypes);
\r
329 if (servicebindings == null || servicebindings.isEmpty()) {
\r
330 logger.error("RefNameServiceUtils.getAuthorityRefDocs: No services bindings found, cannot proceed!");
\r
333 // Filter the list for current user rights
\r
334 servicebindings = SecurityUtils.getReadableServiceBindingsForCurrentUser(servicebindings);
\r
336 // Need to escape the quotes in the refName
\r
337 // TODO What if they are already escaped?
\r
338 String escapedRefName = refName.replaceAll("'", "\\\\'");
\r
339 ArrayList<String> docTypes = new ArrayList<String>();
\r
341 String query = computeWhereClauseForAuthorityRefDocs(escapedRefName, refPropName, docTypes, servicebindings,
\r
342 queriedServiceBindings, authRefFieldsByService );
\r
343 if (query == null) { // found no authRef fields - nothing to query
\r
346 // Now we have to issue the search
\r
347 RepositoryJavaClientImpl nuxeoRepoClient = (RepositoryJavaClientImpl)repoClient;
\r
348 DocumentWrapper<DocumentModelList> docListWrapper = nuxeoRepoClient.findDocs(ctx, repoSession,
\r
349 docTypes, query, pageSize, pageNum, computeTotal);
\r
350 // Now we gather the info for each document into the list and return
\r
351 DocumentModelList docList = docListWrapper.getWrappedObject();
\r
355 private static final boolean READY_FOR_COMPLEX_QUERY = true;
\r
357 private static String computeWhereClauseForAuthorityRefDocs(
\r
358 String escapedRefName,
\r
359 String refPropName,
\r
360 ArrayList<String> docTypes,
\r
361 List<ServiceBindingType> servicebindings,
\r
362 Map<String, ServiceBindingType> queriedServiceBindings,
\r
363 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService ) {
\r
364 StringBuilder whereClause = new StringBuilder();
\r
365 boolean fFirst = true;
\r
366 List<String> authRefFieldPaths;
\r
367 for (ServiceBindingType sb : servicebindings) {
\r
368 // Gets the property names for each part, qualified with the part label (which
\r
369 // is also the table name, the way that the repository works).
\r
370 authRefFieldPaths =
\r
371 ServiceBindingUtils.getAllPartsPropertyValues(sb,
\r
372 refPropName, ServiceBindingUtils.QUALIFIED_PROP_NAMES);
\r
373 if (authRefFieldPaths.isEmpty()) {
\r
376 ArrayList<AuthRefConfigInfo> authRefsInfo = new ArrayList<AuthRefConfigInfo>();
\r
377 for(String spec:authRefFieldPaths) {
\r
378 AuthRefConfigInfo arci = new AuthRefConfigInfo(spec);
\r
379 authRefsInfo.add(arci);
\r
382 String docType = sb.getObject().getName();
\r
383 queriedServiceBindings.put(docType, sb);
\r
384 authRefFieldsByService.put(docType, authRefsInfo);
\r
385 docTypes.add(docType);
\r
386 for (AuthRefConfigInfo arci : authRefsInfo) {
\r
387 // Build up the where clause for each authRef field
\r
388 if(!READY_FOR_COMPLEX_QUERY) { // filter complex field references
\r
389 if(arci.pathEls.length>1)
\r
390 continue; // skip this one
\r
395 whereClause.append(" OR ");
\r
397 //whereClause.append(prefix);
\r
398 whereClause.append(arci.getFullPath());
\r
399 whereClause.append("='");
\r
400 whereClause.append(escapedRefName);
\r
401 whereClause.append("'");
\r
405 String whereClauseStr = whereClause.toString(); // for debugging
\r
406 if (logger.isTraceEnabled()) {
\r
407 logger.trace("The 'where' clause of the xyz method is: ", whereClauseStr);
\r
410 if (fFirst) { // found no authRef fields - nothing to query
\r
413 return whereClause.toString();
\r
418 * Runs through the list of found docs, processing them.
\r
419 * If list is non-null, then processing means gather the info for items.
\r
420 * If list is null, and newRefName is non-null, then processing means replacing and updating.
\r
421 * If processing/updating, this must be called in teh context of an open session, and caller
\r
422 * must release Session after calling this.
\r
425 private static int processRefObjsDocList(
\r
426 DocumentModelList docList,
\r
428 Map<String, ServiceBindingType> queriedServiceBindings,
\r
429 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService,
\r
430 List<AuthorityRefDocList.AuthorityRefDocItem> list,
\r
431 String newAuthorityRefName) {
\r
432 Iterator<DocumentModel> iter = docList.iterator();
\r
433 int nRefsFoundTotal = 0;
\r
434 while (iter.hasNext()) {
\r
435 DocumentModel docModel = iter.next();
\r
436 AuthorityRefDocList.AuthorityRefDocItem ilistItem;
\r
438 String docType = docModel.getDocumentType().getName();
\r
439 docType = ServiceBindingUtils.getUnqualifiedTenantDocType(docType);
\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