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