/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package edu.harvard.iq.dataverse; import edu.harvard.iq.dataverse.authorization.users.User; import edu.harvard.iq.dataverse.dataaccess.ImageThumbConverter; import edu.harvard.iq.dataverse.search.IndexServiceBean; import edu.harvard.iq.dataverse.search.SolrSearchResult; import edu.harvard.iq.dataverse.util.SystemConfig; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; import java.util.ResourceBundle; import java.util.MissingResourceException; import java.util.Properties; import java.util.Set; import java.util.concurrent.Future; import java.util.jar.Attributes; import java.util.jar.Manifest; import javax.ejb.EJB; import javax.ejb.Stateless; import javax.inject.Inject; import javax.inject.Named; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.NonUniqueResultException; import javax.persistence.PersistenceContext; import javax.persistence.Query; import javax.persistence.TypedQuery; /** * * @author gdurand */ @Stateless @Named public class DataverseServiceBean implements java.io.Serializable { private static final Logger logger = Logger.getLogger(DataverseServiceBean.class.getCanonicalName()); @EJB IndexServiceBean indexService; @EJB DatasetServiceBean datasetService; @EJB DataverseLinkingServiceBean dataverseLinkingService; @EJB DatasetLinkingServiceBean datasetLinkingService; @EJB SystemConfig systemConfig; @Inject DataverseSession session; @PersistenceContext(unitName = "VDCNet-ejbPU") private EntityManager em; public Dataverse save(Dataverse dataverse) { dataverse.setModificationTime(new Timestamp(new Date().getTime())); Dataverse savedDataverse = em.merge(dataverse); /** * @todo check the result to see if indexing was successful or not */ Future<String> indexingResult = indexService.indexDataverse(savedDataverse); // logger.log(Level.INFO, "during dataverse save, indexing result was: {0}", indexingResult); return savedDataverse; } public Dataverse find(Object pk) { return (Dataverse) em.find(Dataverse.class, pk); } public List<Dataverse> findAll() { return em.createQuery("select object(o) from Dataverse as o order by o.name").getResultList(); } /** * @param numPartitions The number of partitions you intend to split the * indexing job into. Perhaps you have three Glassfish servers and you'd * like each one to operate on a subset of dataverses. * * @param partitionId Maybe "partitionId" is the wrong term but it's what we * call in the (text) UI. If you've specified three partitions the three * partitionIds are 0, 1, and 2. We do `dataverseId % numPartitions = * partitionId` to figure out which partition the dataverseId falls into. * * @param skipIndexed If true, will skip any dvObjects that have a indexTime set * * @return All dataverses if you say numPartitions=1 and partitionId=0. * Otherwise, a subset of dataverses. */ public List<Dataverse> findAllOrSubset(long numPartitions, long partitionId, boolean skipIndexed) { if (numPartitions < 1) { long saneNumPartitions = 1; numPartitions = saneNumPartitions; } String skipClause = skipIndexed ? "AND o.indexTime is null " : ""; TypedQuery<Dataverse> typedQuery = em.createQuery("SELECT OBJECT(o) FROM Dataverse AS o WHERE MOD( o.id, :numPartitions) = :partitionId " + skipClause + "ORDER BY o.id", Dataverse.class); typedQuery.setParameter("numPartitions", numPartitions); typedQuery.setParameter("partitionId", partitionId); return typedQuery.getResultList(); } public List<Dataverse> findByOwnerId(Long ownerId) { Query query = em.createQuery("select object(o) from Dataverse as o where o.owner.id =:ownerId order by o.name"); query.setParameter("ownerId", ownerId); return query.getResultList(); } public List<Dataverse> findPublishedByOwnerId(Long ownerId) { Query query = em.createQuery("select object(o) from Dataverse as o where o.owner.id =:ownerId and o.publicationDate is not null order by o.name"); query.setParameter("ownerId", ownerId); return query.getResultList(); } /** * @todo Do we really want this method to sometimes throw a * NoResultException which is a RuntimeException? */ public Dataverse findRootDataverse() { return (Dataverse) em.createQuery("select object(o) from Dataverse as o where o.owner.id = null").getSingleResult(); } public List<Dataverse> findAllPublishedByOwnerId(Long ownerId) { List<Dataverse> retVal = new ArrayList(); List<Dataverse> previousLevel = findPublishedByOwnerId(ownerId); retVal.addAll(previousLevel); /* if (!previousLevel.isEmpty()) { for (Dataverse dv : previousLevel) { retVal.addAll(findPublishedByOwnerId(dv.getId())); } }*/ return retVal; } /** * A lookup of a dataverse alias should be case insensitive. If "cfa" * belongs to the Center for Astrophysics, we don't want to allow Code for * America to start using "CFA". Force all queries to be lower case. */ public Dataverse findByAlias(String anAlias) { try { return (anAlias.toLowerCase().equals(":root")) ? findRootDataverse() : em.createNamedQuery("Dataverse.findByAlias", Dataverse.class) .setParameter("alias", anAlias.toLowerCase()) .getSingleResult(); } catch ( NoResultException|NonUniqueResultException ex ) { logger.fine("Unable to find a single dataverse using alias \"" + anAlias + "\": " + ex); return null; } } public boolean hasData( Dataverse dv ) { TypedQuery<Long> amountQry = em.createNamedQuery("Dataverse.ownedObjectsById", Long.class) .setParameter("id", dv.getId()); return (amountQry.getSingleResult()>0); } public boolean isRootDataverseExists() { long count = em.createQuery("SELECT count(dv) FROM Dataverse dv WHERE dv.owner.id=null", Long.class).getSingleResult(); return (count == 1); } public String determineDataversePath(Dataverse dataverse) { List<String> dataversePathSegments = new ArrayList(); indexService.findPathSegments(dataverse, dataversePathSegments); StringBuilder dataversePath = new StringBuilder(); for (String segment : dataversePathSegments) { dataversePath.append("/").append(segment); } return dataversePath.toString(); } public MetadataBlock findMDB(Long id) { return (MetadataBlock) em.find(MetadataBlock.class, id); } public MetadataBlock findMDBByName(String name) { return em.createQuery("select m from MetadataBlock m WHERE m.name=:name", MetadataBlock.class) .setParameter("name", name) .getSingleResult(); } public List<MetadataBlock> findAllMetadataBlocks() { return em.createQuery("select object(o) from MetadataBlock as o order by o.id").getResultList(); } public List<MetadataBlock> findSystemMetadataBlocks(){ return em.createQuery("select object(o) from MetadataBlock as o where o.owner.id=null order by o.id").getResultList(); } public List<MetadataBlock> findMetadataBlocksByDataverseId(Long dataverse_id) { return em.createQuery("select object(o) from MetadataBlock as o where o.owner.id=:dataverse_id order by o.id") .setParameter("dataverse_id", dataverse_id).getResultList(); } public DataverseFacet findFacet(Long id) { return (DataverseFacet) em.find(DataverseFacet.class, id); } public List<DataverseFacet> findAllDataverseFacets() { return em.createQuery("select object(o) from DataverseFacet as o order by o.display").getResultList(); } public String getDataverseLogoThumbnailAsBase64(Dataverse dataverse, User user) { if (dataverse == null) { return null; } File dataverseLogoFile = getLogo(dataverse); if (dataverseLogoFile != null) { String logoThumbNailPath = null; if (dataverseLogoFile.exists()) { logoThumbNailPath = ImageThumbConverter.generateImageThumb(dataverseLogoFile.getAbsolutePath(), 48); if (logoThumbNailPath != null) { return ImageThumbConverter.getImageAsBase64FromFile(new File(logoThumbNailPath)); } } } return null; } public String getDataverseLogoThumbnailAsBase64ById(Long dvId) { File dataverseLogoFile = getLogoById(dvId); if (dataverseLogoFile != null) { String logoThumbNailPath = null; if (dataverseLogoFile.exists()) { logoThumbNailPath = ImageThumbConverter.generateImageThumb(dataverseLogoFile.getAbsolutePath(), 48); if (logoThumbNailPath != null) { return ImageThumbConverter.getImageAsBase64FromFile(new File(logoThumbNailPath)); } } } return null; } /* public boolean isDataverseLogoThumbnailAvailable(Dataverse dataverse, User user) { if (dataverse == null) { return false; } // First, check if the dataverse has a defined logo: //if (dataverse.getDataverseTheme() != null && dataverse.getDataverseTheme().getLogo() != null && !dataverse.getDataverseTheme().getLogo().equals("")) { File dataverseLogoFile = getLogo(dataverse); if (dataverseLogoFile != null) { String logoThumbNailPath = null; if (dataverseLogoFile.exists()) { logoThumbNailPath = ImageThumbConverter.generateImageThumb(dataverseLogoFile.getAbsolutePath(), 48); if (logoThumbNailPath != null) { return true; } } } //} */ // If there's no uploaded logo for this dataverse, go through its // [released] datasets and see if any of them have card images: // // TODO: // Discuss/Decide if we really want to do this - i.e., go through every // file in every dataset below... // -- L.A. 4.0 beta14 /* for (Dataset dataset : datasetService.findPublishedByOwnerId(dataverse.getId())) { if (dataset != null) { DatasetVersion releasedVersion = dataset.getReleasedVersion(); if (releasedVersion != null) { if (datasetService.isDatasetCardImageAvailable(releasedVersion, user)) { return true; } } } } */ /* return false; } */ private File getLogo(Dataverse dataverse) { if (dataverse.getId() == null) { return null; } DataverseTheme theme = dataverse.getDataverseTheme(); if (theme != null && theme.getLogo() != null && !theme.getLogo().equals("")) { Properties p = System.getProperties(); String domainRoot = p.getProperty("com.sun.aas.instanceRoot"); if (domainRoot != null && !"".equals(domainRoot)) { return new File (domainRoot + File.separator + "docroot" + File.separator + "logos" + File.separator + dataverse.getLogoOwnerId() + File.separator + theme.getLogo()); } } return null; } private File getLogoById(Long id) { if (id == null) { return null; } String logoFileName = null; try { logoFileName = (String) em.createNativeQuery("SELECT logo FROM dataversetheme WHERE dataverse_id = " + id).getSingleResult(); } catch (Exception ex) { return null; } if (logoFileName != null && !logoFileName.equals("")) { Properties p = System.getProperties(); String domainRoot = p.getProperty("com.sun.aas.instanceRoot"); if (domainRoot != null && !"".equals(domainRoot)) { return new File (domainRoot + File.separator + "docroot" + File.separator + "logos" + File.separator + id + File.separator + logoFileName); } } return null; } public DataverseTheme findDataverseThemeByIdQuick(Long id) { if (id == null) { return null; } Object[] result = null; try { result = (Object[]) em.createNativeQuery("SELECT logo, logoFormat FROM dataversetheme WHERE dataverse_id = " + id).getSingleResult(); } catch (Exception ex) { return null; } if (result == null) { return null; } DataverseTheme theme = new DataverseTheme(); if (result[0] != null) { theme.setLogo((String) result[0]); } if (result[1] != null) { String format = (String) result[1]; if ("RECTANGLE".equals(format)) { theme.setLogoFormat(DataverseTheme.ImageFormat.RECTANGLE); } else if ("SQUARE".equals(format)) { theme.setLogoFormat(DataverseTheme.ImageFormat.SQUARE); } } return theme; } public List<Dataverse> findDataversesThisIdHasLinkedTo(long dataverseId) { return dataverseLinkingService.findLinkedDataverses(dataverseId); } public List<Dataverse> findDataversesThatLinkToThisDvId(long dataverseId) { return dataverseLinkingService.findLinkingDataverses(dataverseId); } public List<Dataset> findDatasetsThisIdHasLinkedTo(long dataverseId) { return datasetLinkingService.findDatasetsThisDataverseIdHasLinkedTo(dataverseId); } public List<Dataverse> findDataversesThatLinkToThisDatasetId(long datasetId) { return datasetLinkingService.findLinkingDataverses(datasetId); } public List<Dataverse> filterByAliasQuery(String filterQuery) { //Query query = em.createNativeQuery("select o from Dataverse o where o.alias LIKE '" + filterQuery + "%' order by o.alias"); //Query query = em.createNamedQuery("Dataverse.filterByAlias", Dataverse.class).setParameter("alias", filterQuery.toLowerCase() + "%"); Query query = em.createNamedQuery("Dataverse.filterByAliasNameAffiliation", Dataverse.class) .setParameter("alias", filterQuery.toLowerCase() + "%") .setParameter("name", "%" + filterQuery.toLowerCase() + "%") .setParameter("affiliation", "%" + filterQuery.toLowerCase() + "%"); //logger.info("created native query: select o from Dataverse o where o.alias LIKE '" + filterQuery + "%' order by o.alias"); logger.info("created named query"); List<Dataverse> ret = query.getResultList(); if (ret != null) { logger.info("results list: "+ret.size()+" results."); } return ret; } /** * Used to identify and properly display Harvested objects on the dataverse page. * *//* @Deprecated public Map<Long, String> getAllHarvestedDataverseDescriptions(){ String qstr = "SELECT dataverse_id, archiveDescription FROM harvestingClient;"; List<Object[]> searchResults = null; try { searchResults = em.createNativeQuery(qstr).getResultList(); } catch (Exception ex) { searchResults = null; } if (searchResults == null) { return null; } Map<Long, String> ret = new HashMap<>(); for (Object[] result : searchResults) { Long dvId = null; if (result[0] != null) { try { dvId = (Long)result[0]; } catch (Exception ex) { dvId = null; } if (dvId == null) { continue; } ret.put(dvId, (String)result[1]); } } return ret; }*/ public void populateDvSearchCard(SolrSearchResult solrSearchResult) { Long dvId = solrSearchResult.getEntityId(); if (dvId == null) { return; } Long parentDvId = null; String parentId = solrSearchResult.getParent().get("id"); if (parentId != null) { try { parentDvId = Long.parseLong(parentId); } catch (Exception ex) { parentDvId = null; } } Object[] searchResult = null; try { if (parentDvId == null) { searchResult = (Object[]) em.createNativeQuery("SELECT t0.AFFILIATION, t0.ALIAS FROM DATAVERSE t0 WHERE t0.ID = " + dvId).getSingleResult(); } else { searchResult = (Object[]) em.createNativeQuery("SELECT t0.AFFILIATION, t0.ALIAS, t2.ALIAS FROM DATAVERSE t0, DVOBJECT t1, DATAVERSE t2, DVOBJECT t3 WHERE (t0.ID = t1.ID) AND (t1.OWNER_ID = t3.ID) AND (t2.ID = t3.ID) AND (t0.ID = " + dvId + ")").getSingleResult(); } } catch (Exception ex) { return; } if (searchResult == null) { return; } if (searchResult[0] != null) { solrSearchResult.setDataverseAffiliation((String) searchResult[0]); } if (searchResult[1] != null) { solrSearchResult.setDataverseAlias((String) searchResult[1]); } if (parentDvId != null) { if (searchResult[2] != null) { solrSearchResult.setDataverseParentAlias((String) searchResult[2]); } } } }