/** * *************************************************************************** * Copyright (c) 2010 Qcadoo Limited * Project: Qcadoo Framework * Version: 1.4 * * This file is part of Qcadoo. * * Qcadoo is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation; either version 3 of the License, * or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************** */ package com.qcadoo.model.internal; import static com.google.common.base.Preconditions.checkNotNull; import java.io.Serializable; import java.util.Comparator; import java.util.List; import org.hibernate.Criteria; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.qcadoo.model.api.Entity; import com.qcadoo.model.api.FieldDefinition; import com.qcadoo.model.internal.api.EntityService; import com.qcadoo.model.internal.api.HibernateService; import com.qcadoo.model.internal.api.InternalDataDefinition; import com.qcadoo.model.internal.api.PriorityService; import com.qcadoo.model.internal.types.PriorityType; @Service public final class PriorityServiceImpl implements PriorityService { @Autowired private HibernateService hibernateService; @Autowired private EntityService entityService; @Override public void prioritizeEntity(final InternalDataDefinition dataDefinition, final Object databaseEntity) { if (!dataDefinition.isPrioritizable()) { return; } FieldDefinition fieldDefinition = dataDefinition.getPriorityField(); int totalNumberOfEntities = getTotalNumberOfEntities(dataDefinition, fieldDefinition, databaseEntity); entityService.setField(databaseEntity, fieldDefinition, totalNumberOfEntities + 1); } @Override public void deprioritizeEntity(final InternalDataDefinition dataDefinition, final Object databaseEntity) { if (!dataDefinition.isPrioritizable()) { return; } FieldDefinition fieldDefinition = dataDefinition.getPriorityField(); int currentPriority = (Integer) entityService.getField(databaseEntity, fieldDefinition); changePriority(dataDefinition, fieldDefinition, databaseEntity, currentPriority + 1, Integer.MAX_VALUE, -1); } private FieldDefinition getScopeForPriority(final FieldDefinition fieldDefinition) { return ((PriorityType) fieldDefinition.getType()).getScopeFieldDefinition(); } @Override public void move(final InternalDataDefinition dataDefinition, final Object databaseEntity, final int position, final int offset) { FieldDefinition fieldDefinition = dataDefinition.getPriorityField(); Integer currentPriorityInteger = (Integer) entityService.getField(databaseEntity, fieldDefinition); int currentPriority = currentPriorityInteger != null ? currentPriorityInteger.intValue() : 0; int targetPriority = getTargetPriority(position, offset, currentPriority); if (currentPriorityInteger == null) { setPriorityIfNotPresent(dataDefinition, fieldDefinition, databaseEntity, targetPriority); } targetPriority = checkIfTargetPriorityIsNotTooLow(targetPriority); targetPriority = getIfTargetPriorityIsNotTooHigh(dataDefinition, databaseEntity, fieldDefinition, targetPriority); if (currentPriority < targetPriority) { changePriority(dataDefinition, fieldDefinition, databaseEntity, currentPriority + 1, targetPriority, -1); } else if (currentPriority > targetPriority) { changePriority(dataDefinition, fieldDefinition, databaseEntity, targetPriority, currentPriority - 1, 1); } else { return; } entityService.setField(databaseEntity, fieldDefinition, targetPriority); hibernateService.getCurrentSession().update(databaseEntity); } private void setPriorityIfNotPresent(final InternalDataDefinition dataDefinition, final FieldDefinition fieldDefinition, final Object databaseEntity, int currentPriority) { Criteria criteria = getCriteria(dataDefinition, fieldDefinition, databaseEntity).add( Restrictions.isNull(fieldDefinition.getName())).add( Restrictions.not(Restrictions.idEq(entityService.getId(databaseEntity)))); List<Object> entitiesToDecrement = criteria.list(); int index = currentPriority + 1; for (Object entity : entitiesToDecrement) { Integer priorityInteger = (Integer) entityService.getField(entity, fieldDefinition); int priority = priorityInteger != null ? priorityInteger.intValue() : index; entityService.setField(entity, fieldDefinition, priority); hibernateService.getCurrentSession().update(entity); index++; } } private int getIfTargetPriorityIsNotTooHigh(final InternalDataDefinition dataDefinition, final Object databaseEntity, final FieldDefinition fieldDefinition, final int targetPriority) { if (targetPriority > 1) { int totalNumberOfEntities = getTotalNumberOfEntities(dataDefinition, fieldDefinition, databaseEntity); if (targetPriority > totalNumberOfEntities) { return totalNumberOfEntities; } } return targetPriority; } private int checkIfTargetPriorityIsNotTooLow(final int targetPriority) { if (targetPriority < 1) { return 1; } return targetPriority; } private int getTargetPriority(final int position, final int offset, final int currentPriority) { if (offset == 0) { return position; } return currentPriority + offset; } @SuppressWarnings("unchecked") private void changePriority(final InternalDataDefinition dataDefinition, final FieldDefinition fieldDefinition, final Object databaseEntity, final int fromPriority, final int toPriority, final int diff) { Criteria criteria = getCriteria(dataDefinition, fieldDefinition, databaseEntity).add( Restrictions.ge(fieldDefinition.getName(), fromPriority)).add( Restrictions.le(fieldDefinition.getName(), toPriority)); List<Object> entitiesToDecrement = criteria.list(); for (Object entity : entitiesToDecrement) { int priority = (Integer) entityService.getField(entity, fieldDefinition); entityService.setField(entity, fieldDefinition, priority + diff); hibernateService.getCurrentSession().update(entity); } } private int getTotalNumberOfEntities(final InternalDataDefinition dataDefinition, final FieldDefinition fieldDefinition, final Object databaseEntity) { Criteria criteria = getCriteria(dataDefinition, fieldDefinition, databaseEntity).setProjection(Projections.rowCount()); return Integer.valueOf(criteria.uniqueResult().toString()); } private Criteria getCriteria(final InternalDataDefinition dataDefinition, final FieldDefinition fieldDefinition, final Object databaseEntity) { Criteria criteria = hibernateService.getCurrentSession().createCriteria(dataDefinition.getClassForEntity()); FieldDefinition scopeFieldDefinition = getScopeForPriority(fieldDefinition); if (scopeFieldDefinition != null) { Object scopeValue = entityService.getField(databaseEntity, scopeFieldDefinition); if (scopeValue instanceof Entity) { criteria.add(Restrictions.eq(scopeFieldDefinition.getName() + ".id", ((Entity) scopeValue).getId())); } else { criteria.add(Restrictions.eq(scopeFieldDefinition.getName(), scopeValue)); } } return criteria; } private static EntityPriorityComparator entityPriorityComparator = new EntityPriorityComparator(); private static class EntityPriorityComparator implements Comparator<Entity>, Serializable { private static final long serialVersionUID = 143898239L; @Override public int compare(final Entity n1, final Entity n2) { return getPriorityValue(n1).compareTo(getPriorityValue(n2)); } private Integer getPriorityValue(final Entity entity) { FieldDefinition priorityFieldDefinition = entity.getDataDefinition().getPriorityField(); checkNotNull(priorityFieldDefinition, "Missing priority field [" + entity.getDataDefinition().toString() + "]."); return (Integer) entity.getField(priorityFieldDefinition.getName()); } } @Override public Comparator<Entity> getEntityPriorityComparator() { return entityPriorityComparator; } }