View Javadoc

1   /**
2    * Copyright 2005-2014 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.impl.actionlist;
17  
18  import com.google.common.collect.ArrayListMultimap;
19  import com.google.common.collect.ListMultimap;
20  import org.apache.commons.lang.StringUtils;
21  import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
22  import org.kuali.rice.kew.api.action.ActionItem;
23  import org.kuali.rice.kew.api.action.ActionItemCustomization;
24  import org.kuali.rice.kew.doctype.bo.DocumentType;
25  import org.kuali.rice.kew.doctype.service.DocumentTypeService;
26  import org.kuali.rice.kew.framework.KewFrameworkServiceLocator;
27  import org.kuali.rice.kew.framework.actionlist.ActionListCustomizationHandlerService;
28  import org.kuali.rice.kew.framework.actionlist.ActionListCustomizationMediator;
29  import org.kuali.rice.kew.rule.bo.RuleAttribute;
30  
31  import java.util.Collections;
32  import java.util.HashMap;
33  import java.util.List;
34  import java.util.Map;
35  
36  /**
37   * Internal utility class that partitions ActionItems by application id, and calls the appropriate
38   * {@link ActionListCustomizationHandlerService} for each parition to retrieve any customizations.
39   */
40  public class ActionListCustomizationMediatorImpl implements ActionListCustomizationMediator {
41  
42      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ActionListCustomizationMediatorImpl.class);
43  
44      private DocumentTypeService documentTypeService;
45      private ActionListCustomizationHandlerServiceChooser actionListCustomizationHandlerServiceChooser =
46              new ActionListCustomizationHandlerServiceChooser();
47  
48      /**
49       * <p>partitions ActionItems by application id, and calls the appropriate
50       * {@link ActionListCustomizationHandlerService} for each parition, merging the results.</p>
51       *
52       * <dl><dt><b>inherited docs:</b></dt><dd>{@inheritDoc}</dd></dl>
53       */
54      @Override
55      public Map<String, ActionItemCustomization> getActionListCustomizations(String principalId,
56              List<ActionItem> actionItems) throws RiceIllegalArgumentException {
57          if (StringUtils.isBlank(principalId)) {
58              throw new RiceIllegalArgumentException("invalid principalId: " + principalId);
59          }
60          if (actionItems == null) {
61              actionItems = Collections.emptyList();
62          }
63  
64          // map from action item ID to ActionItemCustomization
65          Map<String, ActionItemCustomization> results = new HashMap<String, ActionItemCustomization>();
66  
67          // group each action item by application id that needs to be called for action list customizations (note that
68          // the application id comes from the extension/rule attribute record, most action lists will have doc types
69          // with no custom action list attribute, though the default still needs to be run in this case)
70  
71          ListMultimap<String, ActionItem> itemsByApplicationId = ArrayListMultimap.create();
72  
73          for (ActionItem actionItem : actionItems) {
74              //DocumentType docType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(actionItem.getDocName());
75              DocumentType docType = getDocumentTypeService().findByName(actionItem.getDocName());
76              if (docType == null) {
77                  LOG.error(String.format("Action item %s has an invalid document type name of %s",
78                          actionItem.getId(), actionItem.getDocName()));
79                  // OK to have a null key, this represents the default app id
80                  itemsByApplicationId.put(null, actionItem);
81              } else {
82                  // OK to have a null key, this represents the default app id
83                  itemsByApplicationId.put(getActionListCustomizationApplicationId(docType), actionItem);
84              }
85          }
86  
87          // For each application id, pass all action items which might need to be customized (because they have a
88          // document type, which declares an action list attribute, which has an application id declared) to the
89          // appropriate ActionListCustomizationHandlerService endpoint
90  
91          for (String applicationId : itemsByApplicationId.keySet()) {
92              ActionListCustomizationHandlerService actionListCustomizationHandler =
93                      getActionListCustomizationHandlerServiceChooser().getByApplicationId(applicationId);
94  
95              if (actionListCustomizationHandler == null) {
96                  // get the local ActionListCustomizationHandlerService as a fallback
97                  actionListCustomizationHandler =
98                          getActionListCustomizationHandlerServiceChooser().getByApplicationId(null);
99              }
100 
101             List<ActionItemCustomization> customizations =
102                     actionListCustomizationHandler.customizeActionList(principalId, itemsByApplicationId.get(
103                             applicationId));
104 
105 
106             // Get back the customized results and reassemble with customized results from all different application
107             // customizations (as well as default customizations)
108             if (customizations != null) for (ActionItemCustomization customization : customizations) {
109                 results.put(customization.getActionItemId(), customization);
110             }
111         }
112 
113         return results;
114     }
115 
116     // CustomActionListAttributes are configured in RuleAttributes, so that is the
117     // applicationId we need to use
118     private String getActionListCustomizationApplicationId(DocumentType docType) {
119         String applicationId = null;
120         RuleAttribute ruleAttribute = docType.getCustomActionListRuleAttribute();
121         if (ruleAttribute != null) {
122             applicationId = ruleAttribute.getApplicationId();
123         }
124         // we may return null
125         return applicationId;
126     }
127 
128     public DocumentTypeService getDocumentTypeService() {
129         return documentTypeService;
130     }
131 
132     public void setDocumentTypeService(DocumentTypeService documentTypeService) {
133         this.documentTypeService = documentTypeService;
134     }
135 
136     /**
137      * Need this to make our class testable without having to wire the universe up through spring.
138      */
139     public static class ActionListCustomizationHandlerServiceChooser {
140         public ActionListCustomizationHandlerService getByApplicationId(String applicationId) {
141             return KewFrameworkServiceLocator.getActionListCustomizationHandlerService(applicationId);
142         }
143     }
144 
145     public ActionListCustomizationHandlerServiceChooser getActionListCustomizationHandlerServiceChooser() {
146         return actionListCustomizationHandlerServiceChooser;
147     }
148 
149     public void setActionListCustomizationHandlerServiceChooser(
150             ActionListCustomizationHandlerServiceChooser actionListCustomizationHandlerServiceChooser) {
151         this.actionListCustomizationHandlerServiceChooser = actionListCustomizationHandlerServiceChooser;
152     }
153 }