View Javadoc
1   /*
2   /*
3    * This software was designed and created by Jason Carroll.
4    * Copyright (c) 2002, 2003, 2004 Jason Carroll.
5    * The author can be reached at jcarroll@cowsultants.com
6    * ITracker website: http://www.cowsultants.com
7    * ITracker forums: http://www.cowsultants.com/phpBB/index.php
8    *
9    * This program is free software; you can redistribute it and/or modify
10   * it only under the terms of the GNU General Public License as published by
11   * the Free Software Foundation; either version 2 of the License, or
12   * (at your option) any later version.
13   *
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   */
19  
20  package org.itracker.services.implementations;
21  
22  import org.apache.commons.collections.CollectionUtils;
23  import org.apache.commons.collections.Transformer;
24  import org.apache.commons.collections.functors.NotNullPredicate;
25  import org.apache.commons.lang.StringUtils;
26  import org.itracker.core.resources.ITrackerResources;
27  import org.itracker.model.*;
28  import org.itracker.model.util.CustomFieldUtilities;
29  import org.itracker.model.util.IssueUtilities;
30  import org.itracker.model.util.SystemConfigurationUtilities;
31  import org.itracker.persistence.dao.*;
32  import org.itracker.services.ConfigurationService;
33  import org.itracker.util.NamingUtilites;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  import javax.naming.InitialContext;
38  import java.util.*;
39  
40  /**
41   * Implementation of the ConfigurationService Interface.
42   *
43   * @see ConfigurationService
44   */
45  
46  public class ConfigurationServiceImpl implements ConfigurationService {
47  
48      private static final Logger logger = LoggerFactory.getLogger(ConfigurationServiceImpl.class.getName());
49  
50      private final Properties props;
51      private ConfigurationDAO configurationDAO;
52      private CustomFieldDAO customFieldDAO;
53      private CustomFieldValueDAO customFieldValueDAO;
54      private LanguageDAO languageDAO;
55      private ProjectScriptDAO projectScriptDAO;
56      private WorkflowScriptDAO workflowScriptDAO;
57  
58  
59      private static final Long _START_TIME_MILLIS = System.currentTimeMillis();
60      private String jndiPropertiesOverridePrefix;
61      private String mailSessionLookupName;
62  
63      /**
64       * Creates a new instance using the given configuration.
65       *
66       * @param configurationProperties itracker configuration properties
67       *                                (see classpath:configuration.properties)
68       */
69      public ConfigurationServiceImpl(Properties configurationProperties,
70                                      ConfigurationDAO configurationDAO, CustomFieldDAO customFieldDAO,
71                                      CustomFieldValueDAO customFieldValueDAO, LanguageDAO languageDAO,
72                                      ProjectScriptDAO projectScriptDAO, WorkflowScriptDAO workflowScriptDAO) {
73          if (configurationProperties == null) {
74              throw new IllegalArgumentException("null configurationProperties");
75          }
76          this.props = configurationProperties;
77          props.setProperty("start_time_millis", String.valueOf(_START_TIME_MILLIS));
78  
79          // initialize naming context prefix for properties overrides
80          if (StringUtils.isEmpty(jndiPropertiesOverridePrefix)) {
81              jndiPropertiesOverridePrefix = props.getProperty("jndi_override_prefix", "java:comp/env/itracker");
82          }
83          if (StringUtils.isEmpty(mailSessionLookupName)) {
84              mailSessionLookupName = configurationProperties.getProperty("mail_session_jndi_lookup", "java:comp/env/itracker/mail/Session");
85          }
86  
87          this.configurationDAO = configurationDAO;
88          this.customFieldDAO = customFieldDAO;
89          this.customFieldValueDAO = customFieldValueDAO;
90          this.languageDAO = languageDAO;
91  
92          this.projectScriptDAO = projectScriptDAO;
93          this.workflowScriptDAO = workflowScriptDAO;
94      }
95  
96      public String getJndiPropertiesOverridePrefix() {
97          return jndiPropertiesOverridePrefix;
98      }
99  
100     public void setJndiPropertiesOverridePrefix(String jndiPropertiesOverridePrefix) {
101         if (null != jndiPropertiesOverridePrefix) {
102             return;
103         }
104         this.jndiPropertiesOverridePrefix = jndiPropertiesOverridePrefix;
105     }
106 
107     public String getMailSessionLookupName() {
108         return mailSessionLookupName;
109     }
110 
111     public void setMailSessionLookupName(String mailSessionLookupName) {
112         this.mailSessionLookupName = mailSessionLookupName;
113     }
114 
115     public String getProperty(String name) {
116         String value = null;
117         if (null != getJndiPropertiesOverridePrefix()) {
118 
119             if (logger.isDebugEnabled()) {
120 
121                 logger.debug("getProperty: looking up '" + name
122                         + "' from jndi context "
123                         + getJndiPropertiesOverridePrefix());
124 
125 
126             }
127             try {
128                 value = NamingUtilites.getStringValue(new InitialContext(),
129                         getJndiPropertiesOverridePrefix() + "/" + name, null);
130                 if (null == value) {
131                     if (logger.isDebugEnabled()) {
132                         logger.debug("getProperty: value not found in jndi: " + name);
133                     }
134                 }
135             } catch (Exception e) {
136                 logger.debug("getProperty: caught exception looking up value for " + name, e);
137             }
138 
139         }
140 
141         if (null == value) {
142             value = props.getProperty(name, null);
143         }
144         if (logger.isDebugEnabled()) {
145             logger.debug("getProperty: returning " + value + " for name: " + name);
146         }
147         return value;
148     }
149 
150     public String getProperty(String name, String defaultValue) {
151         String val = getProperty(name);
152         return (val == null) ? defaultValue : val;
153     }
154 
155     private String getItrackerVersion() {
156         return props.getProperty("version");
157     }
158 
159 
160     public boolean getBooleanProperty(String name, boolean defaultValue) {
161         String value = getProperty(name);
162 
163         return (value == null ? defaultValue : Boolean.valueOf(value));
164     }
165 
166     public int getIntegerProperty(String name, int defaultValue) {
167         String value = getProperty(name);
168 
169         try {
170             return (value == null) ? defaultValue : Integer.parseInt(value);
171         } catch (NumberFormatException ex) {
172             return defaultValue;
173         }
174 
175     }
176 
177     public long getLongProperty(String name, long defaultValue) {
178         String value = getProperty(name);
179         try {
180             return (value == null) ? defaultValue : Long.parseLong(value);
181         } catch (NumberFormatException ex) {
182             return defaultValue;
183         }
184 
185     }
186 
187     public Configuration getConfigurationItem(Integer id) {
188         Configuration configItem = configurationDAO.findByPrimaryKey(id);
189         return configItem;
190     }
191 
192     @Deprecated
193     public List<Configuration> getConfigurationItemsByType(int type) {
194         return getConfigurationItemsByType(Configuration.Type.valueOf(type));
195     }
196 
197     public List<Configuration> getConfigurationItemsByType(Configuration.Type type) {
198         List<Configuration> configItems = configurationDAO.findByType(type);
199         Collections.sort(configItems, new Configuration.ConfigurationOrderComparator());
200         return configItems;
201     }
202 
203     @Deprecated
204     public List<Configuration> getConfigurationItemsByType(int type, Locale locale) {
205         return getConfigurationItemsByType(Configuration.Type.valueOf(type), locale);
206     }
207 
208     public List<Configuration> getConfigurationItemsByType(Configuration.Type type, Locale locale) {
209         List<Configuration> items = getConfigurationItemsByType(type);
210 
211         for (int i = 0; i < items.size(); i++) {
212             if (items.get(i).getType() == Configuration.Type.status) {
213                 items.get(i).setName(IssueUtilities.getStatusName(items.get(i).getValue(), locale));
214             } else if (items.get(i).getType() == Configuration.Type.severity) {
215                 items.get(i).setName(IssueUtilities.getSeverityName(items.get(i).getValue(), locale));
216             } else if (items.get(i).getType() == Configuration.Type.resolution) {
217                 items.get(i).setName(IssueUtilities.getResolutionName(items.get(i).getValue(), locale));
218             }
219         }
220         return items;
221     }
222 
223     public Configuration createConfigurationItem(Configuration configuration) {
224 
225         Configuration configurationItem = new Configuration();
226 
227         configurationItem.setType(configuration.getType());
228         configurationItem.setOrder(configuration.getOrder());
229         configurationItem.setValue(configuration.getValue());
230         configurationItem.setCreateDate(new Date());
231         configurationItem.setVersion(getItrackerVersion());
232         configurationDAO.saveOrUpdate(configurationItem);
233 
234         return configurationItem;
235 
236     }
237 
238 
239     public Configuration updateConfigurationItem(Configuration configuration) {
240         // find item by primary key
241         Configuration configurationItem = configurationDAO.findByPrimaryKey(configuration.getId());
242 
243         configurationItem.setVersion(getInitializedVersionString());
244 
245         // update now
246         configurationDAO.saveOrUpdate(configurationItem);
247         // get model from saved item
248         return configurationItem;
249     }
250 
251     @Deprecated
252     public List<Configuration> updateConfigurationItems(List<Configuration> configurations, Configuration.Type type) {
253 
254         List<Configuration> configurationItems = new ArrayList<Configuration>();
255         for (Configuration configurationItem : configurations) {
256             if (type == configurationItem.getType()) {
257                 // create a new item
258                 Configuration curConfiguration = configurationDAO.findByPrimaryKey(configurationItem.getId());
259 
260                 curConfiguration.setName(configurationItem.getName());
261                 curConfiguration.setOrder(configurationItem.getOrder());
262                 curConfiguration.setType(configurationItem.getType());
263                 curConfiguration.setValue(configurationItem.getValue());
264                 curConfiguration.setVersion(getInitializedVersionString());
265 
266                 // save or update
267                 this.configurationDAO.saveOrUpdate(curConfiguration);
268                 configurationItems.add(curConfiguration);
269             }
270         }
271         // sort array
272         Collections.sort(configurationItems);
273 
274         return configurationItems;
275     }
276 
277     /**
278      * Finds the <code>Configuration</code> by primary key <code>id<code>
279      * and deletes it.
280      *
281      * @param id The id of the <code>COnfigurationBean</code> to remove
282      */
283     public void removeConfigurationItem(Integer id) {
284 
285         Configuration configBean = this.configurationDAO.findByPrimaryKey(id);
286         if (configBean != null) {
287             this.configurationDAO.delete(configBean);
288         }
289     }
290 
291     /**
292      * Removes all <code>Configuration</code>s of the give <code>type</code>
293      *
294      * @param type the type of <code>Configuration</code> to remove
295      * @deprecated
296      */
297     public void removeConfigurationItems(int type) {
298         removeConfigurationItems(Configuration.Type.valueOf(type));
299     }
300 
301     /**
302      * Removes all <code>Configuration</code>s of the give <code>type</code>
303      *
304      * @param type the type of <code>Configuration</code> to remove
305      */
306     public void removeConfigurationItems(Configuration.Type type) {
307 
308         // find the configuration beans by its type
309         Collection<Configuration> currentItems = configurationDAO.findByType(type);
310 
311         for (Iterator<Configuration> iter = currentItems.iterator(); iter.hasNext(); ) {
312             // get current config bean
313             Configuration config = (Configuration) iter.next();
314             // delete it
315             this.configurationDAO.delete(config);
316         }
317     }
318 
319     public void removeConfigurationItems(Configuration configuration) {
320         Collection<Configuration> currentItems = configurationDAO.findByTypeAndValue(configuration.getType(), configuration.getValue());
321         for (Iterator<Configuration> iter = currentItems.iterator(); iter.hasNext(); ) {
322             Configuration configItem = (Configuration) iter.next();
323             configurationDAO.delete(configItem);
324         }
325     }
326 
327     public boolean configurationItemExists(Configuration configuration) {
328 
329         if (configuration != null && configuration.getVersion() != null) {
330 
331             Collection<Configuration> configItems = configurationDAO.findByTypeAndValue(configuration.getType(), configuration.getValue());
332 
333             if (configItems != null && configItems.size() > 0) {
334 
335                 return true;
336 
337             }
338 
339         }
340 
341         return false;
342 
343     }
344 
345     public String getInitializedVersionString() {
346         List<Configuration> initialized = getConfigurationItemsByType(Configuration.Type.initialized);
347         if (null == initialized || initialized.isEmpty()) {
348             return "0";
349         }
350         Collections.sort(initialized, new Comparator<Configuration>() {
351             public int compare(Configuration configuration, Configuration configuration1) {
352                 return configuration.getVersion().compareTo(configuration1.getVersion());
353             }
354         });
355 
356         return initialized.get(initialized.size() - 1).getVersion();
357     }
358 
359     public boolean isConfigurationItemUpToDate(Configuration configuration) {
360 
361         if (null == configuration) {
362             return false;
363         }
364 
365         if (StringUtils.endsWith(configuration.getVersion(), "-SNAPSHOT")) {
366             return false;
367         }
368 
369         long currentVersion = SystemConfigurationUtilities.getVersionAsLong(getInitializedVersionString());
370 
371         if (configuration != null && configuration.getVersion() != null) {
372 
373             Collection<Configuration> configItems = configurationDAO.findByTypeAndValue(configuration.getType(), configuration.getValue());
374 
375             for (Iterator<Configuration> iter = configItems.iterator(); iter.hasNext(); ) {
376 
377                 Configuration configItem = (Configuration) iter.next();
378 
379                 if (null != configItem) {
380 
381                     currentVersion = Math.max(SystemConfigurationUtilities.getVersionAsLong(configItem.getVersion()),
382                             currentVersion);
383 
384                 }
385 
386             }
387 
388             if (currentVersion >= SystemConfigurationUtilities.getVersionAsLong(configuration.getVersion())) {
389 
390                 return true;
391 
392             }
393 
394         }
395 
396         return false;
397 
398     }
399 
400     public void resetConfigurationCache() {
401 
402         IssueUtilities.setResolutions(getConfigurationItemsByType(Configuration.Type.resolution));
403         IssueUtilities.setSeverities(getConfigurationItemsByType(Configuration.Type.severity));
404         IssueUtilities.setStatuses(getConfigurationItemsByType(Configuration.Type.status));
405         IssueUtilities.setCustomFields(getCustomFields());
406 
407     }
408 
409     public void resetConfigurationCache(Configuration.Type type) {
410         switch (type) {
411             case resolution:
412                 IssueUtilities.setResolutions(getConfigurationItemsByType(type));
413                 break;
414             case severity:
415                 IssueUtilities.setSeverities(getConfigurationItemsByType(Configuration.Type.severity));
416                 break;
417             case status:
418                 IssueUtilities.setStatuses(getConfigurationItemsByType(Configuration.Type.status));
419                 break;
420             case customfield:
421                 IssueUtilities.setCustomFields(getCustomFields());
422                 break;
423             default:
424                 logger.warn("resetConfigurationCache: unsupported type " + type);
425 
426         }
427     }
428 
429     @Deprecated
430     public void resetConfigurationCache(int type) {
431         logger.warn("resetConfigurationCache: called with deprecated API!");
432         resetConfigurationCache(Configuration.Type.valueOf(type));
433 
434     }
435 
436     public ProjectScript getProjectScript(Integer scriptId) {
437         ProjectScript projectScript = this.projectScriptDAO.findByPrimaryKey(scriptId);
438         return projectScript;
439 
440     }
441 
442     public List<ProjectScript> getProjectScripts() {
443         List<ProjectScript> projectScripts = this.projectScriptDAO.findAll();
444         return projectScripts;
445     }
446 
447 
448     public ProjectScript createProjectScript(ProjectScript projectScript) {
449 
450         // create project script and populate data
451         ProjectScript editprojectScript = new ProjectScript();
452         editprojectScript.setFieldId(projectScript.getFieldId());
453         editprojectScript.setFieldType(projectScript.getFieldType());
454         editprojectScript.setPriority(projectScript.getPriority());
455         editprojectScript.setProject(projectScript.getProject());
456         editprojectScript.setScript(projectScript.getScript());
457 
458         // save entity
459         this.projectScriptDAO.save(editprojectScript);
460 
461         return editprojectScript;
462     }
463 
464     public ProjectScript updateProjectScript(ProjectScript projectScript) {
465         ProjectScript editprojectScript;
466 
467         editprojectScript = projectScriptDAO.findByPrimaryKey(projectScript.getId());
468         editprojectScript.setFieldId(projectScript.getFieldId());
469         editprojectScript.setFieldType(projectScript.getFieldType());
470         editprojectScript.setPriority(projectScript.getPriority());
471         editprojectScript.setProject(projectScript.getProject());
472         editprojectScript.setScript(projectScript.getScript());
473         this.projectScriptDAO.saveOrUpdate(editprojectScript);
474         return editprojectScript;
475     }
476 
477     /**
478      * remove a project script by its id
479      *
480      * @param projectScript_id the id of the project script to remove
481      */
482     public void removeProjectScript(Integer projectScript_id) {
483         if (projectScript_id != null) {
484             ProjectScript projectScript = this.projectScriptDAO.findByPrimaryKey(projectScript_id);
485             if (projectScript != null) {
486                 this.projectScriptDAO.delete(projectScript);
487             }
488         }
489     }
490 
491     public WorkflowScript getWorkflowScript(Integer id) {
492 
493         WorkflowScript workflowScript = workflowScriptDAO.findByPrimaryKey(id);
494 
495         return workflowScript;
496 
497     }
498 
499     public List<WorkflowScript> getWorkflowScripts() {
500         List<WorkflowScript> workflowScripts = workflowScriptDAO.findAll();
501         return workflowScripts;
502     }
503 
504     /**
505      * Creates a workflow script.
506      *
507      * @param workflowScript The <code>WorkflowScript</code> carring the data
508      * @return The <code>WorkflowScript</code> after inserting
509      */
510     public WorkflowScript createWorkflowScript(WorkflowScript workflowScript) {
511 
512         // create workflow script and populate data
513         WorkflowScript editworkflowScript = new WorkflowScript();
514         editworkflowScript.setName(workflowScript.getName());
515         editworkflowScript.setScript(workflowScript.getScript());
516         editworkflowScript.setEvent(workflowScript.getEvent());
517         editworkflowScript.setLanguage(workflowScript.getLanguage());
518         // save entity
519         workflowScriptDAO.save(editworkflowScript);
520 
521         return editworkflowScript;
522     }
523 
524     public WorkflowScript updateWorkflowScript(WorkflowScript workflowScript) {
525         WorkflowScript editworkflowScript;
526 
527         editworkflowScript = workflowScriptDAO.findByPrimaryKey(workflowScript.getId());
528         editworkflowScript.setName(workflowScript.getName());
529         editworkflowScript.setScript(workflowScript.getScript());
530         editworkflowScript.setEvent(workflowScript.getEvent());
531         editworkflowScript.setLanguage(workflowScript.getLanguage());
532         workflowScriptDAO.saveOrUpdate(editworkflowScript);
533         return editworkflowScript;
534     }
535 
536     /**
537      * remove a workflow script by its id
538      *
539      * @param workflowScript_id the id of the workflow script to remove
540      */
541     public void removeWorkflowScript(Integer workflowScript_id) {
542         if (workflowScript_id != null) {
543             WorkflowScript workflowScript = this.workflowScriptDAO.findByPrimaryKey(workflowScript_id);
544             if (workflowScript != null) {
545                 this.workflowScriptDAO.delete(workflowScript);
546             }
547         }
548     }
549 
550     public CustomField getCustomField(Integer id) {
551 
552         CustomField customField = customFieldDAO.findByPrimaryKey(id);
553 
554         return customField;
555 
556     }
557 
558     @Deprecated
559     public List<CustomField> getCustomFields() {
560         return getCustomFieldsSorted(null);
561     }
562 
563     public List<CustomField> getCustomFieldsSorted(Locale locale) {
564         List<CustomField> customFields = customFieldDAO.findAll();
565         Collections.sort(customFields, new CustomFieldUtilities.CustomFieldByNameComparator((null == locale)
566                 ? ITrackerResources.getLocale(ITrackerResources.getDefaultLocale())
567                 : locale));
568         return customFields;
569     }
570 
571     /**
572      * Creates a custom field
573      *
574      * @param customField The <code>CustomField</code> carrying the data
575      * @return the <code>CustomField</code> after saving
576      */
577     public CustomField createCustomField(CustomField customField) {
578         CustomField addcustomField = new CustomField();
579         addcustomField.setDateFormat(customField.getDateFormat());
580         addcustomField.setFieldType(customField.getFieldType());
581         addcustomField.setOptions(customField.getOptions());
582         addcustomField.setRequired(customField.isRequired());
583         this.customFieldDAO.save(addcustomField);
584 
585         return addcustomField;
586     }
587 
588     public CustomField updateCustomField(CustomField customField) {
589         CustomField editcustomField = customFieldDAO.findByPrimaryKey(customField.getId());
590 
591         editcustomField.setDateFormat(customField.getDateFormat());
592         editcustomField.setFieldType(customField.getFieldType());
593         editcustomField.setOptions(customField.getOptions());
594         editcustomField.setRequired(customField.isRequired());
595         this.customFieldDAO.saveOrUpdate(editcustomField);
596 
597         return editcustomField;
598     }
599 
600     /**
601      * searches for a custom field by primary key and removes it
602      *
603      * @param customFieldId the primary key
604      */
605     public boolean removeCustomField(Integer customFieldId) {
606         boolean status = true;
607         boolean del_Status = true;
608         CustomField customField = customFieldDAO.findByPrimaryKey(customFieldId);
609 
610         if (customField != null) {
611             try {
612                 if (customField.getFieldType() == CustomField.Type.LIST)
613                     status = this.removeCustomFieldValues(customFieldId);
614                 String key = CustomFieldUtilities.getCustomFieldLabelKey(customField.getId());
615                 this.customFieldDAO.delete(customField);
616                 if (key != null)
617                     status = this.removeLanguageKey(key);
618             } catch (Exception ex) {
619                 del_Status = false;
620             }
621         }
622         if (!del_Status)
623             status = del_Status;
624 
625         return status;
626     }
627 
628 
629     /**
630      * Gets a <code>CustomFieldValue</code> by primary key
631      *
632      * @param id the primary key
633      * @return The <code>CustomFieldValue</code> found or <code>null</code>
634      */
635     public CustomFieldValue getCustomFieldValue(Integer id) {
636 
637         CustomFieldValue cfvBean = (CustomFieldValue)
638                 this.customFieldValueDAO.findByPrimaryKey(id);
639 
640         return cfvBean;
641     }
642 
643     public CustomFieldValue createCustomFieldValue(CustomFieldValue customFieldValue) {
644         CustomFieldValue addcustomFieldValue = new CustomFieldValue();
645         addcustomFieldValue.setCustomField(customFieldValue.getCustomField());
646         addcustomFieldValue.setValue(customFieldValue.getValue());
647         this.customFieldValueDAO.save(addcustomFieldValue);
648 
649         return addcustomFieldValue;
650     }
651 
652 
653     /**
654      * Updates a <code>CustomFieldValue</code>.
655      *
656      * @param customFieldValue The model to update
657      * @return The <code>CustomFieldValue</code> after saving
658      */
659     public CustomFieldValue updateCustomFieldValue(CustomFieldValue customFieldValue) {
660         CustomFieldValue editcustomFieldValue = this.customFieldValueDAO.findByPrimaryKey(customFieldValue.getId());
661         editcustomFieldValue.setCustomField(customFieldValue.getCustomField());
662         editcustomFieldValue.setValue(customFieldValue.getValue());
663         this.customFieldValueDAO.saveOrUpdate(editcustomFieldValue);
664 
665         return editcustomFieldValue;
666     }
667 
668     public List<CustomFieldValue> updateCustomFieldValues(Integer customFieldId, List<CustomFieldValue> customFieldValues) {
669         List<CustomFieldValue> customFieldValueItems = new ArrayList<CustomFieldValue>();
670 
671         if (customFieldId != null) {
672             try {
673                 CustomField customField = customFieldDAO.findByPrimaryKey(customFieldId);
674                 if (customFieldValues != null && !customFieldValues.isEmpty()) {
675                     for (Iterator<CustomFieldValue> iterator = customFieldValues.iterator(); iterator.hasNext(); ) {
676 
677                         // create a new item
678                         CustomFieldValue customFieldValueItem = (CustomFieldValue) iterator.next();
679                         CustomFieldValue curCustomFieldValue = customFieldValueDAO.findByPrimaryKey(customFieldValueItem.getId());
680 
681                         curCustomFieldValue.setCreateDate(customFieldValueItem.getCreateDate());
682                         curCustomFieldValue.setValue(customFieldValueItem.getValue());
683                         curCustomFieldValue.setCustomField(customFieldValueItem.getCustomField());
684                         curCustomFieldValue.setSortOrder(customFieldValueItem.getSortOrder());
685 
686                         // save or update
687                         this.customFieldValueDAO.saveOrUpdate(curCustomFieldValue);
688                         customFieldValueItems.add(curCustomFieldValue);
689 
690                     }
691                     customField.setOptions(customFieldValueItems);
692                     return customFieldValueItems;
693 
694                 }
695             } catch (Exception fe) {
696             }
697         }
698 
699         return customFieldValues;
700     }
701 
702     /**
703      * removes a custom field value by primary key
704      *
705      * @param customFieldValueId the id of the custoem field
706      */
707     public boolean removeCustomFieldValue(Integer customFieldValueId) {
708         boolean status = true;
709         boolean del_Status = true;
710 
711         // find custom field value by id
712         CustomFieldValue customFieldValue = this.customFieldValueDAO.findByPrimaryKey(customFieldValueId);
713 
714         // delete it
715         try {
716             this.customFieldValueDAO.delete(customFieldValue);
717         } catch (Exception ex) {
718             del_Status = false;
719         }
720         if (!del_Status)
721             status = del_Status;
722 
723         return status;
724     }
725 
726     /**
727      * Removes all field values of a given custom field
728      *
729      * @param customFieldId The id of the customField
730      */
731     public boolean removeCustomFieldValues(Integer customFieldId) {
732         boolean status = true;
733         boolean lp_Status = true;
734         CustomField customField = this.customFieldDAO.findByPrimaryKey(customFieldId);
735         // get values of the field
736         List<CustomFieldValue> customFieldValues = customField.getOptions();
737         for (Iterator<CustomFieldValue> iter = customFieldValues.iterator(); iter.hasNext(); ) {
738             // get current
739             CustomFieldValue customFieldValue = (CustomFieldValue) iter.next();
740             String key = CustomFieldUtilities.getCustomFieldOptionLabelKey(customFieldId, customFieldValue.getId());
741             // remove from collection
742             iter.remove();
743             // delete from datasource
744             try {
745                 this.customFieldValueDAO.delete(customFieldValue);
746 
747                 if (key != null)
748                     status = this.removeLanguageKey(key);
749             } catch (Exception ex) {
750                 lp_Status = false;
751             }
752         }
753         if (!lp_Status)
754             status = lp_Status;
755 
756         return status;
757     }
758 
759     @Override
760     public String getLanguageValue(String key, Locale locale) {
761         return getLanguageItemByKey(key, locale).getResourceValue();
762     }
763 
764     @Override
765     public String getLanguageEntry(String key, Locale locale) {
766         try {
767             Language l = getLanguageItemByKey(key, locale);
768             return l.getResourceValue();
769         } catch (NoSuchEntityException e) {
770             logger.debug("failed to get entry", e);
771         }
772         throw new MissingResourceException("Entry doesn't exist.", Language.class.getName(), key);
773     }
774 
775     @Override
776     public Language getLanguageItemByKey(String key, Locale locale) {
777         String localeString = ITrackerResources.BASE_LOCALE;
778         if (null != locale
779                 && !locale.equals(ITrackerResources.getLocale(ITrackerResources.BASE_LOCALE))) {
780             localeString = locale.toString();
781         }
782         Language languageItem = languageDAO.findByKeyAndLocale(key, localeString);
783         // TODO: obsolete code:
784 //        try {
785 //            languageItem = languageDAO.findByKeyAndLocale(key, ITrackerResources.BASE_LOCALE);
786 //        } catch (RuntimeException e) {
787 //            logger.debug("could not find {} with BASE", key);
788 //            languageItem = null;
789 //        }
790 //
791 //        if (null == locale) {
792 //            logger.debug("locale was null, returning BASE: {}", languageItem);
793 //            return languageItem;
794 //        }
795 //        try {
796 //            languageItem = languageDAO.findByKeyAndLocale(key, locale.getLanguage());
797 //        } catch (RuntimeException re) {
798 //            logger.debug("could not find {} with language {}", key, locale.getLanguage());
799 //        }
800 //        if (StringUtils.isNotEmpty(locale.getCountry())) {
801 //            try {
802 //                languageItem = languageDAO.findByKeyAndLocale(key, locale.toString());
803 //            } catch (RuntimeException ex) {
804 //                logger.debug("could not find {} with locale {}", key, locale);
805 //            }
806 //        }
807 
808         return languageItem;
809 
810     }
811 
812     public List<Language> getLanguageItemsByKey(String key) {
813             List<Language> languageItems = languageDAO.findByKey(key);
814 
815         return languageItems;
816     }
817 
818     public Language updateLanguageItem(Language language) {
819         Language languageItem;
820 
821         try {
822             languageItem = languageDAO.findByKeyAndLocale(language.getResourceKey(), language.getLocale());
823             languageItem.setLocale(language.getLocale());
824             languageItem.setResourceKey(language.getResourceKey());
825             languageItem.setResourceValue(language.getResourceValue());
826         } catch (NoSuchEntityException fe) {
827             logger.debug("NoSuchEntityException: Language, now populating Language");
828             languageItem = new Language();
829             languageItem.setLocale(language.getLocale());
830             languageItem.setResourceKey(language.getResourceKey());
831             languageItem.setResourceValue(language.getResourceValue());
832         }
833         logger.debug("Start saveOrUpdate Language");
834         languageDAO.saveOrUpdate(languageItem);
835         logger.debug("Saved Language");
836         return languageItem;
837     }
838 
839     /**
840      * Removes all <code>Language</code>s with the give key
841      *
842      * @param key The key to be removed
843      */
844     public boolean removeLanguageKey(String key) {
845         boolean status = true;
846         boolean lp_Status = true;
847 
848         // find all <code>Language</code>s for the given key
849         List<Language> languageItems = languageDAO.findByKey(key);
850 
851         for (Iterator<Language> iter = languageItems.iterator(); iter.hasNext(); ) {
852             // delete current item
853             Language language = (Language) iter.next();
854             try {
855                 this.languageDAO.delete(language);
856             } catch (Exception ex) {
857                 lp_Status = false;
858             }
859         }
860         if (!lp_Status)
861             status = lp_Status;
862 
863         return status;
864     }
865 
866     /**
867      * Removes the <code>Language</code> passed as parameter
868      *
869      * @param language The <code>Language</code> to remove
870      */
871     public void removeLanguageItem(Language language) {
872 
873         Language languageItem = languageDAO.findByKeyAndLocale(language.getResourceKey(), language.getLocale());
874 
875         if (languageItem != null) {
876             // delete item
877             this.languageDAO.delete(languageItem);
878         }
879     }
880 
881     public String[] getSortedKeys() {
882 
883         int i = 0;
884         Collection<Language> items = languageDAO.findByLocale(ITrackerResources.BASE_LOCALE);
885         String[] sortedKeys = new String[items.size()];
886 
887         for (Iterator<Language> iter = items.iterator(); iter.hasNext(); i++) {
888             Language item = (Language) iter.next();
889             sortedKeys[i] = item.getResourceKey();
890         }
891 
892         // Now sort the list of keys in a logical manner
893 
894         Arrays.sort(sortedKeys);
895         return sortedKeys;
896 
897     }
898 
899     public HashMap<String, String> getDefinedKeys(String locale) {
900 
901         HashMap<String, String> keys = new HashMap<String, String>();
902 
903         if (locale == null || locale.equals("")) {
904             locale = ITrackerResources.BASE_LOCALE;
905         }
906 
907 
908         Collection<Language> items = languageDAO.findByLocale(locale);
909         for (Iterator<Language> iter = items.iterator(); iter.hasNext(); ) {
910             Language item = iter.next();
911             keys.put(item.getResourceKey(), item.getResourceValue());
912         }
913 
914 
915         return keys;
916 
917     }
918 
919     public List<NameValuePair> getDefinedKeysAsArray(String locale) {
920         NameValuePair[] keys = null;
921         if (locale == null || locale.equals("")) {
922             locale = ITrackerResources.BASE_LOCALE;
923         }
924 
925         int i = 0;
926         Collection<Language> items = languageDAO.findByLocale(locale);
927         keys = new NameValuePair[items.size()];
928 
929         for (Iterator<Language> iter = items.iterator(); iter.hasNext(); i++) {
930             Language item = (Language) iter.next();
931             keys[i] = new NameValuePair(item.getResourceKey(), item.getResourceValue());
932         }
933 
934         Arrays.sort(keys);
935         return Arrays.asList(keys);
936 
937     }
938 
939     public int getNumberDefinedKeys(String locale) {
940 
941         return getDefinedKeys(locale).size();
942 
943     }
944 
945     private List<Language> getLanguage(Locale locale) {
946         Map<String, String> language = new HashMap<String, String>();
947         if (locale == null) {
948             locale = new Locale("");
949         }
950         String localeString = (locale.toString().equals("") ? ITrackerResources.BASE_LOCALE : locale.toString());
951 
952         Collection<Language> items = languageDAO.findByLocale(localeString);
953         for (Language item : items) {
954             language.put(item.getResourceKey(), item.getResourceValue());
955         }
956 
957         Language[] languageArray = new Language[language.size()];
958         int i = 0;
959 
960         for (String key : language.keySet()) {
961             languageArray[i] = new Language(localeString, key, language.get(key));
962             i++;
963         }
964         return Arrays.asList(languageArray);
965     }
966 
967     public Properties getLanguageProperties(Locale locale) {
968         Properties properties = new Properties();
969         List<Language> lang = getLanguage(locale);
970         for (Language l : lang) {
971             properties.put(l.getResourceKey(), l.getResourceValue());
972         }
973         return properties;
974     }
975 
976     public Map<String, List<String>> getAvailableLanguages() {
977 
978         final TreeMap<String, List<String>> languages = new TreeMap<>();
979         final List<Configuration> locales = getConfigurationItemsByType(Configuration.Type.locale);
980 
981         for (int i = 0; i < locales.size(); i++) {
982             String baselocalestring = locales.get(i).getValue();
983             if (baselocalestring.length() == 2) {
984                 List<String> languageList = new ArrayList<>();
985                 final String l = baselocalestring;
986 
987                 languageList.addAll(
988                         CollectionUtils.collect(locales, new Transformer() {
989                             @Override
990                             public Object transform(Object input) {
991                                 String val = ((Configuration) input).getValue();
992                                 if (val.length() > 2 &&
993                                         val.startsWith(l + "_")) {
994                                     return val;
995                                 }
996                                 return null;
997                             }
998                         }));
999                 CollectionUtils.filter(languageList, NotNullPredicate.getInstance());
1000                 languages.put(baselocalestring, languageList);
1001             }
1002         }
1003 
1004 
1005         return languages;
1006 
1007     }
1008 
1009     @SuppressWarnings("unchecked")
1010     public int getNumberAvailableLanguages() {
1011 
1012         int numLanguages = 0;
1013         Map<String, List<String>> availableLanguages = getAvailableLanguages();
1014 
1015         for (Iterator iter = availableLanguages.keySet().iterator(); iter.hasNext(); ) {
1016             List<List> languages = new ArrayList<>();
1017             List list = availableLanguages.get(iter.next());
1018             languages.add(list);
1019 
1020             if (languages != null && languages.size() > 0) {
1021                 numLanguages += languages.size();
1022             } else {
1023                 numLanguages += 1;
1024             }
1025 
1026         }
1027 
1028         return numLanguages;
1029 
1030     }
1031 
1032     public void updateLanguage(Locale locale, List<Language> items) {
1033 
1034         if (locale != null && items != null) {
1035             Configuration configItem = new Configuration(Configuration.Type.locale, locale
1036                     .toString(), getItrackerVersion());
1037             updateLanguage(locale, items, configItem);
1038 
1039         }
1040 
1041     }
1042 
1043     public void updateLanguage(Locale locale, List<Language> items, Configuration configItem) {
1044         for (int i = 0; i < items.size(); i++) {
1045 
1046             if (items.get(i) != null) {
1047                 updateLanguageItem(items.get(i));
1048             }
1049         }
1050         removeConfigurationItems(configItem);
1051         createConfigurationItem(configItem);
1052     }
1053 
1054     public SystemConfiguration getSystemConfiguration(Locale locale) {
1055 
1056         SystemConfiguration config = new SystemConfiguration();
1057 
1058         // Load the basic system configuration
1059 
1060         List<Configuration> resolutions = getConfigurationItemsByType(Configuration.Type.resolution);
1061 
1062         for (int i = 0; i < resolutions.size(); i++) {
1063 
1064             resolutions.get(i).setName(ITrackerResources.getString(SystemConfigurationUtilities
1065                     .getLanguageKey(resolutions.get(i)), locale));
1066 
1067         }
1068 
1069         config.setResolutions(resolutions);
1070 
1071         List<Configuration> severities = getConfigurationItemsByType(Configuration.Type.severity);
1072 
1073         for (int i = 0; i < severities.size(); i++) {
1074 
1075             severities.get(i).setName(ITrackerResources.getString(SystemConfigurationUtilities
1076                     .getLanguageKey(severities.get(i)), locale));
1077 
1078         }
1079 
1080         config.setSeverities(severities);
1081 
1082         List<Configuration> statuses = getConfigurationItemsByType(Configuration.Type.status);
1083 
1084         for (int i = 0; i < statuses.size(); i++) {
1085 
1086             statuses.get(i).setName(ITrackerResources.getString(SystemConfigurationUtilities.getLanguageKey(statuses.get(i)),
1087                     locale));
1088 
1089         }
1090 
1091         config.setStatuses(statuses);
1092 
1093         List<CustomField> customFields = getCustomFields();
1094 
1095         config.setCustomFields(customFields);
1096 
1097 
1098         // Now set the system version
1099 
1100         config.setVersion(getItrackerVersion());
1101 
1102         return config;
1103 
1104     }
1105 
1106 
1107     public boolean initializeLocale(String locale, boolean forceReload) {
1108         boolean result = false;
1109 
1110         Configuration localeConfig = new Configuration(Configuration.Type.locale, locale,
1111                 getItrackerVersion());
1112 
1113         if (!isConfigurationItemUpToDate(localeConfig) || forceReload) {
1114 
1115             logger.debug("Loading database with locale " + locale);
1116 
1117             removeConfigurationItems(localeConfig);
1118 //                
1119             createConfigurationItem(localeConfig);
1120 //                
1121             ITrackerResources.clearBundle(ITrackerResources.getLocale(locale));
1122 
1123             result = true;
1124 
1125 
1126         }
1127 
1128         return result;
1129 
1130     }
1131 
1132     public void initializeConfiguration() {
1133 
1134         // TODO when current version is outdated?
1135         long current = SystemConfigurationUtilities.getVersionAsLong(getItrackerVersion());
1136 
1137         long initialized = SystemConfigurationUtilities.getVersionAsLong(getInitializedVersionString());
1138 
1139         if (0 == initialized) {
1140 
1141             logger.info("System does not appear to be initialized, initializing system configuration.");
1142 
1143             ResourceBundle baseLanguage = ITrackerResources.getBundle(ITrackerResources.getLocale(ITrackerResources.BASE_LOCALE));
1144             getLanguage(ITrackerResources.getLocale(ITrackerResources.BASE_LOCALE));
1145 
1146             if (baseLanguage == null) {
1147 
1148                 throw new IllegalStateException(
1149                         "Languages must be initialized before the system configuration can be loaded.");
1150 
1151             }
1152 
1153             // Remove any previous configuration information, possibly left
1154             // over from previous failed initialization
1155 
1156             logger.debug("Removing previous incomplete initialization information.");
1157 
1158             removeConfigurationItems(Configuration.Type.status);
1159 
1160             removeConfigurationItems(Configuration.Type.severity);
1161 
1162             removeConfigurationItems(Configuration.Type.resolution);
1163 
1164             Set<String> keys = baseLanguage.keySet();
1165             for (final String key : keys) {
1166                 if (key.startsWith(ITrackerResources.KEY_BASE_RESOLUTION)) {
1167 
1168                     try {
1169 
1170                         String resolutionString = key.substring(20);
1171                         if (logger.isDebugEnabled()) {
1172                             logger.debug("Adding new configuration resolution value: " + resolutionString);
1173                         }
1174                         int resolutionNumber = Integer.parseInt(resolutionString);
1175 
1176                         createConfigurationItem(new Configuration(
1177                                 Configuration.Type.resolution, resolutionString, getItrackerVersion(),
1178                                 resolutionNumber));
1179 
1180                     } catch (RuntimeException e) {
1181 
1182                         logger.error("Unable to load resolution value: " + key, e);
1183                         throw e;
1184 
1185                     }
1186 
1187                 }
1188 
1189                 if (key.startsWith(ITrackerResources.KEY_BASE_SEVERITY)) {
1190 
1191                     try {
1192 
1193                         String severityString = key.substring(18);
1194 
1195                         logger.debug("Adding new configuration severity value: " + severityString);
1196 
1197                         int severityNumber = Integer.parseInt(severityString);
1198 
1199                         createConfigurationItem(new Configuration(Configuration.Type.severity,
1200                                 severityString, getItrackerVersion(), severityNumber));
1201 
1202                     } catch (RuntimeException e) {
1203 
1204                         logger.error("Unable to load severity value: " + key, e);
1205                         throw e;
1206                     }
1207 
1208                 }
1209 
1210                 if (key.startsWith(ITrackerResources.KEY_BASE_STATUS)) {
1211 
1212                     try {
1213 
1214                         String statusString = key.substring(16);
1215 
1216                         logger.debug("Adding new configuration status value: " + statusString);
1217 
1218                         int statusNumber = Integer.parseInt(statusString);
1219 
1220                         createConfigurationItem(new Configuration(Configuration.Type.status,
1221                                 statusString, getItrackerVersion(), statusNumber));
1222                     } catch (RuntimeException e) {
1223                         logger.error("Unable to load status value: " + key, e);
1224                         throw e;
1225                     }
1226                 }
1227             }
1228 
1229 
1230             createConfigurationItem(new Configuration(Configuration.Type.initialized, "1",
1231                     getItrackerVersion()));
1232         }
1233 
1234 
1235     }
1236 
1237     public LanguageDAO getLanguageDAO() {
1238         return languageDAO;
1239     }
1240 
1241     public ConfigurationDAO getConfigurationDAO() {
1242         return configurationDAO;
1243     }
1244 
1245     public CustomFieldDAO getCustomFieldDAO() {
1246         return customFieldDAO;
1247     }
1248 
1249     public CustomFieldValueDAO getCustomFieldValueDAO() {
1250         return customFieldValueDAO;
1251     }
1252 
1253     public WorkflowScriptDAO getWorkflowScriptDAO() {
1254         return workflowScriptDAO;
1255     }
1256 
1257     public String getSystemBaseURL() {
1258         return getProperty(PNAME_SYSTEM_BASE_URL);
1259     }
1260 
1261 
1262     /**
1263      * This method will attempt to load all of the locales defined in the
1264      * ITracker.properties file, and add them to the database if they don't
1265      * already exist.
1266      *
1267      * @param forceReload if true, it will reload the languages from the property files
1268      *                    even if they are listed as being up to date
1269      */
1270     public void initializeAllLanguages(boolean forceReload) {
1271         Set<String> definedLocales = new LinkedHashSet<>();
1272 
1273         initializeLocale(ITrackerResources.BASE_LOCALE,
1274                 forceReload);
1275 
1276         String definedLocalesString;
1277         try {
1278             definedLocalesString =
1279                     getProperty("available_locales", ITrackerResources.getDefaultLocale());
1280         } catch (RuntimeException e) {
1281             definedLocalesString = ITrackerResources.getString(ITrackerResources.getDefaultLocale());
1282         }
1283         if (definedLocalesString != null) {
1284             StringTokenizer token = new StringTokenizer(definedLocalesString, ",");
1285             while (token.hasMoreTokens()) {
1286                 String locale = StringUtils.trim(token.nextToken());
1287                 if (locale.length() == 5 && locale.indexOf('_') == 2) {
1288                     definedLocales.add(locale.substring(0, 2));
1289                 }
1290                 definedLocales.add(locale);
1291             }
1292         }
1293 
1294 //        // apply configuration locales
1295 //        for (Configuration c: getConfigurationItemsByType(Configuration.Type.locale)) {
1296 //            if (!definedLocales.contains(c.getValue())) {
1297 //                logger.info("removing language configuration from database: {}, not in: {}", c, definedLocales);
1298 //                removeConfigurationItems(c);
1299 //            }
1300 //        }
1301         for (String locale : definedLocales) {
1302             initializeLocale(locale, forceReload);
1303         }
1304     }
1305 }