View Javadoc

1   /**
2    * Copyright 2005-2012 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.kew.rule.web;
17  
18  import org.apache.commons.beanutils.PropertyUtils;
19  import org.apache.struts.action.ActionErrors;
20  import org.apache.struts.action.ActionMessage;
21  import org.kuali.rice.core.api.util.RiceConstants;
22  import org.kuali.rice.core.framework.persistence.jdbc.sql.SQLUtils;
23  import org.kuali.rice.kew.api.KewApiConstants;
24  import org.kuali.rice.kew.api.rule.RoleName;
25  import org.kuali.rice.kew.api.util.CodeTranslator;
26  import org.kuali.rice.kew.exception.WorkflowServiceError;
27  import org.kuali.rice.kew.rule.KeyValueId;
28  import org.kuali.rice.kew.rule.RuleBaseValues;
29  import org.kuali.rice.kew.rule.RuleDelegationBo;
30  import org.kuali.rice.kew.rule.RuleExtensionValue;
31  import org.kuali.rice.kew.rule.RuleResponsibilityBo;
32  import org.kuali.rice.kew.rule.WorkflowRuleAttributeRows;
33  import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
34  import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
35  import org.kuali.rice.kew.rule.service.RuleDelegationService;
36  import org.kuali.rice.kew.rule.service.RuleTemplateService;
37  import org.kuali.rice.kew.service.KEWServiceLocator;
38  import org.kuali.rice.kns.web.ui.Field;
39  import org.kuali.rice.kns.web.ui.Row;
40  
41  import java.sql.Timestamp;
42  import java.text.ParseException;
43  import java.text.SimpleDateFormat;
44  import java.util.ArrayList;
45  import java.util.Calendar;
46  import java.util.Collection;
47  import java.util.Collections;
48  import java.util.Date;
49  import java.util.HashMap;
50  import java.util.Iterator;
51  import java.util.List;
52  import java.util.Map;
53  
54  
55  /**
56   * A decorator around a {@link RuleBaseValues} object which provides some
57   * convienance functions for interacting with the bean from the web-tier.
58   * This helps to alleviate some of the weaknesses of JSTL.
59   *
60   * @author Kuali Rice Team (rice.collab@kuali.org)
61   */
62  public class WebRuleBaseValues extends RuleBaseValues {
63  
64  	private static final long serialVersionUID = 5938997470219200474L;
65      private static final int TO_DATE_UPPER_LIMIT = 2100;
66  	private List rows = new ArrayList();
67  	private List fields = new ArrayList();
68  	private List roles = new ArrayList();
69  	private String fromDateString;
70  	private String toDateString;
71  	private String ruleTemplateName;
72  	private boolean hasExtensionValueErrors = false;
73  
74  	public WebRuleBaseValues() {
75  	}
76  
77  	public WebRuleBaseValues(RuleBaseValues rule) throws Exception {
78  		edit(rule);
79  	}
80  
81      private void loadFields() {
82     		fields.clear();
83     		if (getRuleTemplateId() != null) {
84     			RuleTemplateBo ruleTemplate = getRuleTemplateService().findByRuleTemplateId(getRuleTemplateId());
85     			if (ruleTemplate != null) {
86     				List ruleTemplateAttributes = ruleTemplate.getActiveRuleTemplateAttributes();
87     				Collections.sort(ruleTemplateAttributes);
88     				for (Iterator iter = ruleTemplateAttributes.iterator(); iter.hasNext();) {
89     					RuleTemplateAttributeBo ruleTemplateAttribute = (RuleTemplateAttributeBo) iter.next();
90     					if (!ruleTemplateAttribute.isWorkflowAttribute()) {
91     						continue;
92     					}
93                      WorkflowRuleAttributeRows workflowRuleAttributeRows =
94                              KEWServiceLocator.getWorkflowRuleAttributeMediator().getRuleRows(null, ruleTemplateAttribute);
95     					for (Row row : workflowRuleAttributeRows.getRows()) {
96     						for (Field field : row.getFields()) {
97                                 String fieldValue = "";
98                                 RuleExtensionValue extensionValue = getRuleExtensionValue(ruleTemplateAttribute.getId(), field.getPropertyName());
99                                 fieldValue = (extensionValue != null) ? extensionValue.getValue() : field.getPropertyValue();
100                                fields.add(new KeyValueId(field.getPropertyName(), fieldValue, ruleTemplateAttribute.getId()));
101                            }
102    					}
103    				}
104    			}
105    		}
106    	}
107 
108 	private void loadWebValues() {
109 		loadRows();
110 		loadDates();
111 		loadRuleTemplateName();
112 	}
113 
114     private void loadRows() {
115    		getRoles().clear();
116    		if (getRuleTemplateId() != null) {
117    			RuleTemplateBo ruleTemplate = getRuleTemplateService().findByRuleTemplateId(getRuleTemplateId());
118    			if (ruleTemplate != null) {
119    				setRuleTemplateName(ruleTemplate.getName());
120    				List<RuleTemplateAttributeBo> ruleTemplateAttributes = ruleTemplate.getActiveRuleTemplateAttributes();
121    				Collections.sort(ruleTemplateAttributes);
122    				List<Row> rows = new ArrayList<Row>();
123    				for (RuleTemplateAttributeBo ruleTemplateAttribute : ruleTemplateAttributes) {
124    					if (!ruleTemplateAttribute.isWorkflowAttribute()) {
125    						continue;
126    					}
127                     WorkflowRuleAttributeRows workflowRuleAttributeRows =
128                             KEWServiceLocator.getWorkflowRuleAttributeMediator().getRuleRows(getFieldMap(ruleTemplateAttribute.getId()), ruleTemplateAttribute);
129                     rows.addAll(workflowRuleAttributeRows.getRows());
130                     getRoles().addAll(KEWServiceLocator.getWorkflowRuleAttributeMediator().getRoleNames(ruleTemplateAttribute));
131    				}
132    				setRows(rows);
133    			}
134    		}
135    	}
136 
137 	private void loadDates() {
138 		if (getFromDateString() != null) {
139 			setFromDateString(RiceConstants.getDefaultDateFormat().format(getFromDateValue()));
140 		}
141 		if (getToDateString() != null) {
142 			setToDateString(RiceConstants.getDefaultDateFormat().format(getToDateValue()));
143 		}
144 	}
145 
146 	private void loadRuleTemplateName() {
147 		if (org.apache.commons.lang.StringUtils.isEmpty(getRuleTemplateName()) && getRuleTemplateId() != null) {
148 			RuleTemplateBo ruleTemplate = getRuleTemplateService().findByRuleTemplateId(getRuleTemplateId());
149 			if (ruleTemplate != null) {
150 				setRuleTemplateName(ruleTemplate.getName());
151 			}
152 		}
153 	}
154 
155 	public List getFields() {
156 		return fields;
157 	}
158 
159 	public void setFields(List fields) {
160 		this.fields = fields;
161 	}
162 
163 	public KeyValueId getField(int index) {
164 		while (getFields().size() <= index) {
165 			KeyValueId field = new KeyValueId();
166 			getFields().add(field);
167 		}
168 		return (KeyValueId) getFields().get(index);
169 	}
170 
171 	public String getFromDateString() {
172 		return fromDateString;
173 	}
174 
175 	public void setFromDateString(String fromDateString) {
176 		this.fromDateString = fromDateString;
177 	}
178 
179 	public List<RoleName> getRoles() {
180 		return roles;
181 	}
182 
183 	public void setRoles(List<RoleName> roles) {
184 		this.roles = roles;
185 	}
186 
187 	public List<RoleName> getRows() {
188 		return rows;
189 	}
190 
191 	public void setRows(List ruleTemplateAttributes) {
192 		this.rows = ruleTemplateAttributes;
193 	}
194 
195     @Override
196 	public String getToDateString() {
197 		return this.toDateString;
198 	}
199 
200 	public void setToDateString(String toDateString) {
201 		this.toDateString = toDateString;
202 	}
203 
204 	@Override
205 	public String getRuleTemplateName() {
206 		return ruleTemplateName;
207 	}
208 
209 	public void setRuleTemplateName(String ruleTemplateName) {
210 		this.ruleTemplateName = ruleTemplateName;
211 	}
212 
213 	public boolean isHasExtensionValueErrors() {
214 		return hasExtensionValueErrors;
215 	}
216 
217 	public void setHasExtensionValueErrors(boolean hasRuleExtensionValueErrors) {
218 		this.hasExtensionValueErrors = hasRuleExtensionValueErrors;
219 	}
220 
221 	/** Web Logic * */
222 
223 	/**
224 	 * Populates this WebRuleBaseValues object for editing the given rule.
225 	 */
226 	public void edit(RuleBaseValues rule) throws Exception {
227 		load(rule);
228 		initialize();
229 	}
230 
231 	/**
232 	 * Loads the given rule into this WebRuleBaseValues.
233 	 */
234 	public void load(RuleBaseValues rule) throws Exception {
235 		PropertyUtils.copyProperties(this, rule);
236 		injectWebMembers();
237 	}
238 
239 	public void initialize() throws Exception {
240 		loadFields();
241 		// setPreviousRuleId(getId());
242 		for (Object element : getRuleResponsibilities()) {
243 			WebRuleResponsibility responsibility = (WebRuleResponsibility) element;
244 			responsibility.initialize();
245 		}
246 		establishRequiredState();
247 	}
248 
249 	private void injectWebMembers() throws Exception {
250 		List currentResponsibilities = getRuleResponsibilities();
251 		setRuleResponsibilities(new ArrayList());
252 		for (Iterator iterator = currentResponsibilities.iterator(); iterator.hasNext();) {
253 			RuleResponsibilityBo responsibility = (RuleResponsibilityBo) iterator.next();
254 			WebRuleResponsibility webResponsibility = createNewRuleResponsibility();
255 			webResponsibility.load(responsibility);
256 		}
257 	}
258 
259 	/**
260 	 * Establishes any missing and required state in the WebRuleBaseValues.
261 	 */
262 	public void establishRequiredState() throws Exception {
263 		loadWebValues();
264 		if (getRuleResponsibilities().isEmpty()) {
265 			createNewRuleResponsibility();
266 		}
267 		for (Object element : getRuleResponsibilities()) {
268 			WebRuleResponsibility responsibility = (WebRuleResponsibility) element;
269 			responsibility.establishRequiredState();
270 		}
271 	}
272 
273 	@Override
274 	public RuleResponsibilityBo getResponsibility(int index) {
275 		while (getRuleResponsibilities().size() <= index) {
276 			createNewRuleResponsibility();
277 		}
278 		return getRuleResponsibilities().get(index);
279 	}
280 
281 	public int getResponsibilitiesSize() {
282 		return getRuleResponsibilities().size();
283 	}
284 
285 	public WebRuleResponsibility createNewRuleResponsibility() {
286 		WebRuleResponsibility responsibility = new WebRuleResponsibility();
287 		responsibility.setRuleBaseValues(this);
288 		addRuleResponsibility(responsibility);
289 		return responsibility;
290 	}
291 
292 	public Map getFieldMap(String ruleTemplateAttributeId) {
293 		Map fieldMap = new HashMap();
294 		for (Iterator iterator = getFields().iterator(); iterator.hasNext();) {
295 			KeyValueId field = (KeyValueId) iterator.next();
296 			if (ruleTemplateAttributeId.equals(field.getId())) {
297 				fieldMap.put(field.getKey(), field.getValue());
298 			}
299 		}
300 		return fieldMap;
301 	}
302 
303 	public void populatePreviousRuleIds() {
304 		if (getPreviousRuleId() == null) {
305 			setPreviousRuleId(getId());
306 		}
307 		for (Object element : getRuleResponsibilities()) {
308 			WebRuleResponsibility responsibility = (WebRuleResponsibility) element;
309 			responsibility.populatePreviousRuleIds();
310 		}
311 	}
312 
313 	/**
314 	 * This method is used to "materialize" the web rule before it gets saved, if we don't do this then certain fields will be saved as NULL. For example, ruleTemplate.
315 	 */
316 	public void materialize() {
317 		if (getRuleTemplate() == null && getRuleTemplateId() != null) {
318 			setRuleTemplate(getRuleTemplateService().findByRuleTemplateId(getRuleTemplateId()));
319 		}
320 	}
321 
322     /**
323      * This will ensure that the toDate is never larger than 2100, currently
324      * doesn't do any throttling on the from date
325      */
326     private void throttleDates() {
327         if (getToDateValue() != null) {
328             Calendar calendar = Calendar.getInstance();
329             calendar.setTime(getToDateValue());
330             if (calendar.get(Calendar.YEAR) > TO_DATE_UPPER_LIMIT) {
331                 calendar.set(Calendar.YEAR, TO_DATE_UPPER_LIMIT);
332                 setToDateValue(new Timestamp(calendar.getTimeInMillis()));
333                 setToDateString(new SimpleDateFormat("MM/dd/yyyy").format(getToDateValue()));
334             }
335         }
336     }
337 
338 	private void saveServiceErrors(String errorKey, Collection srvErrors, ActionErrors errors) {
339 		for (Iterator iterator = srvErrors.iterator(); iterator.hasNext();) {
340 			WorkflowServiceError error = (WorkflowServiceError) iterator.next();
341 			if (error.getArg1() == null && error.getArg2() == null) {
342 				errors.add(errorKey, new ActionMessage(error.getKey()));
343 			} else if (error.getArg1() != null && error.getArg2() == null) {
344 				errors.add(errorKey, new ActionMessage(error.getKey(), error.getArg1()));
345 			} else {
346 				errors.add(errorKey, new ActionMessage(error.getKey(), error.getArg1(), error.getArg2()));
347 			}
348 		}
349 	}
350 
351 	private Timestamp decodeTimestamp(String dateValue) throws ParseException {
352 		if (org.apache.commons.lang.StringUtils.isEmpty(dateValue)) {
353 			return null;
354 		}
355 		/*  Not the best solution below but does allow our forcing of the 4 digit year
356 		 *  until KEW and use the KNS for it's date entry/validation
357 		 */
358 		String convertedDate = SQLUtils.getEntryFormattedDate(dateValue);
359 		if (convertedDate == null) {
360 		    throw new ParseException("Date entered as '" + dateValue + "' is in invalid format", 0);
361 		}
362 		Date date = RiceConstants.getDefaultDateFormat().parse(convertedDate);
363 		return new Timestamp(date.getTime());
364 	}
365 
366 	private RuleTemplateService getRuleTemplateService() {
367 		return (RuleTemplateService) KEWServiceLocator.getService(KEWServiceLocator.RULE_TEMPLATE_SERVICE);
368 	}
369 
370 	/**
371 	 * @return Returns the actionRequestCodes.
372 	 */
373 	public Map getActionRequestCodes() {
374 		Map actionRequestCodes = new HashMap();
375 		actionRequestCodes.putAll(CodeTranslator.arLabels);
376 		if (getRuleTemplateId() != null) {
377 			RuleTemplateBo ruleTemplate = getRuleTemplateService().findByRuleTemplateId(getRuleTemplateId());
378 			if (ruleTemplate != null) {
379 				if (ruleTemplate.getAcknowledge() != null && "false".equals(ruleTemplate.getAcknowledge().getValue())) {
380 					actionRequestCodes.remove(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ);
381 				}
382 				if (ruleTemplate.getComplete() != null && "false".equals(ruleTemplate.getComplete().getValue())) {
383 					actionRequestCodes.remove(KewApiConstants.ACTION_REQUEST_COMPLETE_REQ);
384 				}
385 				if (ruleTemplate.getApprove() != null && "false".equals(ruleTemplate.getApprove().getValue())) {
386 					actionRequestCodes.remove(KewApiConstants.ACTION_REQUEST_APPROVE_REQ);
387 				}
388 				if (ruleTemplate.getFyi() != null && "false".equals(ruleTemplate.getFyi().getValue())) {
389 					actionRequestCodes.remove(KewApiConstants.ACTION_REQUEST_FYI_REQ);
390 				}
391 			}
392 		}
393 		return actionRequestCodes;
394 	}
395 
396 	public RuleDelegationBo getRuleDelegation() {
397 		if (getDelegateRule().booleanValue()) {
398 			List ruleDelegations = getRuleDelegationService().findByDelegateRuleId(getId());
399 			RuleDelegationBo currentRuleDelegation = (RuleDelegationBo) ruleDelegations.get(0);
400 			RuleBaseValues mostRecentRule = currentRuleDelegation.getRuleResponsibility().getRuleBaseValues();
401 
402 			for (Iterator iter = ruleDelegations.iterator(); iter.hasNext();) {
403 				RuleDelegationBo ruleDelegation = (RuleDelegationBo) iter.next();
404 				RuleBaseValues parentRule = ruleDelegation.getRuleResponsibility().getRuleBaseValues();
405 
406 				if (parentRule.getActivationDate().after(mostRecentRule.getActivationDate())) {
407 					mostRecentRule = ruleDelegation.getRuleResponsibility().getRuleBaseValues();
408 					currentRuleDelegation = ruleDelegation;
409 				}
410 			}
411 			return currentRuleDelegation;
412 		}
413 		return null;
414 	}
415 
416 	public String getParentRuleId() {
417 		if (getDelegateRule().booleanValue()) {
418 			List ruleDelegations = getRuleDelegationService().findByDelegateRuleId(getId());
419 			RuleDelegationBo currentRuleDelegation = (RuleDelegationBo) ruleDelegations.get(0);
420 			RuleBaseValues mostRecentRule = currentRuleDelegation.getRuleResponsibility().getRuleBaseValues();
421 
422 			for (Iterator iter = ruleDelegations.iterator(); iter.hasNext();) {
423 				RuleDelegationBo ruleDelegation = (RuleDelegationBo) iter.next();
424 				RuleBaseValues parentRule = ruleDelegation.getRuleResponsibility().getRuleBaseValues();
425 
426 				if (parentRule.getActivationDate().after(mostRecentRule.getActivationDate())) {
427 					mostRecentRule = ruleDelegation.getRuleResponsibility().getRuleBaseValues();
428 				}
429 			}
430 			return mostRecentRule.getId();
431 		}
432 		return null;
433 	}
434 
435 	private RuleDelegationService getRuleDelegationService() {
436 		return (RuleDelegationService) KEWServiceLocator.getService(KEWServiceLocator.RULE_DELEGATION_SERVICE);
437 	}
438 }