/* * This file is part of LibrePlan * * Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e * Desenvolvemento Tecnolóxico de Galicia * Copyright (C) 2010-2011 Igalia, S.L. * * This program 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, see <http://www.gnu.org/licenses/>. */ package org.libreplan.business.resources.daos; import static org.hibernate.criterion.Restrictions.eq; import static org.hibernate.criterion.Restrictions.ilike; import static org.hibernate.criterion.Restrictions.in; import static org.hibernate.criterion.Restrictions.like; import static org.hibernate.criterion.Restrictions.or; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.Validate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.libreplan.business.common.IAdHocTransactionService; import org.libreplan.business.common.IOnTransaction; import org.libreplan.business.resources.entities.Criterion; import org.libreplan.business.resources.entities.CriterionType; import org.libreplan.business.resources.entities.Machine; import org.libreplan.business.resources.entities.Resource; import org.libreplan.business.resources.entities.ResourceEnum; import org.libreplan.business.resources.entities.ResourceType; import org.libreplan.business.resources.entities.Worker; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; @Service @Scope(BeanDefinition.SCOPE_SINGLETON) /** * @author Diego Pino Garcia <dpino@igalia.com> */ public class ResourcesSearcher implements IResourcesSearcher { private static final Log LOG = LogFactory.getLog(ResourcesSearcher.class); @Autowired private IAdHocTransactionService adHocTransactionService; @Autowired private SessionFactory sessionFactory; @Override public IResourcesQuery<Machine> searchMachines() { return new Query<>(Machine.class); } @Override public IResourcesQuery<Worker> searchWorkers() { return new Query<>(Worker.class); } class Query<T extends Resource> implements IResourcesQuery<T> { private final Class<T> klass; private String name = null; private List<Criterion> criteria = null; private ResourceType type = ResourceType.NON_LIMITING_RESOURCE; public Query(Class<T> klass) { this.klass = klass; } @Override public IResourcesQuery<T> byName(String name) { this.name = name; return this; } @Override public IResourcesQuery<T> byCriteria(Collection<? extends Criterion> criteria) { Validate.noNullElements(criteria); this.criteria = new ArrayList<>(criteria); return this; } @Override public IResourcesQuery<T> byResourceType(ResourceType type) { this.type = type; return this; } @Override public List<T> execute() { return adHocTransactionService.runOnReadOnlyTransaction(() -> { Session session = sessionFactory.getCurrentSession(); List<T> resources = buildCriteria(session).list(); return restrictToSatisfyAllCriteria(resources); }); } private Criteria buildCriteria(Session session) { Criteria result = session.createCriteria(klass); result.add(eq("resourceType", type)); addQueryByName(result); addFindRelatedWithSomeOfTheCriterions(result); result.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); return result; } private void addFindRelatedWithSomeOfTheCriterions(Criteria criteria) { if ( !criteriaSpecified() ) { return; } criteria.createCriteria("criterionSatisfactions") .add(in("criterion", Criterion.withAllDescendants(this.criteria))); } private boolean criteriaSpecified() { return this.criteria != null && !this.criteria.isEmpty(); } private void addQueryByName(Criteria criteria) { if ( name == null ) { return; } final String nameWithWildcards = "%" + name + "%"; if ( klass.equals(Worker.class) ) { criteria.add(or(or( ilike("firstName", nameWithWildcards), ilike("surname", nameWithWildcards)), like("nif", nameWithWildcards))); } else if ( klass.equals(Machine.class) ) { criteria.add(or(ilike("name", nameWithWildcards), ilike("code", nameWithWildcards))); } else { LOG.warn("can't handle " + klass); } } private List<T> restrictToSatisfyAllCriteria(List<T> resources) { if ( !criteriaSpecified() ) { return resources; } List<T> result = new ArrayList<>(); for (T each : resources) { if ( each.satisfiesCriterionsAtSomePoint(criteria) ) { result.add(each); } } return result; } @Override public Map<CriterionType, Set<Criterion>> getCriteria() { return adHocTransactionService.runOnReadOnlyTransaction(getCriterionsTree(klass)); } } @Override public IResourcesQuery<?> searchBy(ResourceEnum resourceType) { Validate.notNull(resourceType); switch (resourceType) { case MACHINE: return searchMachines(); case WORKER: return searchWorkers(); default: throw new RuntimeException("can't handle " + resourceType); } } @Override public IResourcesQuery<Resource> searchBoth() { final IResourcesQuery<Worker> searchWorkers = searchWorkers(); final IResourcesQuery<Machine> searchMachines = searchMachines(); return new IResourcesQuery<Resource>() { @Override public IResourcesQuery<Resource> byName(String name) { searchWorkers.byName(name); searchMachines.byName(name); return this; } @Override public IResourcesQuery<Resource> byCriteria(Collection<? extends Criterion> criteria) { searchWorkers.byCriteria(criteria); searchMachines.byCriteria(criteria); return this; } @Override public IResourcesQuery<Resource> byResourceType(ResourceType type) { searchWorkers.byResourceType(type); searchMachines.byResourceType(type); return this; } @Override public List<Resource> execute() { List<Resource> result = new ArrayList<>(); List<Worker> workers = searchWorkers.execute(); result.addAll(workers); List<Machine> machines = searchMachines.execute(); result.addAll(machines); return result; } @Override public Map<CriterionType, Set<Criterion>> getCriteria() { return adHocTransactionService.runOnReadOnlyTransaction(getCriterionsTree(Resource.class)); } }; } @Autowired private ICriterionDAO criterionDAO; private IOnTransaction<Map<CriterionType, Set<Criterion>>> getCriterionsTree( final Class<? extends Resource> klassTheCriterionTypeMustBeRelatedWith) { return () -> { Map<CriterionType, Set<Criterion>> result = new LinkedHashMap<>(); for (Criterion criterion : criterionDAO.getAllSortedByTypeAndName()) { CriterionType key = criterion.getType(); if ( klassTheCriterionTypeMustBeRelatedWith.isAssignableFrom(key.getResource().asClass()) ) { if ( !result.containsKey(key) ) { result.put(key, new LinkedHashSet<>()); } result.get(key).add(criterion); } } return result; }; } }