Coverage Report - org.kuali.rice.kns.web.struts.form.InquiryForm
 
Classes in this File Line Coverage Branch Coverage Complexity
InquiryForm
0%
0/145
0%
0/44
2.458
 
 1  
 /**
 2  
  * Copyright 2005-2011 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.web.struts.form;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.kuali.rice.core.api.encryption.EncryptionService;
 20  
 import org.kuali.rice.core.api.CoreApiServiceLocator;
 21  
 import org.kuali.rice.kns.inquiry.Inquirable;
 22  
 import org.kuali.rice.kns.service.BusinessObjectAuthorizationService;
 23  
 import org.kuali.rice.kns.service.BusinessObjectMetaDataService;
 24  
 import org.kuali.rice.kns.service.KNSServiceLocator;
 25  
 import org.kuali.rice.krad.authorization.AuthorizationConstants;
 26  
 import org.kuali.rice.krad.bo.Exporter;
 27  
 import org.kuali.rice.kns.datadictionary.BusinessObjectEntry;
 28  
 import org.kuali.rice.krad.datadictionary.exception.UnknownBusinessClassAttributeException;
 29  
 import org.kuali.rice.krad.service.DataDictionaryService;
 30  
 import org.kuali.rice.krad.service.KRADServiceLocator;
 31  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 32  
 import org.kuali.rice.krad.service.KualiModuleService;
 33  
 import org.kuali.rice.krad.service.ModuleService;
 34  
 import org.kuali.rice.krad.util.KRADConstants;
 35  
 
 36  
 import javax.servlet.http.HttpServletRequest;
 37  
 import java.lang.reflect.Constructor;
 38  
 import java.security.GeneralSecurityException;
 39  
 import java.util.ArrayList;
 40  
 import java.util.Enumeration;
 41  
 import java.util.HashMap;
 42  
 import java.util.List;
 43  
 import java.util.Map;
 44  
 
 45  
 /**
 46  
  * This class is the action form for inquiries.
 47  
  */
 48  
 public class InquiryForm extends KualiForm {
 49  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(InquiryForm.class);
 50  
 
 51  
     private static final long serialVersionUID = 1L;
 52  
     private String fieldConversions;
 53  
     private List sections;
 54  
     private String businessObjectClassName;
 55  
     private Map editingMode;
 56  
     private String formKey;
 57  
     private boolean canExport;
 58  
 
 59  
     @Override
 60  
     public void addRequiredNonEditableProperties(){
 61  0
             super.addRequiredNonEditableProperties();
 62  0
             registerRequiredNonEditableProperty(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE);
 63  0
             registerRequiredNonEditableProperty(KRADConstants.DISPATCH_REQUEST_PARAMETER);
 64  0
             registerRequiredNonEditableProperty(KRADConstants.DOC_FORM_KEY);
 65  0
             registerRequiredNonEditableProperty(KRADConstants.FORM_KEY);
 66  0
             registerRequiredNonEditableProperty(KRADConstants.FIELDS_CONVERSION_PARAMETER);
 67  0
             registerRequiredNonEditableProperty(KRADConstants.BACK_LOCATION);
 68  0
     }
 69  
 
 70  
     /**
 71  
      * The following map is used to pass primary key values between invocations of the inquiry screens after the start method has been called.  Values in this map will remain encrypted
 72  
      * if the value was passed in as encrypted
 73  
      */
 74  
     private Map<String, String> inquiryPrimaryKeys;
 75  
 
 76  
     private Map<String, String> inquiryDecryptedPrimaryKeys;
 77  
 
 78  
     /**
 79  
      * A map of collection name -> Boolean mappings.  Used to denote whether a collection name is configured to show inactive records.
 80  
      */
 81  
     private Map<String, Boolean> inactiveRecordDisplay;
 82  
 
 83  
     private Inquirable inquirable;
 84  
 
 85  
     public InquiryForm() {
 86  0
         super();
 87  0
         this.editingMode = new HashMap();
 88  0
         this.editingMode.put(AuthorizationConstants.EditMode.VIEW_ONLY, "TRUE");
 89  0
         this.inactiveRecordDisplay = null;
 90  0
     }
 91  
 
 92  
         @Override
 93  
     public void populate(HttpServletRequest request) {
 94  
     // set to null for security reasons (so POJO form base can't access it), then we'll make an new instance of it after
 95  
     // POJO form base is done
 96  0
         this.inquirable = null;
 97  0
         super.populate(request);
 98  0
         if (request.getParameter("returnLocation") != null) {
 99  0
             setBackLocation(request.getParameter("returnLocation"));
 100  
         }
 101  0
         if (request.getParameter(KRADConstants.DOC_FORM_KEY) != null) {
 102  0
             setFormKey(request.getParameter(KRADConstants.DOC_FORM_KEY));
 103  
         }
 104  
         //if the action is download attachment then skip the following populate logic
 105  0
         if(!KRADConstants.DOWNLOAD_BO_ATTACHMENT_METHOD.equals(getMethodToCall())){
 106  0
                 inquirable = getInquirable(getBusinessObjectClassName());
 107  
 
 108  
                 // the following variable is true if the method to call is not start, meaning that we already called start
 109  0
                 boolean passedFromPreviousInquiry = !KRADConstants.START_METHOD.equals(getMethodToCall()) && !KRADConstants.CONTINUE_WITH_INQUIRY_METHOD_TO_CALL.equals(getMethodToCall()) && !KRADConstants
 110  
                     .DOWNLOAD_CUSTOM_BO_ATTACHMENT_METHOD.equals(getMethodToCall());
 111  
 
 112  
                 // There is no requirement that an inquiry screen must display the primary key values.  However, when clicking on hide/show (without javascript) and
 113  
                 // hide/show inactive, the PK values are needed to allow the server to properly render results after the user clicks on a hide/show button that results
 114  
                 // in server processing.  This line will populate the form with the PK values so that they may be used in subsequent requests.  Note that encrypted
 115  
                 // values will remain encrypted in this map.
 116  0
                 this.inquiryPrimaryKeys = new HashMap<String, String>();
 117  0
                 this.inquiryDecryptedPrimaryKeys = new HashMap<String, String>();
 118  
 
 119  0
                 populatePKFieldValues(request, getBusinessObjectClassName(), passedFromPreviousInquiry);
 120  
 
 121  0
                 populateInactiveRecordsInIntoInquirable(inquirable, request);
 122  0
                 populateExportCapabilities(request, getBusinessObjectClassName());
 123  
         }
 124  0
     }
 125  
 
 126  
     protected Inquirable getInquirable(String boClassName) {
 127  
         try {
 128  0
             Class customInquirableClass = null;
 129  
 
 130  
             try {
 131  0
                 BusinessObjectEntry entry = (BusinessObjectEntry) KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(boClassName);
 132  0
                 customInquirableClass = entry.getInquiryDefinition().getInquirableClass();
 133  
             }
 134  0
             catch (Exception e) {
 135  0
                 LOG.error("Unable to correlate business object class with maintenance document entry");
 136  0
             }
 137  
 
 138  0
             Inquirable kualiInquirable = KNSServiceLocator.getKualiInquirable(); // get inquirable impl from Spring
 139  
 
 140  0
             if (customInquirableClass != null) {
 141  0
                 Class[] defaultConstructor = new Class[] {};
 142  0
                 Constructor cons = customInquirableClass.getConstructor(defaultConstructor);
 143  0
                 kualiInquirable = (Inquirable) cons.newInstance();
 144  
             }
 145  
 
 146  0
             kualiInquirable.setBusinessObjectClass(Class.forName(boClassName));
 147  
 
 148  0
             return kualiInquirable;
 149  
         }
 150  0
         catch (Exception e) {
 151  0
             LOG.error("Error attempting to retrieve inquirable.", e);
 152  0
             throw new RuntimeException("Error attempting to retrieve inquirable.");
 153  
         }
 154  
     }
 155  
 
 156  
     /**
 157  
      * Gets the alt keys for a class.  Will not return null but and empty list if no keys exist.
 158  
      *
 159  
      * @param clazz the class.
 160  
      * @return the alt keys
 161  
      */
 162  
     private List<List<String>> getAltkeys(Class<?> clazz) {
 163  0
             final KualiModuleService kualiModuleService = KRADServiceLocatorWeb.getKualiModuleService();
 164  0
             final ModuleService moduleService = kualiModuleService.getResponsibleModuleService(clazz);
 165  
 
 166  0
         List<List<String>> altKeys = null;
 167  0
         if (moduleService != null) {
 168  0
                 altKeys = moduleService.listAlternatePrimaryKeyFieldNames(clazz);
 169  
         }
 170  
 
 171  0
         return altKeys != null ? altKeys : new ArrayList<List<String>>();
 172  
     }
 173  
 
 174  
     protected void populatePKFieldValues(HttpServletRequest request, String boClassName, boolean passedFromPreviousInquiry) {
 175  
         try {
 176  0
             EncryptionService encryptionService = CoreApiServiceLocator.getEncryptionService();
 177  0
             DataDictionaryService dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
 178  0
             BusinessObjectAuthorizationService businessObjectAuthorizationService = KNSServiceLocator
 179  
                     .getBusinessObjectAuthorizationService();
 180  0
             BusinessObjectMetaDataService businessObjectMetaDataService = KNSServiceLocator
 181  
                     .getBusinessObjectMetaDataService();
 182  
 
 183  0
             Class businessObjectClass = Class.forName(boClassName);
 184  
 
 185  
             // build list of key values from request, if all keys not given throw error
 186  0
             List<String> boPKeys = businessObjectMetaDataService.listPrimaryKeyFieldNames(businessObjectClass);
 187  0
             final List<List<String>> altKeys = this.getAltkeys(businessObjectClass);
 188  
 
 189  0
             altKeys.add(boPKeys);
 190  0
             boolean bFound = false;
 191  0
             for(List<String> boKeys : altKeys ){
 192  0
                     if(bFound)
 193  0
                             break;
 194  0
                     int keyCount = boKeys.size();
 195  0
                     int foundCount = 0;
 196  0
                 for (String boKey : boKeys) {
 197  0
                     String pkParamName = boKey;
 198  0
                         if (passedFromPreviousInquiry) {
 199  0
                             pkParamName = KRADConstants.INQUIRY_PK_VALUE_PASSED_FROM_PREVIOUS_REQUEST_PREFIX + pkParamName;
 200  
                         }
 201  
 
 202  0
                         if (request.getParameter(pkParamName) != null) {
 203  0
                                 foundCount++;
 204  0
                                 String parameter = request.getParameter(pkParamName);
 205  
                         
 206  0
                         Boolean forceUppercase = Boolean.FALSE;
 207  
                         try {
 208  0
                             forceUppercase = dataDictionaryService.getAttributeForceUppercase(businessObjectClass, boKey);
 209  0
                         } catch (UnknownBusinessClassAttributeException ex) {
 210  
                             // swallowing exception because this check for ForceUppercase would
 211  
                             // require a DD entry for the attribute.  it is only checking keys
 212  
                             // so most likely there should be an entry.
 213  0
                             LOG.warn("BO class " + businessObjectClassName + " property " + boKey + " should probably have a DD definition.", ex);
 214  0
                         }
 215  0
                         String parameterCopy = parameter;
 216  0
                         if (forceUppercase) {
 217  0
                                         parameter = parameter.toUpperCase();
 218  
                                 }
 219  
 
 220  0
                         inquiryPrimaryKeys.put(boKey, parameter);
 221  0
                         if (businessObjectAuthorizationService.attributeValueNeedsToBeEncryptedOnFormsAndLinks(businessObjectClass, boKey)) {
 222  
                             try {
 223  0
                                 inquiryDecryptedPrimaryKeys.put(boKey, encryptionService.decrypt(parameterCopy));
 224  0
                             } catch (GeneralSecurityException e) {
 225  0
                                 LOG.error("BO class " + businessObjectClassName + " property " + boKey + " should have been encrypted, but there was a problem decrypting it.");
 226  0
                                 throw e;
 227  0
                             }
 228  
                         }
 229  
                         else {
 230  0
                             inquiryDecryptedPrimaryKeys.put(boKey, parameter);
 231  
                         }
 232  
                     }
 233  0
                 }
 234  0
                 if (foundCount == keyCount) {
 235  0
                     bFound = true;
 236  
                 }
 237  0
             }
 238  0
             if(!bFound){
 239  0
                 LOG.error("All keys not given to lookup for bo class name " + businessObjectClass.getName());
 240  0
                 throw new RuntimeException("All keys not given to lookup for bo class name " + businessObjectClass.getName());
 241  
             }
 242  
         }
 243  0
         catch (ClassNotFoundException e) {
 244  0
                 LOG.error("Can't instantiate class: " + boClassName, e);
 245  0
                 throw new RuntimeException("Can't instantiate class: " + boClassName);
 246  
         }
 247  0
         catch (GeneralSecurityException e) {
 248  0
                 LOG.error("Can't decrypt value", e);
 249  0
                 throw new RuntimeException("Can't decrypt value");
 250  0
         }
 251  0
     }
 252  
 
 253  
     /**
 254  
      * Examines the BusinessObject's data dictionary entry to determine if it supports
 255  
      * XML export or not and set's canExport appropriately.
 256  
      */
 257  
     protected void populateExportCapabilities(HttpServletRequest request, String boClassName) {
 258  0
             setCanExport(false);
 259  0
             BusinessObjectEntry businessObjectEntry = (BusinessObjectEntry) KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(boClassName);
 260  0
             Class<? extends Exporter> exporterClass = businessObjectEntry.getExporterClass();
 261  0
             if (exporterClass != null) {
 262  
                     try {
 263  0
                             Exporter exporter = exporterClass.newInstance();
 264  0
                             if (exporter.getSupportedFormats(businessObjectEntry.getBusinessObjectClass()).contains(KRADConstants.XML_FORMAT)) {
 265  0
                                     setCanExport(true);
 266  
                             }
 267  0
                     } catch (Exception e) {
 268  0
                             LOG.error("Failed to locate or create exporter class: " + exporterClass, e);
 269  0
                             throw new RuntimeException("Failed to locate or create exporter class: " + exporterClass);
 270  0
                     }
 271  
             }
 272  0
     }
 273  
 
 274  
 
 275  
     /**
 276  
      * @return Returns the fieldConversions.
 277  
      */
 278  
     public String getFieldConversions() {
 279  0
         return fieldConversions;
 280  
     }
 281  
 
 282  
 
 283  
     /**
 284  
      * @param fieldConversions The fieldConversions to set.
 285  
      */
 286  
     public void setFieldConversions(String fieldConversions) {
 287  0
         this.fieldConversions = fieldConversions;
 288  0
     }
 289  
 
 290  
 
 291  
     /**
 292  
      * @return Returns the inquiry sections.
 293  
      */
 294  
     public List getSections() {
 295  0
         return sections;
 296  
     }
 297  
 
 298  
 
 299  
     /**
 300  
      * @param sections The sections to set.
 301  
      */
 302  
     public void setSections(List sections) {
 303  0
         this.sections = sections;
 304  0
     }
 305  
 
 306  
     /**
 307  
      * @return Returns the businessObjectClassName.
 308  
      */
 309  
     public String getBusinessObjectClassName() {
 310  0
         return businessObjectClassName;
 311  
     }
 312  
 
 313  
     /**
 314  
      * @param businessObjectClassName The businessObjectClassName to set.
 315  
      */
 316  
     public void setBusinessObjectClassName(String businessObjectClassName) {
 317  0
         this.businessObjectClassName = businessObjectClassName;
 318  0
     }
 319  
 
 320  
     public Map getEditingMode() {
 321  0
         return editingMode;
 322  
     }
 323  
 
 324  
     /**
 325  
      * Gets the map used to pass primary key values between invocations of the inquiry screens after the start method has been called.  All field values that were passed in encrypted will
 326  
      * be encrypted in this map
 327  
      *
 328  
      * @return
 329  
      */
 330  
     public Map<String, String> getInquiryPrimaryKeys() {
 331  0
         return this.inquiryPrimaryKeys;
 332  
     }
 333  
 
 334  
     /**
 335  
      * Gets the map used to pass primary key values between invocations of the inquiry screens after the start method has been called.  All fields will be decrypted
 336  
      *
 337  
      * Purposely not named as a getter, to make it harder for POJOFormBase to access it
 338  
      *
 339  
      * @return
 340  
      */
 341  
     public Map<String, String> retrieveInquiryDecryptedPrimaryKeys() {
 342  0
         return this.inquiryDecryptedPrimaryKeys;
 343  
     }
 344  
 
 345  
     /**
 346  
      * Sets the map used to pass primary key values between invocations of the inquiry screens after the start method has been called.
 347  
      *
 348  
      * @param inquiryPrimaryKeys
 349  
      */
 350  
     public void setInquiryPrimaryKeys(Map<String, String> inquiryPrimaryKeys) {
 351  0
         this.inquiryPrimaryKeys = inquiryPrimaryKeys;
 352  0
     }
 353  
 
 354  
     /**
 355  
      * Gets map of collection name -> Boolean mappings.  Used to denote whether a collection name is configured to show inactive records.
 356  
      *
 357  
      * @return
 358  
      */
 359  
     public Map<String, Boolean> getInactiveRecordDisplay() {
 360  0
         return getInquirable().getInactiveRecordDisplay();
 361  
     }
 362  
 
 363  
     public Inquirable getInquirable() {
 364  0
         return inquirable;
 365  
     }
 366  
 
 367  
     protected void populateInactiveRecordsInIntoInquirable(Inquirable inquirable, HttpServletRequest request) {
 368  0
         for (Enumeration e = request.getParameterNames(); e.hasMoreElements();) {
 369  0
             String paramName = (String) e.nextElement();
 370  0
             if (paramName.startsWith(KRADConstants.INACTIVE_RECORD_DISPLAY_PARAM_PREFIX)) {
 371  0
                 String collectionName = StringUtils.substringAfter(paramName, KRADConstants.INACTIVE_RECORD_DISPLAY_PARAM_PREFIX);
 372  0
                 Boolean showInactive = Boolean.parseBoolean(request.getParameter(paramName));
 373  0
                 inquirable.setShowInactiveRecords(collectionName, showInactive);
 374  
             }
 375  0
         }
 376  0
     }
 377  
 
 378  
     public String getFormKey() {
 379  0
         return this.formKey;
 380  
     }
 381  
 
 382  
     public void setFormKey(String formKey) {
 383  0
         this.formKey = formKey;
 384  0
     }
 385  
 
 386  
         /**
 387  
          * Returns true if this Inquiry supports XML export of the BusinessObject.
 388  
          */
 389  
         public boolean isCanExport() {
 390  0
                 return this.canExport;
 391  
         }
 392  
 
 393  
         /**
 394  
          * Sets whether or not this Inquiry supports XML export of it's BusinessObject.
 395  
          */
 396  
         public void setCanExport(boolean canExport) {
 397  0
                 this.canExport = canExport;
 398  0
         }
 399  
 
 400  
 
 401  
 }