///////////////////////////////////////////////////////////////////////////// // // Project ProjectForge Community Edition // www.projectforge.org // // Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de) // // ProjectForge is dual-licensed. // // This community edition is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation; version 3 of the License. // // This community edition is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General // Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, see http://www.gnu.org/licenses/. // ///////////////////////////////////////////////////////////////////////////// package org.projectforge.plugins.skillmatrix; import java.util.Collection; import java.util.LinkedList; import java.util.List; import org.apache.commons.collections.CollectionUtils; import org.projectforge.core.BaseDao; import org.projectforge.core.UserException; import org.projectforge.task.TaskDao; import org.projectforge.user.GroupDO; import org.projectforge.user.PFUserDO; import org.projectforge.user.UserRightId; import org.projectforge.web.user.GroupsProvider; /** * DAO for SkillDO. Handles constraint validation and database access. * @author Billy Duong (b.duong@micromata.de) * */ public class SkillDao extends BaseDao<SkillDO> { public static final String UNIQUE_PLUGIN_ID = "PLUGIN_SKILL_MATRIX_SKILL"; public static final String I18N_KEY_SKILL_PREFIX = "plugins.skillmatrix.skill"; public static final UserRightId USER_RIGHT_ID = new UserRightId(UNIQUE_PLUGIN_ID, "plugin20", I18N_KEY_SKILL_PREFIX); public static final String I18N_KEY_ERROR_CYCLIC_REFERENCE = "plugins.skillmatrix.error.cyclicReference"; public static final String I18N_KEY_ERROR_DUPLICATE_CHILD_SKILL = "plugins.skillmatrix.error.duplicateChildSkill"; public static final String I18N_KEY_ERROR_PARENT_SKILL_NOT_FOUND = "plugins.skillmatrix.error.parentNotFound"; private static final String[] ADDITIONAL_SEARCH_FIELDS = new String[] { "parent.title"}; private final SkillTree skillTree; // private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(SkillDao.class); public SkillDao() { super(SkillDO.class); userRightId = USER_RIGHT_ID; skillTree = new SkillTree().setSkillDao(this); } @Override public SkillDO newInstance() { return new SkillDO(); } /** * @see org.projectforge.core.BaseDao#onSaveOrModify(org.projectforge.core.ExtendedBaseDO) */ @Override protected void onSaveOrModify(final SkillDO obj) { synchronized (this) { checkConstraintViolation(obj); } if(obj.getParent() == null && skillTree.isRootNode(obj) == false) { obj.setParent(skillTree.getRootSkillNode().getSkill()); } } /** * Sets the tree as expired to force a refresh (rebuild of tree). * @see org.projectforge.core.BaseDao#afterSaveOrModify(org.projectforge.core.ExtendedBaseDO) */ @Override protected void afterSaveOrModify(final SkillDO obj) { getSkillTree().setExpired(); } public SkillTree getSkillTree() { return skillTree; } /** * * @param skill that needs to be validated. * @throws UserException is thrown when the user wants to create a duplicate. */ @SuppressWarnings("unchecked") public void checkConstraintViolation(final SkillDO skill) throws UserException { // TODO: Check for valid Tree structure (root) -> example TaskDao.checkConstraintVilation List<SkillDO> list; final StringBuilder sb = new StringBuilder(); sb.append("from SkillDO s where s.title=? and deleted=false and s.parent.id"); final List<Object> params = new LinkedList<Object>(); params.add(skill.getTitle()); if (skill.getParentId() != null) { sb.append("=?"); params.add(skill.getParentId()); } else { sb.append(" is null "); } if (skill.getId() != null) { sb.append(" and s.id != ?"); params.add(skill.getId()); } list = getHibernateTemplate().find(sb.toString(), params.toArray()); if (CollectionUtils.isNotEmpty(list) == true) { throw new UserException(I18N_KEY_ERROR_DUPLICATE_CHILD_SKILL); } } private void checkCyclicReference(final SkillDO obj) { if (obj.getId().equals(obj.getParentId()) == true) { // Self reference throw new UserException(I18N_KEY_ERROR_CYCLIC_REFERENCE); } final SkillNode parent = skillTree.getSkillNodeById(obj.getParentId()); if (parent == null && skillTree.isRootNode(obj) == false) { // Task is orphan because it has no parent task. throw new UserException(I18N_KEY_ERROR_PARENT_SKILL_NOT_FOUND); } final SkillNode node = skillTree.getSkillNodeById(obj.getId()); if (node.isParentOf(parent) == true) { // Cyclic reference because task is ancestor of itself. throw new UserException(TaskDao.I18N_KEY_ERROR_CYCLIC_REFERENCE); } } /** * @see org.projectforge.core.BaseDao#hasUpdateAccess(org.projectforge.user.PFUserDO, org.projectforge.core.ExtendedBaseDO, org.projectforge.core.ExtendedBaseDO, boolean) */ @Override public boolean hasUpdateAccess(final PFUserDO user, final SkillDO obj, final SkillDO dbObj, final boolean throwException) { checkCyclicReference(obj); return super.hasUpdateAccess(user, obj, dbObj, throwException); } /** * @see org.projectforge.core.BaseDao#getAdditionalSearchFields() */ @Override protected String[] getAdditionalSearchFields() { return ADDITIONAL_SEARCH_FIELDS; } /** * @param skill * @param parentId If null, then skill will be set to null; * @see BaseDao#getOrLoad(Integer) */ public SkillDO setParentSkill(final SkillDO skill, final Integer parentId) { final SkillDO parentSkill = getOrLoad(parentId); skill.setParent(parentSkill); return skill; } /** * Please note: Only the string group.fullAccessGroupIds will be modified (but not be saved)! * @param skill * @param fullAccessGroups */ public void setFullAccessGroups(final SkillDO skill, final Collection<GroupDO> fullAccessGroups) { skill.setFullAccessGroupIds(new GroupsProvider().getGroupIds(fullAccessGroups)); } public Collection<GroupDO> getSortedFullAccessGroups(final SkillDO skill) { return new GroupsProvider().getSortedGroups(skill.getFullAccessGroupIds()); } /** * Please note: Only the string group.readonlyAccessGroupIds will be modified (but not be saved)! * @param skill * @param readonlyAccessGroups */ public void setReadonlyAccessGroups(final SkillDO skill, final Collection<GroupDO> readonlyAccessGroups) { skill.setReadOnlyAccessGroupIds(new GroupsProvider().getGroupIds(readonlyAccessGroups)); } public Collection<GroupDO> getSortedReadonlyAccessGroups(final SkillDO skill) { return new GroupsProvider().getSortedGroups(skill.getReadOnlyAccessGroupIds()); } /** * Please note: Only the string group.trainingAccessGroupIds will be modified (but not be saved)! * @param skill * @param trainingAccessGroups */ public void setTrainingAccessGroups(final SkillDO skill, final Collection<GroupDO> trainingAccessGroups) { skill.setTrainingAccessGroupIds(new GroupsProvider().getGroupIds(trainingAccessGroups)); } public Collection<GroupDO> getSortedTrainingAccessGroups(final SkillDO skill) { return new GroupsProvider().getSortedGroups(skill.getTrainingAccessGroupIds()); } @SuppressWarnings("unchecked") public SkillDO getSkill(final String title) { if (title == null) { return null; } final List<SkillDO> list = getHibernateTemplate().find("from SkillDO u where u.title = ?", title); if (CollectionUtils.isEmpty(list) == true) { return null; } return list.get(0); } }