fr.gael.dhus.database.dao.ProductDao.java Source code

Java tutorial

Introduction

Here is the source code for fr.gael.dhus.database.dao.ProductDao.java

Source

/*
 * 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.database.dao;

import java.math.BigInteger;
import java.net.URL;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.stereotype.Repository;

import com.google.common.collect.ImmutableList;

import fr.gael.dhus.database.dao.interfaces.DaoUtils;
import fr.gael.dhus.database.dao.interfaces.HibernateDao;
import fr.gael.dhus.database.object.Collection;
import fr.gael.dhus.database.object.MetadataIndex;
import fr.gael.dhus.database.object.Product;
import fr.gael.dhus.database.object.User;

/**
 * Product Data Access Object provides interface to Product Table into the
 * database.
 */
@Repository
public class ProductDao extends HibernateDao<Product, Long> {
    private static Log logger = LogFactory.getLog(ProductDao.class);

    @Autowired
    private CollectionDao collectionDao;

    @Autowired
    private ProductCartDao productCartDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private EvictionDao evictionDao;

    private final static Integer MAX_PRODUCT_PAGE_SIZE = Integer.getInteger("max.product.page.size", 100);

    /**
     * Checks if the passed number as a number of product is acceptable 
     * according to the current configuration
     * @param n the number of product to retrieve.
     * @throws UnsupportedOperationException if the passed number cannot be 
     *    handled.
     */
    static void checkProductNumber(int n) {
        if (n > MAX_PRODUCT_PAGE_SIZE) {
            throw new UnsupportedOperationException(
                    "Product page size exceeds the authorized size (" + MAX_PRODUCT_PAGE_SIZE + ").");
        }
    }

    /**
     * Returns the maximum number of product that a page of request can handled.
     * @return the max number of products.
     */
    public static int getMaxPageSize() {
        return MAX_PRODUCT_PAGE_SIZE;
    }

    public Product getProductByPath(final URL path) {
        if (path == null)
            return null;

        Product p = (Product) DataAccessUtils
                .uniqueResult(getHibernateTemplate().find("from Product where path=? AND processed=true", path));

        return p;
    }

    /**
     * Retrieve a list of products to their ids. returned list is not controlled
     * with user rights nor processing completion.
     * @param ids the list of ids to retrieve
     * @return the list of products
     */
    @SuppressWarnings("unchecked")
    public List<Product> read(List<Long> ids) {
        if ((ids == null) || ids.isEmpty())
            return ImmutableList.of();
        String facet = "";
        String logic_op = "";
        for (Long id : ids) {
            facet += " " + logic_op + " p.id=" + id;
            logic_op = "or";
        }

        return (List<Product>) find("from " + entityClass.getName() + " p WHERE " + facet);
    }

    /**
     * Does the product corresponding to the given url exist in the database ?
     * Processed or not.
     */
    public boolean exists(URL url) {
        if (url == null)
            return false;

        Product p = (Product) DataAccessUtils
                .uniqueResult(getHibernateTemplate().find("from Product where path=?", url));

        return p != null;
    }

    /**
     * Override Hibernate scroll to add the page size limitation.
     * @see {@link HibernateDao#scroll(String, int, int)}
     */
    @Override
    public List<Product> scroll(String clauses, int skip, int n) {
        checkProductNumber(n);
        if (n < 0)
            n = ProductDao.getMaxPageSize();

        return super.scroll(clauses, skip, n);
    }

    public Iterator<Product> scrollFiltered(String filter, final Long parent_id, int skip) {
        StringBuilder sb = new StringBuilder();
        if (parent_id != null) {
            // filters products of a collection
            sb.append("SELECT p ");
            sb.append("FROM Collection c LEFT OUTER JOIN c.products p ");
            sb.append("WHERE c.id=").append(parent_id).append(" AND ").append("p.identifier LIKE '%")
                    .append(filter.toUpperCase()).append("%' AND p.processed=true");
        } else {
            // filters all products
            sb.append("FROM ").append(entityClass.getName()).append(" ");
            sb.append("WHERE identifier LIKE '%").append(filter).append("%' ");
            sb.append("AND processed=true");
        }
        return new PagedIterator<>(this, sb.toString(), skip);
    }

    public int count(String filter, final Long parent_id, User user) {
        if (parent_id != null) {
            return DataAccessUtils.intResult(find("select count(*) "
                    + "from Collection c left outer join c.products p " + "where c.id=" + parent_id
                    + " and upper(p.identifier) LIKE " + "upper('%" + filter + "%') and p.processed = true"));
        }
        return DataAccessUtils.intResult(find("select count(*) FROM Product p "
                + "WHERE upper(p.identifier) LIKE upper('%" + filter + "%')  AND " + "p.processed=true "));
    }

    @Override
    public void deleteAll() {
        Iterator<Product> it = getAllProducts();
        while (it.hasNext()) {
            it.next();
            it.remove();
        }
    }

    @Override
    public void delete(Product product) {
        Product p = read(product.getId());
        List<Collection> cls = collectionDao.getCollectionsOfProduct(p.getId());
        // Remove collection references
        // Must use rootUser to remove every reference of this product
        // (or maybe a new non usable user ?)
        User user = userDao.getRootUser();
        if (cls != null) {
            for (Collection c : cls) {
                logger.info("deconnect product from collection " + c.getName());
                collectionDao.removeProduct(c.getId(), p.getId(), user);
            }
        }

        // Remove cart references
        productCartDao.deleteProductReferences(p);

        p.setAuthorizedUsers(new HashSet<User>());
        p.getDownload().getChecksums().clear();
        update(p);

        setIndexes(p.getId(), null);

        evictionDao.removeProduct(p);

        super.delete(p);
    }

    /**
     * Manage replacing existing lazy index into persistent structure.
     * @param product the product to modify.
     * @param indexes the index to set.
     */
    public void setIndexes(Product product, List<MetadataIndex> indexes) {
        product.setIndexes(indexes);
        update(product);
    }

    public void setIndexes(Long id, List<MetadataIndex> indexes) {
        setIndexes(read(id), indexes);
    }

    /**
     * Retrieve products ordered by it date of ingestion, updated. 
     * The list of product is returned prior to the passed date argument.
     * Currently processed and locked products are not returned.
     * @param max_date maximum date to retrieve products. More recent
     *                product will not be returned.
     * @return a scrollable list of the products.
     */
    public Iterator<Product> getProductsByIngestionDate(Date max_date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        String date = sdf.format(max_date);
        String query = "FROM " + entityClass.getName() + " " + "WHERE created < '" + date
                + "' AND processed=true AND " + "locked=false ORDER BY created ASC, updated ASC";
        return new PagedIterator<>(this, query);
    }

    /**
     * Retrieve the list of product ordered by lowest access.
     * The list of product is returned prior to the passed date argument.
     * Currently processed and locked products are not returned.
     * @return the ordered list of products.
     */
    public Iterator<Product> getProductsLowerAccess(Date max_date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        String date = sdf.format(max_date);
        String query = "FROM" + entityClass.getName() + "WHERE created < '" + date + "' AND processed=true AND "
                + "locked=false ORDER BY updated ASC, created ASC";
        return new PagedIterator<>(this, query);
    }

    public static String getPathFromProduct(Product product) {
        return getPathFromURL(product.getPath());
    }

    public static String getPathFromURL(URL product) {
        return product.toString();
    }

    /**
     * THIS METHOD IS NOT SAFE: IT MUST BE REMOVED. 
     * TODO: manage access by page.
     * @param user_id
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<Long> getAuthorizedProducts(Long user_id) {
        return (List<Long>) find("select id FROM " + entityClass.getName() + " p WHERE p.processed=true");
    }

    @SuppressWarnings("unchecked")
    public Product getProductByDownloadableFilename(final String filename, final Collection collection) {
        List<Product> products = null;
        if (collection == null || collectionDao.isRoot(collection)) {
            products = (List<Product>) find(
                    "from Product where download.path LIKE '%" + filename + "' AND processed = true");
        } else {
            products = (List<Product>) getHibernateTemplate().find(
                    "select p from Collection c left outer join c.products p " + "where c=? AND"
                            + "      p.download.path LIKE ? AND" + "      processed=true",
                    collection, "%" + filename + "%");
        }

        if ((products != null) && (products.size() > 0))
            return products.iterator().next();
        return null;
    }

    @SuppressWarnings("unchecked")
    public Product getProductByOrigin(final String origin) {
        List<Product> products = find(
                "from Product where origin='" + DaoUtils.secureString(origin) + "' AND processed = true");
        try {
            return DataAccessUtils.uniqueResult(products);
        } catch (IncorrectResultSizeDataAccessException e) {
            // Case of more than one product found.
            logger.warn("More than one entry of product origin found in database: " + origin);
            return products.get(0);
        }
    }

    public Product getProductByUuid(String uuid, User user) {
        @SuppressWarnings("unchecked")
        Product product = (Product) DataAccessUtils
                .uniqueResult(find("from Product p where p.uuid='" + uuid + "' AND p.processed=true"));
        return product;
    }

    /**
     * TODO: manage access by page.
     * @param user
     * @return
     */
    public List<Product> getNoCollectionProducts(User user) {
        ArrayList<Product> products = new ArrayList<>();
        StringBuilder sqlBuilder = new StringBuilder();
        sqlBuilder.append("SELECT p.ID ");
        sqlBuilder.append("FROM PRODUCTS p ");
        sqlBuilder.append("LEFT OUTER JOIN COLLECTION_PRODUCT cp ").append("ON p.ID = cp.PRODUCTS_ID ");
        sqlBuilder.append("WHERE cp.COLLECTIONS_ID IS NULL");
        final String sql = sqlBuilder.toString();
        List<BigInteger> queryResult = getHibernateTemplate().execute(new HibernateCallback<List<BigInteger>>() {
            @Override
            @SuppressWarnings("unchecked")
            public List<BigInteger> doInHibernate(Session session) throws HibernateException, SQLException {
                SQLQuery query = session.createSQLQuery(sql);
                return query.list();
            }
        });

        for (BigInteger pid : queryResult) {
            Product p = read(pid.longValue());
            if (p == null) {
                throw new IllegalStateException("Existing product is null ! product id = " + pid.longValue());
            }
            products.add(p);
        }

        return products;
    }

    public List<Product> scrollUploadedProducts(final User user, final int skip, final int top) {
        checkProductNumber(top);
        return getHibernateTemplate().execute(new HibernateCallback<List<Product>>() {
            @Override
            @SuppressWarnings("unchecked")
            public List<Product> doInHibernate(Session session) throws HibernateException, SQLException {
                String hql = "SELECT p FROM Product p, User u"
                        + " WHERE p.owner = u and u.id = ? AND p.processed = true";
                Query query = session.createQuery(hql);
                query.setLong(0, user.getId());
                query.setFirstResult(skip);
                query.setMaxResults(top);
                return (List<Product>) query.list();
            }
        });
    }

    @SuppressWarnings("unchecked")
    public List<Product> getUploadedProducts(final User user) {
        return (List<Product>) getHibernateTemplate().find("FROM Product WHERE owner = ? AND processed = true",
                user);
    }

    public User getOwnerOfProduct(final Product product) {
        return (User) DataAccessUtils
                .uniqueResult(getHibernateTemplate().find("select p.owner from Product p where p=?", product));
    }

    public boolean isAuthorized(final long user_id, final long product_id) {
        if (userDao.read(user_id) == null || read(product_id) == null) {
            return false;
        }
        return true;
    }

    public Iterator<Product> getUnprocessedProducts() {
        String query = "FROM " + entityClass.getName() + " WHERE processed is false";
        return new PagedIterator<>(this, query);
    }

    public Iterator<Product> getAllProducts() {
        String query = "FROM " + entityClass.getName();
        return new PagedIterator<>(this, query);
    }
}