/* * Copyright 2015-Present Entando Inc. (http://www.entando.com) All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library 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 Lesser General Public License for more * details. */ package com.agiletec.plugins.jacms.aps.system.services.resource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.agiletec.aps.system.common.AbstractSearcherDAO; import com.agiletec.aps.system.common.FieldSearchFilter; import com.agiletec.aps.system.exception.ApsSystemException; import com.agiletec.aps.system.services.category.Category; import com.agiletec.plugins.jacms.aps.system.services.resource.model.ResourceInterface; import com.agiletec.plugins.jacms.aps.system.services.resource.model.ResourceRecordVO; import org.entando.entando.aps.system.services.cache.ICacheInfoManager; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; /** * Data Access Object per gli oggetti risorsa. * @author E.Santoboni - W.Ambu */ public class ResourceDAO extends AbstractSearcherDAO implements IResourceDAO { private static final Logger _logger = LoggerFactory.getLogger(ResourceDAO.class); /** * Carica una risorsa nel db. * @param resource La risorsa da caricare nel db. */ @Override public void addResource(ResourceInterface resource) { Connection conn = null; try { conn = this.getConnection(); conn.setAutoCommit(false); this.executeAddResource(resource, conn); conn.commit(); } catch (Throwable t) { this.executeRollback(conn); _logger.error("Error adding resource", t); throw new RuntimeException("Error adding resource", t); } finally { closeConnection(conn); } } protected void executeAddResource(ResourceInterface resource, Connection conn) throws ApsSystemException { this.addResourceRecord(resource, conn); this.addCategoryRelationsRecord(resource, conn); } protected void addResourceRecord(ResourceInterface resource, Connection conn) throws ApsSystemException { PreparedStatement stat = null; try { stat = conn.prepareStatement(ADD_RESOURCE); stat.setString(1, resource.getId()); stat.setString(2, resource.getType()); stat.setString(3, resource.getDescr()); stat.setString(4, resource.getMainGroup()); stat.setString(5, resource.getXML()); stat.setString(6, resource.getMasterFileName()); if (null != resource.getCreationDate()) { stat.setDate(7, new java.sql.Date(resource.getCreationDate().getTime())); } else { stat.setDate(7, new java.sql.Date(new java.util.Date().getTime())); } stat.executeUpdate(); } catch (Throwable t) { _logger.error("Error adding resource record", t); throw new RuntimeException("Error adding resource record", t); } finally { closeDaoResources(null, stat); } } /** * Aggiorna una risorsa nel database. * @param resource La risorsa da aggiornare nel db. */ @Override @CacheEvict(value = ICacheInfoManager.DEFAULT_CACHE_NAME, key = "'jacms_resource_'.concat(#resource.id)", condition = "null != #resource") public void updateResource(ResourceInterface resource) { Connection conn = null; try { conn = this.getConnection(); conn.setAutoCommit(false); this.executeUpdateResource(resource, conn); conn.commit(); } catch (Throwable t) { this.executeRollback(conn); _logger.error("Error updating resource", t); throw new RuntimeException("Error updating resource", t); } finally { closeConnection(conn); } } protected void executeUpdateResource(ResourceInterface resource, Connection conn) throws ApsSystemException { this.deleteRecordsById(resource.getId(), DELETE_RESOURCE_REL_RECORD, conn); this.updateResourceRecord(resource, conn); this.addCategoryRelationsRecord(resource, conn); } protected void updateResourceRecord(ResourceInterface resource, Connection conn) throws ApsSystemException { PreparedStatement stat = null; try { stat = conn.prepareStatement(UPDATE_RESOURCE); stat.setString(1, resource.getType()); stat.setString(2, resource.getDescr()); stat.setString(3, resource.getMainGroup()); stat.setString(4, resource.getXML()); stat.setString(5, resource.getMasterFileName()); if (null != resource.getLastModified()) { stat.setDate(6, new java.sql.Date(resource.getLastModified().getTime())); } else { stat.setDate(6, new java.sql.Date(new java.util.Date().getTime())); } stat.setString(7, resource.getId()); stat.executeUpdate(); } catch (Throwable t) { _logger.error("Error updating resource record", t); throw new RuntimeException("Error updating resource record", t); } finally { closeDaoResources(null, stat); } } /** * Cancella una risorsa dal db. * @param id L'identificativo della risorsa da cancellare. */ @Override @CacheEvict(value = ICacheInfoManager.DEFAULT_CACHE_NAME, key = "'jacms_resource_'.concat(#id)", condition = "null != #id") public void deleteResource(String id) { Connection conn = null; try { conn = this.getConnection(); conn.setAutoCommit(false); this.executeDeleteResource(id, conn); conn.commit(); } catch (Throwable t) { this.executeRollback(conn); _logger.error("Error deleting resource {}", id, t); throw new RuntimeException("Error deleting resource " + id, t); } finally { this.closeConnection(conn); } } protected void executeDeleteResource(String resourceId, Connection conn) throws ApsSystemException { PreparedStatement stat = null; try { this.deleteRecordsById(resourceId, DELETE_RESOURCE_REL_RECORD, conn); this.deleteRecordsById(resourceId, DELETE_CONTENTS_REFERENCE, conn); stat = conn.prepareStatement(DELETE_RESOURCE); stat.setString(1, resourceId); stat.executeUpdate(); } catch (Throwable t) { _logger.error("Error deleting resource {}", resourceId, t); throw new RuntimeException("Error deleting resource " + resourceId, t); } finally { closeDaoResources(null, stat); } } /** * Carica una lista di identificativi di risorse * in base al tipo, ad una parola chiave e dalla categoria della risorsa. * @param type Tipo di risorsa da cercare. * @param text Testo immesso per il raffronto con la descrizione della risorsa. null o * stringa vuota nel caso non si voglia ricercare le risorse per parola chiave. * @param categoryCode Il codice della categoria delle risorse. null o * stringa vuota nel caso non si voglia ricercare le risorse per categoria. * @param groupCodes I codici dei gruppi utenti consentiti tramite il quale * filtrare le risorse. Nel caso che la collezione di codici sia nulla o vuota, * non verrà eseguito la selezione per gruppi. * @return La lista di identificativi di risorse. */ @Override public List<String> searchResourcesId(String type, String text, String categoryCode, Collection<String> groupCodes) { return this.searchResourcesId(type, text, null, categoryCode, groupCodes); } @Override public List<String> searchResourcesId(String type, String text, String filename, String categoryCode, Collection<String> groupCodes) { FieldSearchFilter[] filters = this.createFilters(type, text, filename, groupCodes); return this.searchResourcesId(filters, categoryCode, groupCodes); } private FieldSearchFilter[] createFilters(String type, String text, String filename, Collection<String> groupCodes) { FieldSearchFilter[] filters = new FieldSearchFilter[0]; if (null != type && type.trim().length() > 0) { FieldSearchFilter filterToAdd = new FieldSearchFilter(IResourceManager.RESOURCE_TYPE_FILTER_KEY, type, false); filters = super.addFilter(filters, filterToAdd); } if (null != text && text.trim().length() > 0) { FieldSearchFilter filterToAdd = new FieldSearchFilter(IResourceManager.RESOURCE_DESCR_FILTER_KEY, text, true); filters = super.addFilter(filters, filterToAdd); } if (null != filename && filename.trim().length() > 0) { FieldSearchFilter filterToAdd = new FieldSearchFilter(IResourceManager.RESOURCE_FILENAME_FILTER_KEY, filename, true); filters = super.addFilter(filters, filterToAdd); } if (groupCodes != null && groupCodes.size() > 0) { List<String> allowedValues = new ArrayList<String>(); allowedValues.addAll(groupCodes); FieldSearchFilter filterToAdd = new FieldSearchFilter(IResourceManager.RESOURCE_MAIN_GROUP_FILTER_KEY, allowedValues, false); filters = super.addFilter(filters, filterToAdd); } if (filters.length == 0) { return null; } return filters; } @Override public List<String> searchResourcesId(FieldSearchFilter[] filters, String categoryCode, Collection<String> groupCodes) { Connection conn = null; List<String> resources = new ArrayList<String>(); PreparedStatement stat = null; ResultSet res = null; try { conn = this.getConnection(); stat = this.buildStatement(filters, categoryCode, groupCodes, conn); res = stat.executeQuery(); this.flowResult(resources, filters, res); } catch (Throwable t) { _logger.error("Error loading resources id", t); throw new RuntimeException("Error loading resources id", t); } finally { closeDaoResources(res, stat, conn); } return resources; } private PreparedStatement buildStatement(FieldSearchFilter[] filters, String categoryCode, Collection<String> groupCodes, Connection conn) { String query = this.createQueryString(filters, categoryCode, groupCodes); PreparedStatement stat = null; try { stat = conn.prepareStatement(query); int index = 0; index = this.addMetadataFieldFilterStatementBlock(filters, index, stat); if (null != categoryCode && categoryCode.trim().length() > 0) { stat.setString(++index, categoryCode); } } catch (Throwable t) { _logger.error("Error while creating the statement", t); throw new RuntimeException("Error while creating the statement", t); } return stat; } private String createQueryString(FieldSearchFilter[] filters, String categoryCode, Collection<String> groupCodes) { StringBuffer query = this.createBaseQueryBlock(filters, false, categoryCode); boolean hasAppendWhereClause = this.appendMetadataFieldFilterQueryBlocks(filters, query, false); if (null != categoryCode && categoryCode.trim().length() > 0) { hasAppendWhereClause = this.verifyWhereClauseAppend(query, hasAppendWhereClause); query.append("resourcerelations.refcategory = ? "); } query.append("ORDER BY resources.descr "); return query.toString(); } private StringBuffer createBaseQueryBlock(FieldSearchFilter[] filters, boolean selectAll, String categoryCode) { StringBuffer query = super.createBaseQueryBlock(filters, selectAll); if (null != categoryCode && categoryCode.trim().length() > 0) { query.append("INNER JOIN resourcerelations ON resources.resid = resourcerelations.resid "); } return query; } /** * Carica un record di risorse in funzione dell'id Risorsa. Questo record è * necessario per l'estrazione della risorse in oggetto tipo AbstractResource * da parte del ResourceManager. * @param id L'identificativo della risorsa. * @return Il record della risorsa. */ @Override @Cacheable(value = ICacheInfoManager.DEFAULT_CACHE_NAME, key = "'jacms_resource_'.concat(#id)", condition = "null != #id") public ResourceRecordVO loadResourceVo(String id) { Connection conn = null; ResourceRecordVO resourceVo = null; PreparedStatement stat = null; ResultSet res = null; try { conn = this.getConnection(); stat = conn.prepareStatement(LOAD_RESOURCE_VO); stat.setString(1, id); res = stat.executeQuery(); if (res.next()) { resourceVo = new ResourceRecordVO(); resourceVo.setId(id); resourceVo.setResourceType(res.getString(1)); resourceVo.setDescr(res.getString(2)); resourceVo.setMainGroup(res.getString(3)); resourceVo.setXml(res.getString(4)); resourceVo.setMasterFileName(res.getString(5)); resourceVo.setCreationDate(res.getDate(6)); resourceVo.setLastModified(res.getDate(7)); } } catch (Throwable t) { _logger.error("Errore loading resource {}", id, t); throw new RuntimeException("Errore loading resource" + id, t); } finally { closeDaoResources(res, stat, conn); } return resourceVo; } /** * Metodo di servizio. * Aggiunge un record nella tabella resourcerelations * per ogni categoria della risorsa. * @param resource La risorsa del quale referenziare le categorie. * @param conn La connessione con il db. * @throws ApsSystemException */ protected void addCategoryRelationsRecord(ResourceInterface resource, Connection conn) throws ApsSystemException { if (resource.getCategories().size()>0) { PreparedStatement stat = null; try { Set<String> codes = this.getCategoryCodes(resource); stat = conn.prepareStatement(ADD_RESOURCE_REL_RECORD); Iterator<String> codeIter = codes.iterator(); while (codeIter.hasNext()) { String code = (String) codeIter.next(); stat.setString(1, resource.getId()); stat.setString(2, code); stat.addBatch(); stat.clearParameters(); } stat.executeBatch(); } catch (Throwable t) { _logger.error("Error adding resourcerelations record for {}", resource.getId(), t); throw new RuntimeException("Error adding resourcerelations record for " + resource.getId(), t); } finally { closeDaoResources(null, stat); } } } /** * Restituisce la lista di codici di categorie associate ad una risorsa. * La risorsa viene sempre referenziata con la categoria "root" della * tipologia relativa (che corrisponde al codice della tipologia). * @param resource La risorsa da inserire o da modificare. * @return Il set di codici di categorie. */ private Set<String> getCategoryCodes(ResourceInterface resource) { Set<String> codes = new HashSet<String>(); Iterator<Category> categoryIter = resource.getCategories().iterator(); while (categoryIter.hasNext()) { Category category = (Category) categoryIter.next(); this.addCategoryCode(resource, category, codes); } return codes; } private void addCategoryCode(ResourceInterface resource, Category category, Set<String> codes) { if (category.getCode().equals(category.getParent().getCode())) return; codes.add(category.getCode()); Category parentCategory = (Category) category.getParent(); if (null != parentCategory) { this.addCategoryCode(resource, parentCategory, codes); } } protected void deleteRecordsById(String resourceId, String query, Connection conn) { PreparedStatement stat = null; try { stat = conn.prepareStatement(query); stat.setString(1, resourceId); stat.executeUpdate(); } catch (Throwable t) { _logger.error("Error deleting resource records for resource {}", resourceId, t); throw new RuntimeException("Error deleting resource records for resource " + resourceId, t); } finally { closeDaoResources(null, stat); } } /* ESTENSIONE SPOSTAMENTO NODI */ @Override public void updateResourceRelations(ResourceInterface resource) { Connection conn = null; try { conn = this.getConnection(); conn.setAutoCommit(false); this.deleteRecordsById(resource.getId(), DELETE_RESOURCE_REL_RECORD, conn); this.addCategoryRelationsRecord(resource, conn); conn.commit(); } catch (Throwable t) { this.executeRollback(conn); this.processDaoException(t, "Error updating resource category relations", "updateResourceRelations"); } finally { closeConnection(conn); } } @Override protected String getMasterTableName() { return "resources"; } @Override protected String getMasterTableIdFieldName() { return "resid"; } @Override protected String getTableFieldName(String metadataFieldKey) { return metadataFieldKey; } @Override protected boolean isForceCaseInsensitiveLikeSearch() { return true; } private final String LOAD_RESOURCE_VO = "SELECT restype, descr, maingroup, resourcexml, masterfilename, creationdate, lastmodified FROM resources WHERE resid = ? "; private final String ADD_RESOURCE = "INSERT INTO resources (resid, restype, descr, maingroup, resourcexml, masterfilename, creationdate) " + "VALUES ( ? , ? , ? , ? , ? , ? , ? )"; private final String UPDATE_RESOURCE = "UPDATE resources SET restype = ? , descr = ? , maingroup = ? , resourcexml = ? , masterfilename = ? , lastmodified = ? WHERE resid = ? "; private final String DELETE_CONTENTS_REFERENCE = "DELETE FROM contentrelations WHERE refresource = ? "; private final String DELETE_RESOURCE = "DELETE FROM resources WHERE resid = ? "; private final String ADD_RESOURCE_REL_RECORD = "INSERT INTO resourcerelations (resid, refcategory) VALUES ( ? , ? )"; private final String DELETE_RESOURCE_REL_RECORD = "DELETE FROM resourcerelations WHERE resid = ? "; }