View Javadoc

1   /*
2    * Copyright 2007 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 1.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/ecl1.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.krad.uif.widget;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.CoreApiServiceLocator;
20  import org.kuali.rice.core.web.format.Formatter;
21  import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
22  import org.kuali.rice.krad.service.KRADServiceLocator;
23  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
24  import org.kuali.rice.krad.service.ModuleService;
25  import org.kuali.rice.krad.uif.UifConstants;
26  import org.kuali.rice.krad.uif.UifParameters;
27  import org.kuali.rice.krad.uif.view.View;
28  import org.kuali.rice.krad.uif.component.BindingInfo;
29  import org.kuali.rice.krad.uif.component.Component;
30  import org.kuali.rice.krad.uif.field.AttributeField;
31  import org.kuali.rice.krad.uif.field.LinkField;
32  import org.kuali.rice.krad.uif.util.LookupInquiryUtils;
33  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
34  import org.kuali.rice.krad.uif.util.ViewModelUtils;
35  import org.kuali.rice.krad.util.UrlFactory;
36  
37  import java.security.GeneralSecurityException;
38  import java.util.HashMap;
39  import java.util.List;
40  import java.util.Map;
41  import java.util.Map.Entry;
42  import java.util.Properties;
43  
44  /**
45   * Widget for rendering an Inquiry link on a field's value
46   *
47   * @author Kuali Rice Team (rice.collab@kuali.org)
48   */
49  public class Inquiry extends WidgetBase {
50      private static final long serialVersionUID = -2154388007867302901L;
51      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(Inquiry.class);
52  
53      public static final String INQUIRY_TITLE_PREFIX = "title.inquiry.url.value.prependtext";
54  
55      private String baseInquiryUrl;
56  
57      private String dataObjectClassName;
58      private String viewName;
59  
60      private Map<String, String> inquiryParameters;
61  
62      private boolean forceInquiry;
63  
64      private LinkField inquiryLinkField;
65  
66      public Inquiry() {
67          super();
68  
69          forceInquiry = false;
70          inquiryParameters = new HashMap<String, String>();
71      }
72  
73      /**
74       * @see org.kuali.rice.krad.uif.widget.WidgetBase#performFinalize(org.kuali.rice.krad.uif.view.View,
75       *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
76       */
77      @Override
78      public void performFinalize(View view, Object model, Component parent) {
79          super.performFinalize(view, model, parent);
80  
81          // only set inquiry if enabled
82          if (!isRender() || !isReadOnly()) {
83              return;
84          }
85  
86          // set render to false until we find an inquiry class
87          setRender(false);
88  
89          AttributeField field = (AttributeField) parent;
90  
91          // check if field value is null, if so no inquiry
92          Object propertyValue = ObjectPropertyUtils.getPropertyValue(model, field.getBindingInfo().getBindingPath());
93          if ((propertyValue == null) || StringUtils.isBlank(propertyValue.toString())) {
94              return;
95          }
96  
97          setupLink(view, model, field);
98      }
99  
100     /**
101      * Get parent object and field name and build the inquiry link
102      * This was moved from the performFinalize because overlapping and to be used
103      * by DirectInquiry
104      *
105      * @param view - Container View
106      * @param model - model
107      * @param field - The parent Attribute field
108      */
109     public void setupLink(View view, Object model, AttributeField field) {
110         // get parent object for inquiry
111         Object parentObject = ViewModelUtils.getParentObjectForMetadata(view, model, field);
112         String propertyName = field.getBindingInfo().getBindingName();
113 
114         // if class and parameters configured, build link from those
115         if (StringUtils.isNotBlank(getDataObjectClassName()) && (getInquiryParameters() != null) &&
116                 !getInquiryParameters().isEmpty()) {
117             Class<?> inquiryObjectClass = null;
118             try {
119                 inquiryObjectClass = Class.forName(getDataObjectClassName());
120             } catch (ClassNotFoundException e) {
121                 LOG.error("Unable to get class for: " + getDataObjectClassName());
122                 throw new RuntimeException(e);
123             }
124 
125             updateInquiryParameters(field.getBindingInfo());
126 
127             buildInquiryLink(parentObject, propertyName, inquiryObjectClass, getInquiryParameters());
128         }
129         // get inquiry class and parameters from view helper
130         else {
131             view.getViewHelperService().buildInquiryLink(parentObject, propertyName, this);
132         }
133     }
134 
135     /**
136      * Adjusts the path on the inquiry parameter property to match the binding
137      * path prefix of the given <code>BindingInfo</code>
138      *
139      * @param bindingInfo - binding info instance to copy binding path prefix from
140      */
141     public void updateInquiryParameters(BindingInfo bindingInfo) {
142         Map<String, String> adjustedInquiryParameters = new HashMap<String, String>();
143         for (String fromField : inquiryParameters.keySet()) {
144             String toField = inquiryParameters.get(fromField);
145             String adjustedFromFieldPath = bindingInfo.getPropertyAdjustedBindingPath(fromField);
146 
147             adjustedInquiryParameters.put(adjustedFromFieldPath, toField);
148         }
149 
150         this.inquiryParameters = adjustedInquiryParameters;
151     }
152 
153     /**
154      * Builds the inquiry link based on the given inquiry class and parameters
155      *
156      * @param dataObject - parent object that contains the data (used to pull inquiry
157      * parameters)
158      * @param propertyName - name of the property the inquiry is set on
159      * @param inquiryObjectClass - class of the object the inquiry should point to
160      * @param inquiryParms - map of key field mappings for the inquiry
161      */
162     public void buildInquiryLink(Object dataObject, String propertyName, Class<?> inquiryObjectClass,
163             Map<String, String> inquiryParms) {
164         Properties urlParameters = new Properties();
165 
166         urlParameters.put(UifParameters.DATA_OBJECT_CLASS_NAME, inquiryObjectClass.getName());
167         urlParameters.put(UifParameters.METHOD_TO_CALL, UifConstants.MethodToCallNames.START);
168 
169         for (Entry<String, String> inquiryParameter : inquiryParms.entrySet()) {
170             String parameterName = inquiryParameter.getKey();
171 
172             Object parameterValue = ObjectPropertyUtils.getPropertyValue(dataObject, parameterName);
173 
174             // TODO: need general format util that uses spring
175             if (parameterValue == null) {
176                 parameterValue = "";
177             } else if (parameterValue instanceof java.sql.Date) {
178                 if (Formatter.findFormatter(parameterValue.getClass()) != null) {
179                     Formatter formatter = Formatter.getFormatter(parameterValue.getClass());
180                     parameterValue = formatter.format(parameterValue);
181                 }
182             } else {
183                 parameterValue = parameterValue.toString();
184             }
185 
186             // Encrypt value if it is a field that has restriction that prevents
187             // a value from being shown to user, because we don't want the
188             // browser history to store the restricted
189             // attribute's value in the URL
190             if (KRADServiceLocatorWeb.getDataObjectAuthorizationService()
191                     .attributeValueNeedsToBeEncryptedOnFormsAndLinks(inquiryObjectClass, inquiryParameter.getValue())) {
192                 try {
193                     parameterValue = CoreApiServiceLocator.getEncryptionService().encrypt(parameterValue);
194                 } catch (GeneralSecurityException e) {
195                     LOG.error("Exception while trying to encrypted value for inquiry framework.", e);
196                     throw new RuntimeException(e);
197                 }
198             }
199 
200             // add inquiry parameter to URL
201             urlParameters.put(inquiryParameter.getValue(), parameterValue);
202         }
203 
204         // check for EBOs and adjust inquiry
205         ModuleService responsibleModuleService =
206                 KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(inquiryObjectClass);
207         if (responsibleModuleService != null && responsibleModuleService.isExternalizable(inquiryObjectClass)) {
208             Class<? extends ExternalizableBusinessObject> implLookupObjectClass =
209                     responsibleModuleService.getExternalizableBusinessObjectImplementation(
210                             inquiryObjectClass.asSubclass(ExternalizableBusinessObject.class));
211 
212             // TODO: this should set base inquiry URL from module service as well, but right now set for KNS
213             if (implLookupObjectClass != null) {
214                 urlParameters.put(UifParameters.DATA_OBJECT_CLASS_NAME, implLookupObjectClass.getName());
215             } else {
216                 throw new RuntimeException(
217                         "Unable to find implementation class for EBO: " + inquiryObjectClass.getName());
218             }
219         }
220 
221         String inquiryUrl = UrlFactory.parameterizeUrl(getBaseInquiryUrl(), urlParameters);
222         getInquiryLinkField().setHrefText(inquiryUrl);
223 
224         // set inquiry title
225         String linkTitle = createTitleText(inquiryObjectClass);
226         linkTitle = LookupInquiryUtils.getLinkTitleText(linkTitle, inquiryObjectClass, getInquiryParameters());
227         getInquiryLinkField().setTitle(linkTitle);
228 
229         setRender(true);
230     }
231 
232     /**
233      * Gets text to prepend to the inquiry link title
234      *
235      * @param dataObjectClass - data object class being inquired into
236      * @return String title prepend text
237      */
238     public String createTitleText(Class<?> dataObjectClass) {
239         String titleText = "";
240 
241         String titlePrefixProp =
242                 KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString(INQUIRY_TITLE_PREFIX);
243         if (StringUtils.isNotBlank(titlePrefixProp)) {
244             titleText += titlePrefixProp + " ";
245         }
246 
247         String objectLabel = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary()
248                 .getDataObjectEntry(dataObjectClass.getName()).getObjectLabel();
249         if (StringUtils.isNotBlank(objectLabel)) {
250             titleText += objectLabel + " ";
251         }
252 
253         return titleText;
254     }
255 
256     /**
257      * @see org.kuali.rice.krad.uif.component.ComponentBase#getNestedComponents()
258      */
259     @Override
260     public List<Component> getNestedComponents() {
261         List<Component> components = super.getNestedComponents();
262 
263         components.add(getInquiryLinkField());
264 
265         return components;
266     }
267 
268     public String getBaseInquiryUrl() {
269         return this.baseInquiryUrl;
270     }
271 
272     public void setBaseInquiryUrl(String baseInquiryUrl) {
273         this.baseInquiryUrl = baseInquiryUrl;
274     }
275 
276     public String getDataObjectClassName() {
277         return this.dataObjectClassName;
278     }
279 
280     public void setDataObjectClassName(String dataObjectClassName) {
281         this.dataObjectClassName = dataObjectClassName;
282     }
283 
284     public String getViewName() {
285         return this.viewName;
286     }
287 
288     public void setViewName(String viewName) {
289         this.viewName = viewName;
290     }
291 
292     public boolean isForceInquiry() {
293         return this.forceInquiry;
294     }
295 
296     public void setForceInquiry(boolean forceInquiry) {
297         this.forceInquiry = forceInquiry;
298     }
299 
300     public Map<String, String> getInquiryParameters() {
301         return this.inquiryParameters;
302     }
303 
304     public void setInquiryParameters(Map<String, String> inquiryParameters) {
305         this.inquiryParameters = inquiryParameters;
306     }
307 
308     public LinkField getInquiryLinkField() {
309         return this.inquiryLinkField;
310     }
311 
312     public void setInquiryLinkField(LinkField inquiryLinkField) {
313         this.inquiryLinkField = inquiryLinkField;
314     }
315 }