View Javadoc

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