/* * Data Hub Service (DHuS) - For Space data distribution. * Copyright (C) 2013,2014,2015 GAEL Systems * * This file is part of DHuS software sources. * * 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 fr.gael.dhus.service; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import fr.gael.dhus.database.dao.CollectionDao; import fr.gael.dhus.database.dao.ProductDao; import fr.gael.dhus.database.dao.UserDao; import fr.gael.dhus.database.object.Collection; import fr.gael.dhus.database.object.Product; import fr.gael.dhus.database.object.Role; import fr.gael.dhus.database.object.User; import fr.gael.dhus.service.exception.CollectionNameExistingException; import fr.gael.dhus.service.exception.RequiredFieldMissingException; import fr.gael.dhus.system.config.ConfigurationManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import org.hibernate.Hibernate; import org.hibernate.criterion.DetachedCriteria; import org.hibernate.criterion.Restrictions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; /** * Collection Service provides connected clients with a set of method to * interact with it. */ @Service public class CollectionService extends WebService { private static final Logger LOGGER = LogManager.getLogger(CollectionService.class); @Autowired private CollectionDao collectionDao; @Autowired private ProductDao productDao; @Autowired private UserDao userDao; @Autowired private SecurityService securityService; @Autowired private SearchService searchService; @Autowired private ConfigurationManager cfgManager; @PreAuthorize ("hasRole('ROLE_DATA_MANAGER')") @Transactional (readOnly=false, propagation=Propagation.REQUIRED) public Collection createCollection(Collection collection) throws RequiredFieldMissingException, CollectionNameExistingException { // Can user securityService.getCurrentUser() because // there is a required role. User user = securityService.getCurrentUser(); checkRequiredFields(collection); checkName(collection); return collectionDao.create (collection, user); } @PreAuthorize ("hasRole('ROLE_DATA_MANAGER')") @Transactional (readOnly=false, propagation=Propagation.REQUIRED) public void updateCollection(Collection collection) throws RequiredFieldMissingException { checkRequiredFields(collection); Collection c = collectionDao.read (collection.getUUID ()); String old_name = c.getName(); String new_name = collection.getName(); c.setName(new_name); c.setDescription (collection.getDescription ()); if (!new_name.equals(old_name)) { Iterator<Collection> collectionIterator = collectionDao.getAllCollections (); while (collectionIterator.hasNext ()) { c = collectionIterator.next (); for (Product product : c.getProducts ()) { searchService.index (product); } } } } @PreAuthorize ("hasRole('ROLE_DATA_MANAGER')") @Transactional (readOnly=false, propagation=Propagation.REQUIRED) public void deleteCollection(String uuid) { Collection collection = collectionDao.read (uuid); LOGGER.info("Removing collection " + collection.getName ()); for (Product product : collection.getProducts ()) { searchService.index (product); } collectionDao.delete (collection); } @PreAuthorize ("hasAnyRole('ROLE_DATA_MANAGER','ROLE_SEARCH')") @Transactional (readOnly=true, propagation=Propagation.REQUIRED) public Collection getCollection (String uuid) { return systemGetCollection (uuid); } @Transactional (readOnly=true, propagation=Propagation.REQUIRED) public List<Collection> getCollections (Product product) { return collectionDao.getCollectionsOfProduct(product.getId()); } @PreAuthorize ("hasRole('ROLE_DATA_MANAGER')") @Transactional (readOnly=false, propagation=Propagation.REQUIRED) public void removeProducts (String uuid, Long[] pids) { collectionDao.removeProducts (uuid, pids, null); long start = new Date ().getTime (); for (Long pid: pids) { searchService.index(productDao.read(pid)); } long end = new Date ().getTime (); LOGGER.info("[SOLR] Remove " + pids.length + " product(s) from collection spent " + (end-start) + "ms" ); } @PreAuthorize ("hasRole('ROLE_DATA_MANAGER')") @Transactional (readOnly=false, propagation=Propagation.REQUIRED) public void addProducts (String uuid, Long[] pids) { for (int i = 0; i < pids.length; i++) { systemAddProduct (uuid, pids[i], true); } } @Transactional (readOnly=false, propagation=Propagation.REQUIRED) public void systemAddProduct (String uuid, Long pid, boolean followRights) { Collection collection = collectionDao.read (uuid); Product product = productDao.read (pid); this.addProductInCollection(collection, product); searchService.index(product); } private void addProductInCollection (Collection collection, Product product) { Hibernate.initialize(collection.getProducts()); if (!collection.getProducts().contains(product)) { collection.getProducts().add(product); collectionDao.update (collection); } } @PreAuthorize ("hasAnyRole('ROLE_DATA_MANAGER','ROLE_SEARCH')") @Transactional (readOnly=true, propagation=Propagation.REQUIRED) public List<Long> getProductIds(String uuid) { User user = securityService.getCurrentUser(); return collectionDao.getProductIds (uuid, user); } @PreAuthorize ("hasAnyRole('ROLE_DATA_MANAGER','ROLE_SEARCH')") @Transactional (readOnly=true, propagation=Propagation.REQUIRED) public Integer count () { // Can use securityService.getCurrentUser() because // there is a required // role. User user = securityService.getCurrentUser (); return collectionDao.count (user); } @Transactional (readOnly=true, propagation=Propagation.REQUIRED) private void checkName (Collection collection) throws RequiredFieldMissingException, CollectionNameExistingException { final String toCheck = collection.getName (); if (toCheck == null) { throw new RequiredFieldMissingException ( "At least one required field is empty."); } Iterator<Collection> it = collectionDao.getAllCollections (); while (it.hasNext ()) { final String name = it.next ().getName (); if (toCheck.equals (name)) { throw new CollectionNameExistingException ("Collection name '" + collection.getName () + "' is already used."); } } } private void checkRequiredFields(Collection collection) throws RequiredFieldMissingException { if (collection.getName () == null || collection.getName ().trim () .isEmpty ()) { throw new RequiredFieldMissingException ( "At least one required field is empty."); } } @Transactional (readOnly=true, propagation=Propagation.REQUIRED) public Product getProduct (String uuid, String collection_uuid, User u) { Product p = productDao.getProductByUuid(uuid); if (collectionDao.contains(collection_uuid, p.getId())) return p; return null; } @Transactional (readOnly=true, propagation=Propagation.REQUIRED) public List<Product> getAuthorizedProducts (String uuid, User u) { Collection collection = collectionDao.read (uuid); if (collection == null) { return Collections.emptyList (); } List<Product> products = new LinkedList<> (); Iterator<Long> it = getProductIds (collection.getUUID ()).iterator (); while (it.hasNext ()) { Long pid = it.next (); if (pid != null) { Product p = productDao.read (pid); if (p != null) { products.add (p); } } } return products; } @Transactional (readOnly=true, propagation=Propagation.REQUIRED) public String getCollectionUUIDByName(String collection_name) { return collectionDao.getCollectionUUIDByName(collection_name); } @Transactional (readOnly=true, propagation=Propagation.REQUIRED) public boolean hasAccessToCollection (String cid, String uid) { User user = userDao.read (uid); if (user == null) return false; if (user.getRoles ().contains (Role.DATA_MANAGER)) return true; return collectionDao.hasAccessToCollection (cid, uid); } @Transactional (readOnly=true, propagation=Propagation.REQUIRED) public boolean containsProduct (String uuid, Long pid) { if (uuid == null) return false; return collectionDao.contains (uuid, pid); } @Transactional (readOnly=true) public List<Collection> getCollectionsOfProduct(Product p) { return collectionDao.getCollectionsOfProduct(p.getId()); } /** * Retrieves collections higher authorized collection of the given user in * function of the given criteria. * * @param criteria criteria contains filter and order of required collection. * @param user * @param skip number of skipped valid results. * @param top max of valid results. * @return a list of {@link Collection} */ @Transactional(readOnly = true) public List<Collection> getHigherCollections (DetachedCriteria criteria, User user, int skip, int top) { if (criteria == null) { criteria = DetachedCriteria.forClass (Collection.class); } List<String> cids = new ArrayList<> (); if (cfgManager.isDataPublic () || user.getRoles ().contains (Role.DATA_MANAGER)) { Iterator<Collection> it = collectionDao.getAllCollections (); while (it.hasNext ()) { cids.add (it.next ().getUUID ()); } } else { List<String> collections = collectionDao.getAuthorizedCollections (user.getUUID ()); Iterator<String> it = collections.iterator (); while (it.hasNext ()) { cids.add (it.next ()); } } if (!cids.isEmpty()) { criteria.add(Restrictions.in("uuid", cids)); } return collectionDao.listCriteria (criteria, skip, top); } @Transactional(readOnly = true) public int countHigherCollections (DetachedCriteria detached, User user) { return getHigherCollections (detached, user, 0, 0).size (); } /** * Counts of authorized collections for the given user. * @param user the user to filter collections. * @return number of collections than can see the user. */ @Transactional(readOnly = true) public int countAuthorizedCollections (User user) { if (user == null) { throw new IllegalArgumentException ("User must not be null !"); } if (cfgManager.isDataPublic () || user.getRoles ().contains (Role.DATA_MANAGER)) { return productDao.count (); } return 0; } /** * Retrieves all authorized collections for the given user. * * @param u the given user. * @return a set of authorized collections. */ @Transactional(readOnly = true) public Set<Collection> getAuthorizedCollection (User u) { HashSet<Collection> collections = new HashSet<> (); for (String cid : collectionDao.getAuthorizedCollections (u.getUUID ())) { Collection collection = collectionDao.read (cid); if (collection != null) { collections.add (collection); } } return collections; } /** * Retrieves a collection by its name. * <p>Checks also if the given user is authorized to access it.</p> * * @param name collection name. * @param u the current user. * @return the named collection or null. */ @Transactional(readOnly = true) public Collection getAuthorizedCollectionByName (String name, User u) { if (name != null && u != null) { Collection collection = collectionDao.read ( getCollectionUUIDByName (name)); if (collection != null && (cfgManager.isDataPublic () || collection.getAuthorizedUsers ().contains (u))) { return collection; } } return null; } /** * Retrieves all products contained in a collection. * @return a set of products. */ @Transactional(readOnly = true) public Set<Product> getAllProductInCollection () { Set<Product> products = new HashSet<> (); Iterator<Collection> it = collectionDao.getAllCollections (); while (it.hasNext ()) { products.addAll (it.next ().getProducts ()); } return products; } public Collection systemGetCollection (String id) { return collectionDao.read (id); } }