Coverage Report - org.kuali.rice.kns.util.MaintenanceUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
MaintenanceUtils
0%
0/216
0%
0/128
4.667
 
 1  
 /*
 2  
  * Copyright 2007 The Kuali Foundation
 3  
  * 
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  * 
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  * 
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.kns.util;
 17  
 
 18  
 import java.util.Collection;
 19  
 import java.util.HashMap;
 20  
 import java.util.HashSet;
 21  
 import java.util.Iterator;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 import java.util.Properties;
 25  
 import java.util.Set;
 26  
 import java.util.StringTokenizer;
 27  
 
 28  
 import org.apache.commons.lang.StringUtils;
 29  
 import org.kuali.rice.kew.exception.WorkflowException;
 30  
 import org.kuali.rice.kns.bo.BusinessObject;
 31  
 import org.kuali.rice.kns.datadictionary.AttributeSecurity;
 32  
 import org.kuali.rice.kns.datadictionary.MaintainableCollectionDefinition;
 33  
 import org.kuali.rice.kns.datadictionary.MaintainableFieldDefinition;
 34  
 import org.kuali.rice.kns.datadictionary.MaintainableItemDefinition;
 35  
 import org.kuali.rice.kns.datadictionary.MaintainableSectionDefinition;
 36  
 import org.kuali.rice.kns.datadictionary.MaintenanceDocumentEntry;
 37  
 import org.kuali.rice.kns.document.MaintenanceDocument;
 38  
 import org.kuali.rice.kns.exception.KualiExceptionIncident;
 39  
 import org.kuali.rice.kns.exception.ValidationException;
 40  
 import org.kuali.rice.kns.lookup.LookupUtils;
 41  
 import org.kuali.rice.kns.lookup.SelectiveReferenceRefresher;
 42  
 import org.kuali.rice.kns.maintenance.Maintainable;
 43  
 import org.kuali.rice.kns.service.DataDictionaryService;
 44  
 import org.kuali.rice.kns.service.KNSServiceLocator;
 45  
 import org.kuali.rice.kns.service.KualiConfigurationService;
 46  
 import org.kuali.rice.kns.service.KualiExceptionIncidentService;
 47  
 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
 48  
 import org.kuali.rice.kns.service.MaintenanceDocumentService;
 49  
 import org.kuali.rice.kns.web.ui.Field;
 50  
 import org.kuali.rice.kns.web.ui.Row;
 51  
 import org.kuali.rice.kns.web.ui.Section;
 52  
 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
 53  
 import org.kuali.rice.kns.workflow.service.WorkflowDocumentService;
 54  
 
 55  0
 public class MaintenanceUtils {
 56  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MaintenanceUtils.class);
 57  
 
 58  
     private static MaintenanceDocumentService maintenanceDocumentService;
 59  
     private static WorkflowDocumentService workflowDocumentService;
 60  
     private static KualiConfigurationService kualiConfigurationService;
 61  
     private static KualiExceptionIncidentService kualiExceptionIncidentService; 
 62  
     private static MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
 63  
     private static DataDictionaryService dataDictionaryService;
 64  
     
 65  
     /**
 66  
      * Returns the field templates defined in the maint dictionary xml files. Field templates are used in multiple value lookups.
 67  
      * When doing a MV lookup on a collection, the returned BOs are not necessarily of the same type as the elements of the
 68  
      * collection. Therefore, a means of mapping between the fields for the 2 BOs are necessary. The template attribute of
 69  
      * <maintainableField>s contained within <maintainableCollection>s tells us this mapping. Example: a
 70  
      * <maintainableField name="collectionAttrib" template="lookupBOAttrib"> definition means that when a list of BOs are
 71  
      * returned, the lookupBOAttrib value of the looked up BO will be placed into the collectionAttrib value of the BO added to the
 72  
      * collection
 73  
      * 
 74  
      * @param sections the sections of a document
 75  
      * @param collectionName the name of a collection. May be a nested collection with indices (e.g. collA[1].collB)
 76  
      * @return
 77  
      */
 78  
     public static Map<String, String> generateMultipleValueLookupBOTemplate(List<MaintainableSectionDefinition> sections, String collectionName) {
 79  0
         MaintainableCollectionDefinition definition = findMaintainableCollectionDefinition(sections, collectionName);
 80  0
         if (definition == null) {
 81  0
             return null;
 82  
         }
 83  0
         Map<String, String> template = null;
 84  
 
 85  0
         for (MaintainableFieldDefinition maintainableField : definition.getMaintainableFields()) {
 86  0
             String templateString = maintainableField.getTemplate();
 87  0
             if (StringUtils.isNotBlank(templateString)) {
 88  0
                 if (template == null) {
 89  0
                     template = new HashMap<String, String>();
 90  
                 }
 91  0
                 template.put(maintainableField.getName(), templateString);
 92  
             }
 93  0
         }
 94  0
         return template;
 95  
     }
 96  
     
 97  
     /**
 98  
      * Finds the MaintainableCollectionDefinition corresponding to the given collection name. For example, if the collection name is
 99  
      * "A.B.C", it will attempt to find the MaintainableCollectionDefinition for C that is nested in B that is nested under A. This
 100  
      * may not work correctly if there are duplicate collection definitions within the sections
 101  
      * 
 102  
      * @param sections the sections of a maint doc
 103  
      * @param collectionName the name of a collection, relative to the root of the BO being maintained. This value may have index
 104  
      *        values (e.g. [1]), but these are ignored.
 105  
      * @return
 106  
      */
 107  
     public static MaintainableCollectionDefinition findMaintainableCollectionDefinition(List<MaintainableSectionDefinition> sections, String collectionName) {
 108  0
         String[] collectionNameParts = StringUtils.split(collectionName, ".");
 109  0
         for (MaintainableSectionDefinition section : sections) {
 110  0
             MaintainableCollectionDefinition collDefinition = findMaintainableCollectionDefinitionHelper(section.getMaintainableItems(), collectionNameParts, 0);
 111  0
             if (collDefinition != null) {
 112  0
                 return collDefinition;
 113  
             }
 114  0
         }
 115  0
         return null;
 116  
     }
 117  
 
 118  
     private static <E extends MaintainableItemDefinition> MaintainableCollectionDefinition findMaintainableCollectionDefinitionHelper(Collection<E> items, String[] collectionNameParts, int collectionNameIndex) {
 119  0
         if (collectionNameParts.length <= collectionNameIndex) {
 120  
             // we've gone too far down the nesting without finding it
 121  0
             return null;
 122  
         }
 123  
 
 124  
         // we only care about the coll name, and not the index, since the coll definitions do not include the indexing characters,
 125  
         // i.e. [ and ]
 126  0
         String collectionToFind = StringUtils.substringBefore(collectionNameParts[collectionNameIndex], "[");
 127  0
         for (MaintainableItemDefinition item : items) {
 128  0
             if (item instanceof MaintainableCollectionDefinition) {
 129  0
                 MaintainableCollectionDefinition collection = (MaintainableCollectionDefinition) item;
 130  0
                 if (collection.getName().equals(collectionToFind)) {
 131  
                     // we found an appropriate coll, now we have to see if we need to recurse even more (more nested collections),
 132  
                     // or just return the one we found.
 133  0
                     if (collectionNameIndex == collectionNameParts.length - 1) {
 134  
                         // we're at the last part of the name, so we return
 135  0
                         return collection;
 136  
                     }
 137  
                     else {
 138  
                         // go deeper
 139  0
                         return findMaintainableCollectionDefinitionHelper(collection.getMaintainableCollections(), collectionNameParts, collectionNameIndex + 1);
 140  
                     }
 141  
                 }
 142  0
             }
 143  
         }
 144  0
         return null;
 145  
     }
 146  
 
 147  
     /**
 148  
      * Checks to see if there has been an override lookup declared for the maintenance field. If so, the override will be used for
 149  
      * the quickfinder and lookup utils will not be called. If no override was given, LookupUtils.setFieldQuickfinder will be called
 150  
      * to set the system generated quickfinder based on the attributes relationship to the parent business object.
 151  
      * 
 152  
      * @return Field with quickfinder set if one was found
 153  
      */
 154  
     public static final Field setFieldQuickfinder(BusinessObject businessObject, String attributeName, MaintainableFieldDefinition maintainableFieldDefinition, Field field, List<String> displayedFieldNames, SelectiveReferenceRefresher srr) {
 155  0
         if (maintainableFieldDefinition.getOverrideLookupClass() != null && StringUtils.isNotBlank(maintainableFieldDefinition.getOverrideFieldConversions())) {
 156  0
             field.setQuickFinderClassNameImpl(maintainableFieldDefinition.getOverrideLookupClass().getName());
 157  0
             field.setFieldConversions(maintainableFieldDefinition.getOverrideFieldConversions());
 158  0
             field.setBaseLookupUrl(LookupUtils.getBaseLookupUrl(false));
 159  0
             field.setReferencesToRefresh(LookupUtils.convertReferencesToSelectCollectionToString(
 160  
                     srr.getAffectedReferencesFromLookup(businessObject, attributeName, "")));
 161  0
             return field;
 162  
         }
 163  0
         if (maintainableFieldDefinition.isNoLookup()){
 164  0
                 return field;
 165  
         }
 166  0
         return LookupUtils.setFieldQuickfinder(businessObject, null, false, 0, attributeName, field, displayedFieldNames, maintainableFieldDefinition.isNoLookup());
 167  
     }
 168  
 
 169  
     public static final Field setFieldQuickfinder(BusinessObject businessObject, String collectionName, boolean addLine, int index,
 170  
             String attributeName, Field field, List<String> displayedFieldNames, Maintainable maintainable, MaintainableFieldDefinition maintainableFieldDefinition) {
 171  0
         if (maintainableFieldDefinition.getOverrideLookupClass() != null && StringUtils.isNotBlank(maintainableFieldDefinition.getOverrideFieldConversions())) {
 172  0
             if (maintainable != null) {
 173  0
                 String collectionPrefix = "";
 174  0
                 if ( collectionName != null ) {
 175  0
                     if (addLine) {
 176  0
                         collectionPrefix = KNSConstants.MAINTENANCE_ADD_PREFIX + collectionName + ".";
 177  
                     }
 178  
                     else {
 179  0
                         collectionPrefix = collectionName + "[" + index + "].";
 180  
                     }
 181  
                 }
 182  0
                 field.setQuickFinderClassNameImpl(maintainableFieldDefinition.getOverrideLookupClass().getName());
 183  
                 
 184  0
                 String prefixedFieldConversions = prefixFieldConversionsDestinationsWithCollectionPrefix(maintainableFieldDefinition.getOverrideFieldConversions(), collectionPrefix);
 185  0
                 field.setFieldConversions(prefixedFieldConversions);
 186  0
                 field.setBaseLookupUrl(LookupUtils.getBaseLookupUrl(false));
 187  0
                 field.setReferencesToRefresh(LookupUtils.convertReferencesToSelectCollectionToString(
 188  
                         maintainable.getAffectedReferencesFromLookup(businessObject, attributeName, collectionPrefix)));
 189  
             }
 190  0
             return field;
 191  
         }
 192  0
         if(maintainableFieldDefinition.isNoLookup()){
 193  0
                 return field;
 194  
         }
 195  0
         return LookupUtils.setFieldQuickfinder(businessObject, collectionName, addLine, index,
 196  
                 attributeName, field, displayedFieldNames, maintainable);
 197  
     }
 198  
     
 199  
     private static String prefixFieldConversionsDestinationsWithCollectionPrefix(String originalFieldConversions, String collectionPrefix) {
 200  0
         StringBuilder buf = new StringBuilder();
 201  0
         StringTokenizer tok = new StringTokenizer(originalFieldConversions, KNSConstants.FIELD_CONVERSIONS_SEPARATOR);
 202  0
         boolean needsSeparator = false;
 203  0
         while (tok.hasMoreTokens()) {
 204  0
             String conversionPair = tok.nextToken();
 205  0
             if (StringUtils.isBlank(conversionPair)) {
 206  0
                 continue;
 207  
             }
 208  
             
 209  0
             String fromValue = StringUtils.substringBefore(conversionPair, KNSConstants.FIELD_CONVERSION_PAIR_SEPARATOR);
 210  0
             String toValue = StringUtils.substringAfter(conversionPair, KNSConstants.FIELD_CONVERSION_PAIR_SEPARATOR);
 211  
             
 212  0
             if (needsSeparator) {
 213  0
                 buf.append(KNSConstants.FIELD_CONVERSIONS_SEPARATOR);
 214  
             }
 215  0
             needsSeparator = true;
 216  
             
 217  0
             buf.append(fromValue).append(KNSConstants.FIELD_CONVERSION_PAIR_SEPARATOR).append(collectionPrefix).append(toValue);
 218  0
         }
 219  0
         return buf.toString();
 220  
     }
 221  
     
 222  
     public static final void setFieldDirectInquiry(BusinessObject businessObject, String attributeName, MaintainableFieldDefinition maintainableFieldDefinition, Field field, List<String> displayedFieldNames) {
 223  0
         LookupUtils.setFieldDirectInquiry(businessObject, attributeName, field);
 224  0
     }
 225  
     
 226  
     public static final void setFieldDirectInquiry(BusinessObject businessObject, String collectionName, boolean addLine, int index,
 227  
             String attributeName, Field field, List<String> displayedFieldNames, Maintainable maintainable, MaintainableFieldDefinition maintainableFieldDefinition) {
 228  0
         LookupUtils.setFieldDirectInquiry(businessObject, attributeName, field);
 229  0
     }
 230  
     /**
 231  
      * Given a section, returns a comma delimited string of all fields, representing the error keys that exist for a section
 232  
      * 
 233  
      * @param section a section
 234  
      * @return
 235  
      */
 236  
     public static String generateErrorKeyForSection(Section section) {
 237  0
         Set<String> fieldPropertyNames = new HashSet<String>();
 238  0
         addRowsToErrorKeySet(section.getRows(), fieldPropertyNames);
 239  
 
 240  0
         StringBuilder buf = new StringBuilder();
 241  0
         buf.append(section.getSectionId()).append(",");
 242  
         
 243  0
         Iterator<String> nameIter = fieldPropertyNames.iterator();
 244  0
         while (nameIter.hasNext()) {
 245  0
             buf.append(nameIter.next());
 246  0
             if (nameIter.hasNext()) {
 247  0
                 buf.append(",");
 248  
             }
 249  
         }
 250  
 
 251  0
         if (section.getContainedCollectionNames() != null && section.getContainedCollectionNames().size() > 0) {
 252  0
             buf.append(",");
 253  
             
 254  0
             Iterator<String> collectionIter = section.getContainedCollectionNames().iterator();
 255  0
             while (collectionIter.hasNext()) {
 256  0
                 buf.append(KNSConstants.MAINTENANCE_NEW_MAINTAINABLE + collectionIter.next());
 257  0
                 if (collectionIter.hasNext()) {
 258  0
                     buf.append(",");
 259  
                 }
 260  
             }
 261  
         }
 262  
 
 263  0
         return buf.toString();
 264  
     }
 265  
 
 266  
     /**
 267  
      * This method recurses through all the fields of the list of rows and adds each field's property name to the set if it starts
 268  
      * with Constants.MAINTENANCE_NEW_MAINTAINABLE
 269  
      * 
 270  
      * @see KNSConstants#MAINTENANCE_NEW_MAINTAINABLE
 271  
      * @param listOfRows
 272  
      * @param errorKeys
 273  
      */
 274  
     protected static void addRowsToErrorKeySet(List<Row> listOfRows, Set<String> errorKeys) {
 275  0
         if (listOfRows == null) {
 276  0
             return;
 277  
         }
 278  0
         for (Row row : listOfRows) {
 279  0
             List<Field> fields = row.getFields();
 280  0
             if (fields == null) {
 281  0
                 continue;
 282  
             }
 283  0
             for (Field field : fields) {
 284  0
                 String fieldPropertyName = field.getPropertyName();
 285  0
                 if (fieldPropertyName != null && fieldPropertyName.startsWith(KNSConstants.MAINTENANCE_NEW_MAINTAINABLE)) {
 286  0
                     errorKeys.add(field.getPropertyName());
 287  
                 }
 288  0
                 addRowsToErrorKeySet(field.getContainerRows(), errorKeys);
 289  0
             }
 290  0
         }
 291  0
     }
 292  
     
 293  
     public static boolean isMaintenanceDocumentCreatingNewRecord(String maintenanceAction) {
 294  0
         if (KNSConstants.MAINTENANCE_EDIT_ACTION.equalsIgnoreCase(maintenanceAction)) {
 295  0
             return false;
 296  
         }
 297  0
         else if (KNSConstants.MAINTENANCE_NEWWITHEXISTING_ACTION.equalsIgnoreCase(maintenanceAction)) {
 298  0
             return false;
 299  
         }
 300  0
         else if (KNSConstants.MAINTENANCE_DELETE_ACTION.equalsIgnoreCase(maintenanceAction)) {
 301  0
             return false;
 302  
         }
 303  
         
 304  0
         else if (KNSConstants.MAINTENANCE_NEW_ACTION.equalsIgnoreCase(maintenanceAction)) {
 305  0
             return true;
 306  
         }
 307  0
         else if (KNSConstants.MAINTENANCE_COPY_ACTION.equalsIgnoreCase(maintenanceAction)) {
 308  0
             return true;
 309  
         }
 310  
         else {
 311  0
             return true;
 312  
         }
 313  
     }
 314  
 
 315  
     /**
 316  
      * This method will throw a {@link ValidationException} if there is a valid locking document in existence and throwExceptionIfLocked is true.
 317  
      */
 318  
     public static void checkForLockingDocument(MaintenanceDocument document, boolean throwExceptionIfLocked) {
 319  0
         LOG.info("starting checkForLockingDocument (by MaintenanceDocument)");
 320  
 
 321  
         // get the docHeaderId of the blocking docs, if any are locked and blocking
 322  
         //String blockingDocId = getMaintenanceDocumentService().getLockingDocumentId(document);
 323  0
         String blockingDocId = document.getNewMaintainableObject().getLockingDocumentId();
 324  0
         checkDocumentBlockingDocumentId(blockingDocId, throwExceptionIfLocked);
 325  0
     }
 326  
 
 327  
     /**
 328  
      * This method will throw a {@link ValidationException} if there is a valid locking document in existence and throwExceptionIfLocked is true.
 329  
      */
 330  
     public static void checkForLockingDocument(Maintainable maintainable, boolean throwExceptionIfLocked) {
 331  0
         LOG.info("starting checkForLockingDocument (by Maintainable)");
 332  
 
 333  
         // get the docHeaderId of the blocking docs, if any are locked and blocking
 334  
         //String blockingDocId = getMaintenanceDocumentService().getLockingDocumentId(maintainable, null);
 335  0
         String blockingDocId = maintainable.getLockingDocumentId();
 336  0
         checkDocumentBlockingDocumentId(blockingDocId, throwExceptionIfLocked);
 337  0
     }
 338  
 
 339  
     private static void checkDocumentBlockingDocumentId(String blockingDocId, boolean throwExceptionIfLocked) {
 340  
         // if we got nothing, then no docs are blocking, and we're done
 341  0
         if (StringUtils.isBlank(blockingDocId)) {
 342  0
             return;
 343  
         }
 344  
 
 345  0
         if ( LOG.isInfoEnabled() ) {
 346  0
             LOG.info("Locking document found:  docId = " + blockingDocId + ".");
 347  
         }
 348  
 
 349  
         // load the blocking locked document
 350  0
         KualiWorkflowDocument lockedDocument = null;
 351  
         try {
 352  
                 // need to perform this check to prevent an exception from being thrown by the
 353  
                 // createWorkflowDocument call - the throw itself causes transaction rollback problems to
 354  
                 // occur, even though the exception would be caught here
 355  0
                 if ( getWorkflowDocumentService().workflowDocumentExists(blockingDocId) ) {
 356  0
                         lockedDocument = getWorkflowDocumentService().createWorkflowDocument(Long.valueOf(blockingDocId), GlobalVariables.getUserSession().getPerson() );
 357  
                 }
 358  0
         } catch (Exception ex) {
 359  
                 // clean up the lock and notify the admins
 360  0
                 LOG.error("Unable to retrieve locking document specified in the maintenance lock table: " + blockingDocId, ex);
 361  
 
 362  0
                 cleanOrphanLocks(blockingDocId, ex);
 363  0
                 return;
 364  0
         }
 365  0
         if ( lockedDocument == null ) {
 366  0
                 LOG.warn( "Locking document header for " + blockingDocId + "came back null." );
 367  0
                 cleanOrphanLocks(blockingDocId, null);
 368  
         }
 369  
 
 370  
         // if we can ignore the lock (see method notes), then exit cause we're done
 371  0
         if (lockCanBeIgnored(lockedDocument)) {
 372  0
             return;
 373  
         }
 374  
 
 375  
         // build the link URL for the blocking document
 376  0
         Properties parameters = new Properties();
 377  0
         parameters.put(KNSConstants.PARAMETER_DOC_ID, blockingDocId);
 378  0
         parameters.put(KNSConstants.PARAMETER_COMMAND, KNSConstants.METHOD_DISPLAY_DOC_SEARCH_VIEW);
 379  0
         String blockingUrl = UrlFactory.parameterizeUrl(getKualiConfigurationService().getPropertyString(KNSConstants.WORKFLOW_URL_KEY) + "/" + KNSConstants.DOC_HANDLER_ACTION, parameters);
 380  0
         if ( LOG.isDebugEnabled() ) {
 381  0
             LOG.debug("blockingUrl = '" + blockingUrl + "'");
 382  0
             LOG.debug("Maintenance record: " + lockedDocument.getAppDocId() + "is locked.");
 383  
         }
 384  0
         String[] errorParameters = { blockingUrl, blockingDocId };
 385  
         
 386  
         // If specified, add an error to the ErrorMap and throw an exception; otherwise, just add a warning to the ErrorMap instead.
 387  0
         if (throwExceptionIfLocked) {
 388  
                 // post an error about the locked document
 389  0
             GlobalVariables.getMessageMap().putError(KNSConstants.GLOBAL_ERRORS, RiceKeyConstants.ERROR_MAINTENANCE_LOCKED, errorParameters);
 390  0
             throw new ValidationException("Maintenance Record is locked by another document.");
 391  
         }
 392  
         else {
 393  
                 // Post a warning about the locked document.
 394  0
                 GlobalVariables.getMessageMap().putWarning(KNSConstants.GLOBAL_MESSAGES, RiceKeyConstants.WARNING_MAINTENANCE_LOCKED, errorParameters);
 395  
         }
 396  0
     }
 397  
 
 398  
     /**
 399  
      * This method guesses whether the current user should be allowed to change a document even though it is locked. It probably
 400  
      * should use Authorization instead? See KULNRVSYS-948
 401  
      * 
 402  
      * @param lockedDocument
 403  
      * @return
 404  
      * @throws WorkflowException
 405  
      */
 406  
     private static boolean lockCanBeIgnored(KualiWorkflowDocument lockedDocument) {
 407  
         // TODO: implement real authorization for Maintenance Document Save/Route - KULNRVSYS-948
 408  0
             if ( lockedDocument == null ) {
 409  0
                     return true;
 410  
                 }
 411  
 
 412  
         // get the user-id. if no user-id, then we can do this test, so exit
 413  0
         String userId = GlobalVariables.getUserSession().getPrincipalId().trim();
 414  0
         if (StringUtils.isBlank(userId)) {
 415  0
             return false; // dont bypass locking
 416  
         }
 417  
 
 418  
         // if the current user is not the initiator of the blocking document
 419  0
         if (!userId.equalsIgnoreCase(lockedDocument.getRouteHeader().getInitiatorPrincipalId().trim())) {
 420  0
             return false;
 421  
         }
 422  
 
 423  
         // if the blocking document hasn't been routed, we can ignore it
 424  0
         return lockedDocument.stateIsInitiated();
 425  
     }
 426  
 
 427  
     private static void cleanOrphanLocks( String lockingDocumentNumber, Exception workflowException ) {
 428  
             // put a try/catch around the whole thing - the whole reason we are doing this is to prevent data errors
 429  
             // from stopping a document
 430  
             try {
 431  
                     // delete the locks for this document since it does not seem to exist
 432  0
                     getMaintenanceDocumentService().deleteLocks(lockingDocumentNumber);
 433  
                     // notify the incident list
 434  0
             Map<String, String> parameters = new HashMap<String, String>(1);
 435  0
             parameters.put(KNSConstants.PARAMETER_DOC_ID, lockingDocumentNumber);
 436  0
                 KualiExceptionIncident kei = getKualiExceptionIncidentService().getExceptionIncident(workflowException, parameters);
 437  0
                     getKualiExceptionIncidentService().report(kei);
 438  0
             } catch ( Exception ex ) {
 439  0
                     LOG.error("Unable to delete and notify upon locking document retrieval failure.", ex);
 440  0
             }
 441  0
     }
 442  
 
 443  
         private static MaintenanceDocumentService getMaintenanceDocumentService() {
 444  0
                 if ( maintenanceDocumentService == null ) {
 445  0
                         maintenanceDocumentService = KNSServiceLocator.getMaintenanceDocumentService();
 446  
                 }
 447  0
                 return maintenanceDocumentService;
 448  
         }
 449  
 
 450  
         private static WorkflowDocumentService getWorkflowDocumentService() {
 451  0
                 if ( workflowDocumentService == null ) {
 452  0
                         workflowDocumentService = KNSServiceLocator.getWorkflowDocumentService();
 453  
                 }
 454  0
                 return workflowDocumentService;
 455  
         }
 456  
 
 457  
         private static KualiConfigurationService getKualiConfigurationService() {
 458  0
                 if ( kualiConfigurationService == null ) {
 459  0
                         kualiConfigurationService = KNSServiceLocator.getKualiConfigurationService();
 460  
                 }
 461  0
                 return kualiConfigurationService;
 462  
         }
 463  
 
 464  
         private static KualiExceptionIncidentService getKualiExceptionIncidentService() {
 465  0
                 if ( kualiExceptionIncidentService == null ) {
 466  0
                         kualiExceptionIncidentService = KNSServiceLocator.getKualiExceptionIncidentService();
 467  
                 }
 468  0
                 return kualiExceptionIncidentService;
 469  
         }
 470  
     
 471  
         private static MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
 472  0
                 if ( maintenanceDocumentDictionaryService == null ) {
 473  0
                         maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
 474  
                 }
 475  0
                 return maintenanceDocumentDictionaryService;
 476  
         }
 477  
         
 478  
         private static DataDictionaryService getDataDictionaryService() {
 479  0
                 if ( dataDictionaryService == null ) {
 480  0
                         dataDictionaryService = KNSServiceLocator.getDataDictionaryService();
 481  
                 }
 482  0
                 return dataDictionaryService;
 483  
         }
 484  
         public static Map<String, AttributeSecurity> retrievePropertyPathToAttributeSecurityMappings(String docTypeName) {
 485  0
                 Map<String, AttributeSecurity> results = new HashMap<String, AttributeSecurity>();
 486  0
                 MaintenanceDocumentEntry entry = getMaintenanceDocumentDictionaryService().getMaintenanceDocumentEntry(docTypeName);
 487  0
                 String className = entry.getBusinessObjectClass().getName();
 488  
                 
 489  0
                 for (MaintainableSectionDefinition section : entry.getMaintainableSections()) {
 490  0
                         for (MaintainableItemDefinition item : section.getMaintainableItems()) {
 491  0
                                 if (item instanceof MaintainableFieldDefinition) {
 492  0
                                         MaintainableFieldDefinition field = (MaintainableFieldDefinition) item;
 493  0
                                         AttributeSecurity attributeSecurity = getDataDictionaryService().getAttributeSecurity(className, field.getName());
 494  0
                                         if (attributeSecurity != null) {
 495  0
                                                 results.put(field.getName(), attributeSecurity);
 496  
                                         }
 497  0
                                 }
 498  0
                                 else if (item instanceof MaintainableCollectionDefinition) {
 499  0
                                         addMaintenanceDocumentCollectionPathToSecurityMappings(results, "", (MaintainableCollectionDefinition) item);
 500  
                                 }
 501  
                         }
 502  
                 }
 503  0
                 return results;
 504  
         }
 505  
         
 506  
         private static void addMaintenanceDocumentCollectionPathToSecurityMappings(Map<String, AttributeSecurity> mappings, String propertyPathPrefix, MaintainableCollectionDefinition collectionDefinition) {
 507  0
                 propertyPathPrefix = propertyPathPrefix + collectionDefinition.getName() + ".";
 508  0
                 String boClassName = collectionDefinition.getBusinessObjectClass().getName();
 509  0
                 for (MaintainableFieldDefinition field : collectionDefinition.getMaintainableFields()) {
 510  0
                         AttributeSecurity attributeSecurity = getDataDictionaryService().getAttributeSecurity(boClassName, field.getName());
 511  0
                         if (attributeSecurity != null) {
 512  0
                                 mappings.put(propertyPathPrefix + field.getName(), attributeSecurity);
 513  
                         }
 514  0
                 }
 515  0
                 for (MaintainableCollectionDefinition nestedCollection : collectionDefinition.getMaintainableCollections()) {
 516  0
                         addMaintenanceDocumentCollectionPathToSecurityMappings(mappings, propertyPathPrefix, nestedCollection);
 517  
                 }
 518  0
         }
 519  
 }