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.preferences.service.impl;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.HashMap;
21  import java.util.Map;
22  import java.util.Map.Entry;
23  
24  import org.apache.commons.lang.StringUtils;
25  import org.kuali.rice.core.api.CoreApiServiceLocator;
26  import org.kuali.rice.core.api.config.property.ConfigContext;
27  import org.kuali.rice.core.api.config.property.ConfigurationService;
28  import org.kuali.rice.kew.api.KewApiConstants;
29  import org.kuali.rice.kew.api.preferences.Preferences;
30  import org.kuali.rice.kew.api.preferences.PreferencesService;
31  import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
32  import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl;
33  import org.kuali.rice.kew.service.KEWServiceLocator;
34  import org.kuali.rice.kew.useroptions.UserOptions;
35  import org.kuali.rice.kew.useroptions.UserOptionsService;
36  
37  /**
38   * An implementation of the {@link PreferencesService}.
39   *
40   * @author Kuali Rice Team (rice.collab@kuali.org)
41   */
42  public class PreferencesServiceImpl implements PreferencesService {
43  
44      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PreferencesServiceImpl.class);
45  
46      private static Map<String, String> USER_OPTION_KEY_DEFAULT_MAP;
47  
48      static {
49          USER_OPTION_KEY_DEFAULT_MAP = new HashMap<String, String>();
50          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.COLOR_APPROVED, "userOptions.default.color");
51          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.COLOR_CANCELED, "userOptions.default.color");
52          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.COLOR_DISAPPROVE_CANCEL, "userOptions.default.color");
53          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.COLOR_DISAPPROVED, "userOptions.default.color");
54          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.COLOR_ENROUTE, "userOptions.default.color");
55          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.COLOR_EXCEPTION, "userOptions.default.color");
56          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.COLOR_FINAL, "userOptions.default.color");
57          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.COLOR_INITIATED, "userOptions.default.color");
58          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.COLOR_PROCESSED, "userOptions.default.color");
59          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.COLOR_SAVED, "userOptions.default.color");
60          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.EMAIL_NOTIFICATION, "userOptions.default.email");
61          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.NOTIFY_PRIMARY_DELEGATION, "userOptions.default.notifyPrimary");
62          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.NOTIFY_SECONDARY_DELEGATION, "userOptions.default.notifySecondary");
63          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.OPEN_NEW_WINDOW, "userOptions.default.openNewWindow");
64          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.PAGE_SIZE, "userOptions.default.actionListSize");
65          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.REFRESH_RATE, "userOptions.default.refreshRate");
66          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.SHOW_ACTION_REQUESTED, "userOptions.default.showActionRequired");
67          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.SHOW_DATE_CREATED, "userOptions.default.showDateCreated");
68          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.SHOW_DOC_TYPE, "userOptions.default.showDocumentType");
69          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.SHOW_DOCUMENT_STATUS, "userOptions.default.showDocumentStatus");
70          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.SHOW_INITIATOR, "showInitiator");
71          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.SHOW_DELEGATOR, "userOptions.default.showDelegator");
72          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.SHOW_DOC_TITLE, "userOptions.default.showTitle");
73          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.SHOW_GROUP_REQUEST, "userOptions.default.showWorkgroupRequest");
74          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.SHOW_CLEAR_FYI, "userOptions.default.showClearFYI");
75          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.DELEGATOR_FILTER, "userOptions.default.delegatorFilterOnActionList");
76          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.PRIMARY_DELEGATE_FILTER, "userOptions.default.primaryDelegatorFilterOnActionList");
77          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.SHOW_DATE_APPROVED, "userOptions.default.showLastApprovedDate");
78          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.SHOW_CURRENT_NODE, "userOptions.default.showCurrentNode");
79          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.USE_OUT_BOX, KewApiConstants.USER_OPTIONS_DEFAULT_USE_OUTBOX_PARAM);
80          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.NOTIFY_ACKNOWLEDGE, "userOptions.default.notifyAcknowledge");
81          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.NOTIFY_APPROVE, "userOptions.default.notifyApprove");
82          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.NOTIFY_COMPLETE, "userOptions.default.notifyComplete");
83          USER_OPTION_KEY_DEFAULT_MAP.put(Preferences.KEYS.NOTIFY_FYI, "userOptions.default.notifyFYI");
84      }
85  
86  
87      public Preferences getPreferences(String principalId) {
88          if ( LOG.isDebugEnabled() ) {
89          LOG.debug("start preferences fetch user " + principalId);
90          }
91          Collection<UserOptions> options = getUserOptionService().findByWorkflowUser(principalId);
92          Map<String,UserOptions> optionMap = new HashMap<String, UserOptions>();
93          Map<String,String> optionValueMap = new HashMap<String, String>();
94          Map<String, String> documentTypeNotificationPreferences = new HashMap<String, String>();
95          for ( UserOptions option : options ) {
96              if(option.getOptionId().endsWith(KewApiConstants.DOCUMENT_TYPE_NOTIFICATION_PREFERENCE_SUFFIX)) {
97                  String preferenceName = option.getOptionId();
98                  preferenceName = StringUtils.substringBeforeLast(preferenceName, KewApiConstants.DOCUMENT_TYPE_NOTIFICATION_PREFERENCE_SUFFIX);
99                  documentTypeNotificationPreferences.put(preferenceName, option.getOptionVal());
100             } else {
101                 optionMap.put(option.getOptionId(), option);
102             }
103         }
104         
105         ConfigurationService kcs = CoreApiServiceLocator.getKualiConfigurationService();
106 
107         boolean isSaveRequired = false;
108 
109         for (Map.Entry<String, String> entry : USER_OPTION_KEY_DEFAULT_MAP.entrySet()) {
110             String optionKey = entry.getKey();
111             String defaultValue = kcs.getPropertyValueAsString(entry.getValue());
112             if (LOG.isDebugEnabled()) {
113                 LOG.debug("start fetch option " + optionKey + " user " + principalId);
114             }
115 
116             UserOptions option = optionMap.get(optionKey);
117             if (option == null) {
118                 if (LOG.isDebugEnabled()) {
119                     LOG.debug("User option '"
120                             + optionKey
121                             + "' on user "
122                             + principalId
123                             + " has no stored value.  Preferences will require save.");
124                 }
125                 option = new UserOptions();
126                 option.setWorkflowId(principalId);
127                 option.setOptionId(optionKey);
128                 option.setOptionVal(defaultValue);
129                 optionMap.put(optionKey, option); // just in case referenced a second time
130 
131                 if (!isSaveRequired) {
132                     if (optionKey.equals(Preferences.KEYS.USE_OUT_BOX) && !ConfigContext.getCurrentContextConfig().getOutBoxOn()) {
133                         // don't mark as needing save
134                     } else {
135                         isSaveRequired = true;
136                     }
137                 }
138             }
139             if (LOG.isDebugEnabled()) {
140                 LOG.debug("End fetch option " + optionKey + " user " + principalId);
141             }
142 
143             optionValueMap.put(optionKey, option.getOptionVal());
144         }
145 
146 //  TODO: JLR - I'm not sure why this isSaveRequired logic is necessary -- couldn't we do something like the following?
147 //        if (isSaveRequired)
148 //            getUserOptionService().save(principalId, optionValueMap);
149 
150         return Preferences.Builder.create(optionValueMap, documentTypeNotificationPreferences, isSaveRequired).build();
151     }
152 
153     public void savePreferences(String principalId, Preferences preferences) {
154     	// NOTE: this previously displayed the principalName.  Now it's just the id
155     	if ( LOG.isDebugEnabled() ) {
156             LOG.debug("saving preferences user " + principalId);
157     	}
158 
159         validate(preferences);
160         Map<String,String> optionsMap = new HashMap<String,String>(50);
161         
162         optionsMap.put(Preferences.KEYS.COLOR_DISAPPROVE_CANCEL, preferences.getColorDisapproveCancel());
163         optionsMap.put(Preferences.KEYS.COLOR_DISAPPROVED, preferences.getColorDisapproved());
164         optionsMap.put(Preferences.KEYS.COLOR_APPROVED, preferences.getColorApproved());
165         optionsMap.put(Preferences.KEYS.COLOR_CANCELED, preferences.getColorCanceled());
166         optionsMap.put(Preferences.KEYS.COLOR_SAVED, preferences.getColorSaved());
167         optionsMap.put(Preferences.KEYS.COLOR_ENROUTE, preferences.getColorEnroute());
168         optionsMap.put(Preferences.KEYS.COLOR_PROCESSED, preferences.getColorProcessed());
169         optionsMap.put(Preferences.KEYS.COLOR_INITIATED, preferences.getColorInitiated());
170         optionsMap.put(Preferences.KEYS.COLOR_FINAL, preferences.getColorFinal());
171         optionsMap.put(Preferences.KEYS.COLOR_EXCEPTION, preferences.getColorException());
172         optionsMap.put(Preferences.KEYS.REFRESH_RATE, preferences.getRefreshRate().trim());
173         optionsMap.put(Preferences.KEYS.OPEN_NEW_WINDOW, preferences.getOpenNewWindow());
174         optionsMap.put(Preferences.KEYS.SHOW_DOC_TYPE, preferences.getShowDocType());
175         optionsMap.put(Preferences.KEYS.SHOW_DOC_TITLE, preferences.getShowDocTitle());
176         optionsMap.put(Preferences.KEYS.SHOW_ACTION_REQUESTED, preferences.getShowActionRequested());
177         optionsMap.put(Preferences.KEYS.SHOW_INITIATOR, preferences.getShowInitiator());
178         optionsMap.put(Preferences.KEYS.SHOW_DELEGATOR, preferences.getShowDelegator());
179         optionsMap.put(Preferences.KEYS.SHOW_DATE_CREATED, preferences.getShowDateCreated());
180         optionsMap.put(Preferences.KEYS.SHOW_DOCUMENT_STATUS, preferences.getShowDocumentStatus());
181         optionsMap.put(Preferences.KEYS.SHOW_APP_DOC_STATUS, preferences.getShowAppDocStatus());
182         optionsMap.put(Preferences.KEYS.SHOW_GROUP_REQUEST, preferences.getShowWorkgroupRequest());
183         optionsMap.put(Preferences.KEYS.SHOW_CLEAR_FYI, preferences.getShowClearFyi());
184         optionsMap.put(Preferences.KEYS.PAGE_SIZE, preferences.getPageSize().trim());
185         optionsMap.put(Preferences.KEYS.EMAIL_NOTIFICATION, preferences.getEmailNotification());
186         optionsMap.put(Preferences.KEYS.NOTIFY_PRIMARY_DELEGATION, preferences.getNotifyPrimaryDelegation());
187         optionsMap.put(Preferences.KEYS.NOTIFY_SECONDARY_DELEGATION, preferences.getNotifySecondaryDelegation());
188         optionsMap.put(Preferences.KEYS.DELEGATOR_FILTER, preferences.getDelegatorFilter());
189         optionsMap.put(Preferences.KEYS.PRIMARY_DELEGATE_FILTER, preferences.getPrimaryDelegateFilter());
190         optionsMap.put(Preferences.KEYS.SHOW_DATE_APPROVED, preferences.getShowDateApproved());
191         optionsMap.put(Preferences.KEYS.SHOW_CURRENT_NODE, preferences.getShowCurrentNode());
192         optionsMap.put(Preferences.KEYS.NOTIFY_ACKNOWLEDGE, preferences.getNotifyAcknowledge());
193         optionsMap.put(Preferences.KEYS.NOTIFY_APPROVE, preferences.getNotifyApprove());
194         optionsMap.put(Preferences.KEYS.NOTIFY_COMPLETE, preferences.getNotifyComplete());
195         optionsMap.put(Preferences.KEYS.NOTIFY_FYI, preferences.getNotifyFYI());
196         if (ConfigContext.getCurrentContextConfig().getOutBoxOn()) {
197             optionsMap.put(Preferences.KEYS.USE_OUT_BOX, preferences.getUseOutbox());
198         }
199         for(Entry<String, String> documentTypePreference : preferences.getDocumentTypeNotificationPreferences().entrySet()) {
200             optionsMap.put(documentTypePreference.getKey() + KewApiConstants.DOCUMENT_TYPE_NOTIFICATION_PREFERENCE_SUFFIX, documentTypePreference.getValue());
201         }
202         getUserOptionService().save(principalId, optionsMap);
203         
204         // Find which document type notification preferences have been deleted
205         // and remove them from the database
206         Preferences storedPreferences = this.getPreferences(principalId);
207         for(Entry<String, String> storedEntry : storedPreferences.getDocumentTypeNotificationPreferences().entrySet()) {
208             if(preferences.getDocumentTypeNotificationPreference(storedEntry.getKey()) == null) {
209                 getUserOptionService().deleteUserOptions(getUserOptionService().findByOptionId(storedEntry.getKey() + KewApiConstants.DOCUMENT_TYPE_NOTIFICATION_PREFERENCE_SUFFIX, principalId));
210             }
211         }
212         if ( LOG.isDebugEnabled() ) {
213         LOG.debug("saved preferences user " + principalId);
214     }
215     }
216 
217     private void validate(Preferences preferences) {
218         LOG.debug("validating preferences");
219         
220         Collection errors = new ArrayList();
221         try {
222             new Integer(preferences.getRefreshRate().trim());
223         } catch (NumberFormatException e) {
224             errors.add(new WorkflowServiceErrorImpl("ActionList Refresh Rate must be in whole " +
225                     "minutes", Preferences.KEYS.ERR_KEY_REFRESH_RATE_WHOLE_NUM));
226         } catch (NullPointerException e1) {
227             errors.add(new WorkflowServiceErrorImpl("ActionList Refresh Rate must be in whole " +
228                     "minutes", Preferences.KEYS.ERR_KEY_REFRESH_RATE_WHOLE_NUM));
229         }
230 
231         try {
232             if(new Integer(preferences.getPageSize().trim()) == 0){
233             	errors.add(new WorkflowServiceErrorImpl("ActionList Page Size must be non-zero ",
234                         Preferences.KEYS.ERR_KEY_ACTION_LIST_PAGE_SIZE_WHOLE_NUM));
235             }            
236         } catch (NumberFormatException e) {
237             errors.add(new WorkflowServiceErrorImpl("ActionList Page Size must be in whole " +
238                     "minutes", Preferences.KEYS.ERR_KEY_ACTION_LIST_PAGE_SIZE_WHOLE_NUM));
239         } catch (NullPointerException e1) {
240             errors.add(new WorkflowServiceErrorImpl("ActionList Page Size must be in whole " +
241                     "minutes", Preferences.KEYS.ERR_KEY_ACTION_LIST_PAGE_SIZE_WHOLE_NUM));
242         }
243       
244         LOG.debug("end validating preferences");
245         if (! errors.isEmpty()) {
246             throw new WorkflowServiceErrorException("Preference Validation Error", errors);
247         }
248     }
249 
250     public UserOptionsService getUserOptionService() {
251         return (UserOptionsService) KEWServiceLocator.getService(
252                 KEWServiceLocator.USER_OPTIONS_SRV);
253     }
254 
255     private final class UserOptionsWrapper {
256 
257         private final UserOptions userOptions;
258         private final boolean isSaveRequired;
259 
260         public UserOptionsWrapper(UserOptions userOptions, boolean isSaveRequired) {
261             this.userOptions = userOptions;
262             this.isSaveRequired = isSaveRequired;
263         }
264 
265         public UserOptions getUserOptions() {
266             return userOptions;
267         }
268 
269         public boolean isSaveRequired() {
270             return isSaveRequired;
271         }
272     }
273 }
274 
275