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 ServiceBindingType sb = queriedServiceBindings.get(docType);
\r
441 throw new RuntimeException(
\r
442 "getAuthorityRefDocs: No Service Binding for docType: " + docType);
\r
444 String serviceContextPath = "/" + sb.getName().toLowerCase() + "/";
\r
446 if(list == null) { // no list - should be update refName case.
\r
447 if(newAuthorityRefName==null) {
\r
448 throw new InternalError("processRefObjsDocList() called with neither an itemList nor a new RefName!");
\r
451 } else { // Have a list - refObjs case
\r
452 if(newAuthorityRefName!=null) {
\r
453 throw new InternalError("processRefObjsDocList() called with both an itemList and a new RefName!");
\r
455 ilistItem = new AuthorityRefDocList.AuthorityRefDocItem();
\r
456 String csid = NuxeoUtils.getCsid(docModel);//NuxeoUtils.extractId(docModel.getPathAsString());
\r
457 ilistItem.setDocId(csid);
\r
458 ilistItem.setUri(serviceContextPath + csid);
\r
460 ilistItem.setUpdatedAt(DocHandlerBase.getUpdatedAtAsString(docModel));
\r
461 } catch(Exception e) {
\r
462 logger.error("Error getting udpatedAt value for doc ["+csid+"]: "+e.getLocalizedMessage());
\r
464 // The id and URI are the same on all doctypes
\r
465 ilistItem.setDocType(docType);
\r
466 ilistItem.setDocNumber(
\r
467 ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NUMBER_PROP, docModel));
\r
468 ilistItem.setDocName(
\r
469 ServiceBindingUtils.getMappedFieldInDoc(sb, ServiceBindingUtils.OBJ_NAME_PROP, docModel));
\r
471 // Now, we have to loop over the authRefFieldsByService to figure
\r
472 // out which field(s) matched this.
\r
473 List<AuthRefConfigInfo> matchingAuthRefFields = authRefFieldsByService.get(docType);
\r
474 if (matchingAuthRefFields == null || matchingAuthRefFields.isEmpty()) {
\r
475 throw new RuntimeException(
\r
476 "getAuthorityRefDocs: internal logic error: can't fetch authRefFields for DocType.");
\r
478 //String authRefAncestorField = "";
\r
479 //String authRefDescendantField = "";
\r
480 //String sourceField = "";
\r
481 int nRefsFoundInDoc = 0;
\r
483 ArrayList<RefNameServiceUtils.AuthRefInfo> foundProps
\r
484 = new ArrayList<RefNameServiceUtils.AuthRefInfo>();
\r
486 findAuthRefPropertiesInDoc(docModel, matchingAuthRefFields, refName, foundProps);
\r
487 for(RefNameServiceUtils.AuthRefInfo ari:foundProps) {
\r
488 if(ilistItem != null) {
\r
489 if(nRefsFoundInDoc == 0) { // First one?
\r
490 ilistItem.setSourceField(ari.getQualifiedDisplayName());
\r
491 } else { // duplicates from one object
\r
492 ilistItem = cloneAuthRefDocItem(ilistItem, ari.getQualifiedDisplayName());
\r
494 list.add(ilistItem);
\r
495 } else { // update refName case
\r
496 Property propToUpdate = ari.getProperty();
\r
497 propToUpdate.setValue(newAuthorityRefName);
\r
501 } catch (ClientException ce) {
\r
502 throw new RuntimeException(
\r
503 "getAuthorityRefDocs: Problem fetching values from repo: " + ce.getLocalizedMessage());
\r
505 if (nRefsFoundInDoc == 0) {
\r
506 throw new RuntimeException(
\r
507 "getAuthorityRefDocs: Could not find refname in object:"
\r
508 + docType + ":" + NuxeoUtils.getCsid(docModel));
\r
510 nRefsFoundTotal += nRefsFoundInDoc;
\r
512 return nRefsFoundTotal;
\r
515 private static AuthorityRefDocList.AuthorityRefDocItem cloneAuthRefDocItem(
\r
516 AuthorityRefDocList.AuthorityRefDocItem ilistItem, String sourceField) {
\r
517 AuthorityRefDocList.AuthorityRefDocItem newlistItem = new AuthorityRefDocList.AuthorityRefDocItem();
\r
518 newlistItem.setDocId(ilistItem.getDocId());
\r
519 newlistItem.setDocName(ilistItem.getDocName());
\r
520 newlistItem.setDocNumber(ilistItem.getDocNumber());
\r
521 newlistItem.setDocType(ilistItem.getDocType());
\r
522 newlistItem.setUri(ilistItem.getUri());
\r
523 newlistItem.setSourceField(sourceField);
\r
524 return newlistItem;
\r
527 public static List<AuthRefInfo> findAuthRefPropertiesInDoc(
\r
528 DocumentModel docModel,
\r
529 List<AuthRefConfigInfo> authRefFieldInfo,
\r
530 String refNameToMatch,
\r
531 List<AuthRefInfo> foundProps
\r
533 // Assume that authRefFieldInfo is keyed by the field name (possibly mapped for UI)
\r
534 // and the values are elPaths to the field, where intervening group structures in
\r
535 // lists of complex structures are replaced with "*". Thus, valid paths include
\r
536 // the following (note that the ServiceBindingUtils prepend schema names to configured values):
\r
537 // "schemaname:fieldname"
\r
538 // "schemaname:scalarlistname"
\r
539 // "schemaname:complexfieldname/fieldname"
\r
540 // "schemaname:complexlistname/*/fieldname"
\r
541 // "schemaname:complexlistname/*/scalarlistname"
\r
542 // "schemaname:complexlistname/*/complexfieldname/fieldname"
\r
543 // "schemaname:complexlistname/*/complexlistname/*/fieldname"
\r
545 for (AuthRefConfigInfo arci : authRefFieldInfo) {
\r
547 // Get first property and work down as needed.
\r
548 Property prop = docModel.getProperty(arci.pathEls[0]);
\r
549 findAuthRefPropertiesInProperty(foundProps, prop, arci, 0, refNameToMatch);
\r
550 } catch(Exception e) {
\r
551 logger.error("Problem fetching property: "+arci.pathEls[0]);
\r
557 public static List<AuthRefInfo> findAuthRefPropertiesInProperty(
\r
558 List<AuthRefInfo> foundProps,
\r
560 AuthRefConfigInfo arci,
\r
561 int pathStartIndex, // Supports recursion and we work down the path
\r
562 String refNameToMatch
\r
564 if (pathStartIndex >= arci.pathEls.length) {
\r
565 throw new ArrayIndexOutOfBoundsException("Index = "+pathStartIndex+" for path: "
\r
566 +arci.pathEls.toString());
\r
568 AuthRefInfo ari = null;
\r
569 if (prop == null) {
\r
573 if (prop instanceof StringProperty) { // scalar string
\r
574 addARIifMatches(refNameToMatch, arci, prop, foundProps);
\r
575 } else if(prop instanceof List) {
\r
576 List<Property> propList = (List<Property>)prop;
\r
577 // run through list. Must either be list of Strings, or Complex
\r
578 for (Property listItemProp : propList) {
\r
579 if(listItemProp instanceof StringProperty) {
\r
580 if(arci.pathEls.length-pathStartIndex != 1) {
\r
581 logger.error("Configuration for authRefs does not match schema structure: "
\r
582 +arci.pathEls.toString());
\r
585 addARIifMatches(refNameToMatch, arci, listItemProp, foundProps);
\r
587 } else if(listItemProp.isComplex()) {
\r
588 // Just recurse to handle this. Note that since this is a list of complex,
\r
589 // which should look like listName/*/... we add 2 to the path start index
\r
590 findAuthRefPropertiesInProperty(foundProps, listItemProp, arci,
\r
591 pathStartIndex+2, refNameToMatch);
\r
593 logger.error("Configuration for authRefs does not match schema structure: "
\r
594 +arci.pathEls.toString());
\r
598 } else if(prop.isComplex()) {
\r
599 String localPropName = arci.pathEls[pathStartIndex];
\r
601 Property localProp = prop.get(localPropName);
\r
602 // Now just recurse, pushing down the path 1 step
\r
603 findAuthRefPropertiesInProperty(foundProps, localProp, arci,
\r
604 pathStartIndex, refNameToMatch);
\r
605 } catch(PropertyNotFoundException pnfe) {
\r
606 logger.error("Could not find property: ["+localPropName+"] in path: "+
\r
607 arci.getFullPath());
\r
608 // Fall through - ari will be null and we will continue...
\r
611 logger.error("Configuration for authRefs does not match schema structure: "
\r
612 +arci.pathEls.toString());
\r
616 foundProps.add(ari); //FIXME: REM - This is dead code. 'ari' is never touched after being initalized to null. Why?
\r
622 private static void addARIifMatches(
\r
623 String refNameToMatch,
\r
624 AuthRefConfigInfo arci,
\r
626 List<AuthRefInfo> foundProps) {
\r
627 // Need to either match a passed refName
\r
628 // OR have no refName to match but be non-empty
\r
630 String value = (String)prop.getValue();
\r
631 if(((refNameToMatch!=null) && refNameToMatch.equals(value))
\r
632 || ((refNameToMatch==null) && Tools.notBlank(value))) {
\r
634 logger.debug("Found a match on property: "+prop.getPath()+" with value: ["+value+"]");
\r
635 AuthRefInfo ari = new AuthRefInfo(arci, prop);
\r
636 foundProps.add(ari);
\r
638 } catch(PropertyException pe) {
\r
639 logger.debug("PropertyException on: "+prop.getPath()+pe.getLocalizedMessage());
\r
644 * Identifies whether the refName was found in the supplied field.
\r
645 * If passed a new RefName, will set that into fields in which the old one was found.
\r
649 * * Repeatable scalar fields (aka multi-valued fields)
\r
651 * Does not work for:
\r
652 * * Structured fields (complexTypes)
\r
653 * * Repeatable structured fields (repeatable complexTypes)
\r
654 private static int refNameFoundInField(String oldRefName, Property fieldValue, String newRefName) {
\r
656 if (fieldValue instanceof List) {
\r
657 List<Property> fieldValueList = (List) fieldValue;
\r
658 for (Property listItemValue : fieldValueList) {
\r
660 if ((listItemValue instanceof StringProperty)
\r
661 && oldRefName.equalsIgnoreCase((String)listItemValue.getValue())) {
\r
663 if(newRefName!=null) {
\r
664 fieldValue.setValue(newRefName);
\r
666 // We cannot quit after the first, if we are replacing values.
\r
667 // If we are just looking (not replacing), finding one is enough.
\r
671 } catch( PropertyException pe ) {}
\r
675 if ((fieldValue instanceof StringProperty)
\r
676 && oldRefName.equalsIgnoreCase((String)fieldValue.getValue())) {
\r
678 if(newRefName!=null) {
\r
679 fieldValue.setValue(newRefName);
\r
682 } catch( PropertyException pe ) {}
\r