package pl.net.bluesoft.rnd.processtool.dao.impl; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.functors.UniquePredicate; import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.criterion.Order; import org.hibernate.criterion.Restrictions; import pl.net.bluesoft.rnd.processtool.dao.ProcessDictionaryDAO; import pl.net.bluesoft.rnd.processtool.dict.GlobalDictionaryProvider; import pl.net.bluesoft.rnd.processtool.dict.ProcessDictionaryProvider; import pl.net.bluesoft.rnd.processtool.hibernate.SimpleHibernateBean; import pl.net.bluesoft.rnd.processtool.model.config.ProcessDefinitionConfig; import pl.net.bluesoft.rnd.processtool.model.dict.db.*; import pl.net.bluesoft.util.cache.Caches; import pl.net.bluesoft.util.lang.ExpiringCache; import java.lang.reflect.InvocationTargetException; import java.util.*; import java.util.Map.Entry; import java.util.logging.Logger; public class ProcessDictionaryDAOImpl extends SimpleHibernateBean<ProcessDBDictionary> implements ProcessDictionaryDAO, ProcessDictionaryProvider<ProcessDBDictionary>, GlobalDictionaryProvider<ProcessDBDictionary> { public ProcessDictionaryDAOImpl(Session session) { super(session); } private static final Logger logger = Logger.getLogger(ProcessDictionaryDAOImpl.class.getName()); private static final ExpiringCache<DictionaryCacheKey, ProcessDBDictionary> cache = new ExpiringCache<DictionaryCacheKey, ProcessDBDictionary>(60 * 60 * 1000); private static class DictionaryCacheKey { private String definitionId; private String dictionaryId; private String languageCode; private Boolean defaultDictionary; public DictionaryCacheKey(ProcessDefinitionConfig definition, String dictionaryId, String languageCode) { this(definition, dictionaryId, languageCode, null); } public DictionaryCacheKey(ProcessDefinitionConfig definition, String dictionaryId, String languageCode, Boolean defaultDictionary) { this(getCacheDefinitionId(definition), dictionaryId, languageCode, defaultDictionary); } public DictionaryCacheKey(String definitionId, String dictionaryId, String languageCode) { this(definitionId, dictionaryId, languageCode, null); } public DictionaryCacheKey(String definitionId, String dictionaryId, String languageCode, Boolean defaultDictionary) { this.definitionId = definitionId; this.dictionaryId = dictionaryId; this.languageCode = languageCode; this.defaultDictionary = defaultDictionary; } @Override public String toString() { if (defaultDictionary != null && defaultDictionary) { return Caches.cachedObjectId(definitionId, dictionaryId, getCacheDefaultToken(defaultDictionary)); } return Caches.cachedObjectId(definitionId, dictionaryId, languageCode); } @Override public boolean equals(Object obj) { if (obj instanceof DictionaryCacheKey) { return toString().equals(obj.toString()); } return false; } @Override public int hashCode() { return toString().hashCode(); } } private static String getCacheDefaultToken(Boolean flag) { return "default=" + flag; } private static String getCacheDefinitionId(ProcessDefinitionConfig config) { return "" + (config != null ? config.getId() : "global"); } private void updateCache(Collection<ProcessDBDictionary> dictionaries) { for (ProcessDBDictionary dict : dictionaries) { updateCache(dict); } } private void updateCache(ProcessDBDictionary dict) { String definitionId = getCacheDefinitionId(dict.getProcessDefinition()); String dictionaryId = dict.getDictionaryId(); String languageCode = dict.getLanguageCode(); DictionaryCacheKey key = new DictionaryCacheKey(definitionId, dictionaryId, languageCode); cache.put(key, dict); // logger.info("Cached dictionary: " + objectId); if (dict.isDefaultDictionary() != null && dict.isDefaultDictionary()) { key = new DictionaryCacheKey(definitionId, dictionaryId, getCacheDefaultToken(dict.isDefaultDictionary())); cache.put(key, dict); // logger.info("Cached dictionary: " + objectId); } } @Override public ProcessDBDictionary fetchProcessDictionary(final ProcessDefinitionConfig definition, final String dictionaryId, final String languageCode) { DictionaryCacheKey key = new DictionaryCacheKey(definition, dictionaryId, languageCode); return cache.get(key, new ExpiringCache.NewValueCallback<DictionaryCacheKey, ProcessDBDictionary>() { @Override public ProcessDBDictionary getNewValue(DictionaryCacheKey key) { Criteria criteria = getSession().createCriteria(ProcessDBDictionary.class) .add(Restrictions.eq("dictionaryId", dictionaryId)) .add(Restrictions.eq("languageCode", languageCode)) .add(definition == null ? Restrictions.isNull("processDefinition") : Restrictions.eq("processDefinition", definition)); return (ProcessDBDictionary) criteria.uniqueResult(); } }); } @Override public ProcessDBDictionary fetchDefaultProcessDictionary(final ProcessDefinitionConfig definition, final String dictionaryId) { DictionaryCacheKey key = new DictionaryCacheKey(definition, dictionaryId, null, true); return cache.get(key, new ExpiringCache.NewValueCallback<DictionaryCacheKey, ProcessDBDictionary>() { @Override public ProcessDBDictionary getNewValue(DictionaryCacheKey key) { Criteria criteria = getSession().createCriteria(ProcessDBDictionary.class) .add(Restrictions.eq("dictionaryId", dictionaryId)) .add(Restrictions.eq("defaultDictionary", Boolean.TRUE)) .add(definition == null ? Restrictions.isNull("processDefinition") : Restrictions.eq("processDefinition", definition)); return (ProcessDBDictionary)criteria.uniqueResult(); } }); } @Override public List<ProcessDBDictionary> fetchProcessDictionaries(ProcessDefinitionConfig definition) { Criteria criteria = getSession().createCriteria(ProcessDBDictionary.class) .add(definition == null ? Restrictions.isNull("processDefinition") : Restrictions.eq("processDefinition", definition)) .addOrder(Order.desc("dictionaryName")); List<ProcessDBDictionary> dictionaries = criteria.list(); updateCache(dictionaries); return dictionaries; } @Override public List<ProcessDBDictionary> fetchAllProcessDictionaries() { List<ProcessDBDictionary> dictionaries = getSession().createCriteria(ProcessDBDictionary.class) .add(Restrictions.isNotNull("processDefinition")) .addOrder(Order.desc("dictionaryName")) .list(); updateCache(dictionaries); return dictionaries; } @Override public List<ProcessDBDictionary> fetchAllActiveProcessDictionaries() { List<ProcessDBDictionary> dictionaries = getSession().createCriteria(ProcessDBDictionary.class) .addOrder(Order.desc("dictionaryName")) .createCriteria("processDefinition") .add(Restrictions.eq("latest", Boolean.TRUE)) .list(); updateCache(dictionaries); return dictionaries; } @Override public List<ProcessDBDictionary> fetchAllGlobalDictionaries() { return fetchProcessDictionaries(null); } @Override public ProcessDBDictionary fetchDefaultGlobalDictionary(String dictionaryId) { return fetchDefaultProcessDictionary(null, dictionaryId); } @Override public ProcessDBDictionary fetchGlobalDictionary(String dictionaryId, String languageCode) { return fetchProcessDictionary(null, dictionaryId, languageCode); } @Override public void createOrUpdateDictionary(ProcessDefinitionConfig definition, ProcessDBDictionary dictionary, boolean overwrite) { createOrUpdateDictionaries(definition, Collections.singletonList(dictionary), overwrite); } public ProcessDBDictionary findDictionaryById(Long dictionaryId) { Criteria criteria = getSession().createCriteria(ProcessDBDictionary.class) .add(Restrictions.eq("id", dictionaryId)); return (ProcessDBDictionary)criteria.uniqueResult(); } public void createOrUpdateDictionaryItem(ProcessDBDictionary dictionary, String dictionaryItemKey, String dictionaryItemValue) { Session session = getSession(); ProcessDBDictionaryItem dictionaryItem = null; if(dictionary.getId() == null) { Criteria criteria = session.createCriteria(ProcessDBDictionaryItem.class) .add(Restrictions.eq("key", dictionaryItemKey)) .add(Restrictions.eq("dictionary", dictionary)); dictionaryItem = (ProcessDBDictionaryItem)criteria.uniqueResult(); } else { dictionaryItem = dictionary.getItems().get(dictionaryItemKey); } if(dictionaryItem == null) { dictionaryItem = new ProcessDBDictionaryItem(); dictionaryItem.setDictionary(dictionary); dictionaryItem.setKey(dictionaryItemKey); ProcessDBDictionaryItemValue itemValue = new ProcessDBDictionaryItemValue(); itemValue.setItem(dictionaryItem); itemValue.setValue(dictionaryItemValue); itemValue.setStringValue(dictionaryItemValue); itemValue.setValidStartDate(new Date()); dictionaryItem.getValues().add(itemValue); dictionary.addItem(dictionaryItem); session.saveOrUpdate(dictionary); } else { ProcessDBDictionaryItemValue currentValue = dictionaryItem.getValueForCurrentDate(); currentValue.setValue(dictionaryItemValue); dictionaryItem.getValues().remove(currentValue); ProcessDBDictionaryItemValue itemValue = new ProcessDBDictionaryItemValue(); itemValue.setItem(dictionaryItem); itemValue.setValue(dictionaryItemValue); itemValue.setStringValue(dictionaryItemValue); itemValue.setValidStartDate(new Date()); dictionaryItem.getValues().add(itemValue); session.saveOrUpdate(dictionary); } updateCache(dictionary); } @Override public void createOrUpdateDictionaries(ProcessDefinitionConfig definition, List<ProcessDBDictionary> newDictionaries, boolean overwrite) { List<ProcessDBDictionary> existingDBDictionaries = definition != null ? fetchProcessDictionaries(definition) : fetchAllGlobalDictionaries(); Session session = getSession(); for (ProcessDBDictionary newDict : newDictionaries) { ProcessDBDictionary existingDictionary = null; for (ProcessDBDictionary existingDict : existingDBDictionaries) if (existingDict.getDictionaryId().equals(newDict.getDictionaryId()) && existingDict.getLanguageCode().equals(newDict.getLanguageCode())) { existingDictionary = existingDict; break; } boolean updated = false; if(existingDictionary != null) { if (overwrite) { session.delete(existingDictionary); } else { existingDictionary.getPermissions().clear(); for(ProcessDBDictionaryPermission permission: newDict.getPermissions()) { permission.setDictionary(existingDictionary); existingDictionary.getPermissions().add(permission); } existingDictionary.setDefaultDictionary(newDict.isDefaultDictionary()); existingDictionary.setDescription(newDict.getDescription()); for (ProcessDBDictionaryItem newItem : newDict.getItems().values()) { if (!existingDictionary.getItems().containsKey(newItem.getKey())) { existingDictionary.addItem(newItem); } } session.saveOrUpdate(existingDictionary); updateCache(existingDictionary); updated = true; } } if (!updated) { newDict.setProcessDefinition(definition); session.saveOrUpdate(newDict); updateCache(newDict); } } } @Override public void updateDictionary(ProcessDBDictionary dictionary) { Session session = getSession(); session.update(dictionary); session.flush(); updateCache(dictionary); } // @Override // public void copyDictionaries(ProcessDefinitionConfig oldDefinitionConfig, // ProcessDefinitionConfig newDefinitionConfig) { // // TODO Auto-generated method stub // // } @Override public void copyDictionaries(ProcessDefinitionConfig oldDefinitionConfig, ProcessDefinitionConfig newDefinitionConfig) { List<ProcessDBDictionary> existingDBDictionaries = fetchProcessDictionaries(newDefinitionConfig); if (existingDBDictionaries != null && existingDBDictionaries.size() > 0) return; //słowniki już są List<ProcessDBDictionary> oldDBDictionariesList = fetchProcessDictionaries(oldDefinitionConfig); Collection<ProcessDBDictionary> oldDBDictionaries = CollectionUtils.select(oldDBDictionariesList, new UniquePredicate()); //newDefinitionConfig.getBpmDefinitionKey() // PropertyFilter vetoer = new PropertyFilter() { // public boolean propagate(String propertyName, Method readerMethod) { // return readerMethod.getReturnType() != ProcessDefinitionConfig.class; // } // }; // Hibernate3BeanReplicator replicator = new Hibernate3BeanReplicator(null, null, vetoer); // // for (ProcessDBDictionary existingDict : existingDBDictionaries) { // ProcessDBDictionary newDict = replicator.deepCopy(existingDict); // newDict.setProcessDefinition(newDefinitionConfig); // session.save(newDict); // } for (ProcessDBDictionary oldDict : oldDBDictionaries) { try { ProcessDBDictionary newDict = new ProcessDBDictionary(); PropertyUtils.copyProperties(newDict, oldDict); newDict.setId(null); newDict.setProcessDefinition(newDefinitionConfig); Map<String, ProcessDBDictionaryItem> items = oldDict.getItems(); newDict.setItems(new HashMap<String, ProcessDBDictionaryItem>()); for (Entry<String, ProcessDBDictionaryItem> item : items.entrySet()) { ProcessDBDictionaryItem newItem = new ProcessDBDictionaryItem(); PropertyUtils.copyProperties(newItem, item.getValue()); newItem.setId(null); newItem.setDictionary(newDict); newDict.getItems().put(item.getKey(), newItem); Set<ProcessDBDictionaryItemValue> values = item.getValue().getValues(); newItem.setValues(new HashSet<ProcessDBDictionaryItemValue>()); for (ProcessDBDictionaryItemValue value : values) { ProcessDBDictionaryItemValue newValue = new ProcessDBDictionaryItemValue(); PropertyUtils.copyProperties(newValue, value); newValue.setId(null); newValue.setItem(newItem); newItem.getValues().add(newValue); Map<String, ProcessDBDictionaryItemExtension> extensions = value.getExtensions(); newValue.setExtensions(new HashMap<String, ProcessDBDictionaryItemExtension>()); for (Entry<String, ProcessDBDictionaryItemExtension> extension : extensions.entrySet()) { ProcessDBDictionaryItemExtension newExtension = new ProcessDBDictionaryItemExtension(); PropertyUtils.copyProperties(newExtension, extension.getValue()); newExtension.setId(null); newExtension.setItemValue(newValue); newValue.getExtensions().put(extension.getKey(), newExtension); } } } Set<ProcessDBDictionaryPermission> permissions = oldDict.getPermissions(); newDict.setPermissions(new HashSet<ProcessDBDictionaryPermission>()); for (ProcessDBDictionaryPermission permission : permissions) { ProcessDBDictionaryPermission newPermission = new ProcessDBDictionaryPermission(); PropertyUtils.copyProperties(newPermission, permission); newPermission.setId(null); newPermission.setDictionary(newDict); newDict.getPermissions().add(newPermission); } session.save(newDict); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }