/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of the License at the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ package org.apereo.portal.portlet.dao.jpa; import com.google.common.base.Function; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.persistence.EntityManager; import javax.persistence.Query; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.ParameterExpression; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import org.apache.commons.lang.Validate; import org.apereo.portal.jpa.BasePortalJpaDao; import org.apereo.portal.jpa.OpenEntityManager; import org.apereo.portal.portlet.dao.IMarketplaceRatingDao; import org.apereo.portal.portlet.dao.IPortletDefinitionDao; import org.apereo.portal.portlet.marketplace.IMarketplaceRating; import org.apereo.portal.portlet.om.IPortletDefinition; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Repository; @Repository("marketplaceRatingDAO") @Qualifier("persistence") public class JpaMarketplaceRatingDao extends BasePortalJpaDao implements IMarketplaceRatingDao { private static final String CLEAR_RATINGS_JPQL = "DELETE FROM MarketplaceRatingImpl m " + "WHERE m.marketplaceRatingPK.portletDefinition = :portletDefinition"; private IPortletDefinitionDao portletDefinitionDao; @Autowired public void getPortletDefinitionDao(IPortletDefinitionDao dao) { this.portletDefinitionDao = dao; } private CriteriaQuery<MarketplaceRatingImpl> findAllMarketPlaceRating; @Override public void afterPropertiesSet() throws Exception { this.findAllMarketPlaceRating = this.createCriteriaQuery( new Function<CriteriaBuilder, CriteriaQuery<MarketplaceRatingImpl>>() { @Override public CriteriaQuery<MarketplaceRatingImpl> apply( CriteriaBuilder input) { final CriteriaQuery<MarketplaceRatingImpl> criteriaQuery = input.createQuery(MarketplaceRatingImpl.class); final Root<MarketplaceRatingImpl> definitionRoot = criteriaQuery.from(MarketplaceRatingImpl.class); criteriaQuery.select(definitionRoot); return criteriaQuery; } }); } /** * This method will either create a new rating or update an existing rating * * @param Must not be null * @return the attached entity */ @Override @PortalTransactional public IMarketplaceRating createOrUpdateRating( IMarketplaceRating marketplaceRatingImplementation) { Validate.notNull(marketplaceRatingImplementation, "MarketplaceRatingImpl must not be null"); final EntityManager entityManager = this.getEntityManager(); IMarketplaceRating temp = this.getRating(marketplaceRatingImplementation.getMarketplaceRatingPK()); if (!entityManager.contains(marketplaceRatingImplementation) && temp != null) { //Entity is not managed and there is a rating for this portlet/user - update needed temp = entityManager.merge(marketplaceRatingImplementation); } else { //Entity is either already managed or doesn't exist - create needed temp = marketplaceRatingImplementation; } entityManager.persist(temp); return temp; } @Override @PortalTransactional public IMarketplaceRating createOrUpdateRating( int rating, String userName, String review, IPortletDefinition portletDefinition) { MarketplaceRatingImpl temp = new MarketplaceRatingImpl(); PortletDefinitionImpl tempPortlet = new PortletDefinitionImpl( portletDefinition.getType(), portletDefinition.getFName(), portletDefinition.getName(), portletDefinition.getTitle(), portletDefinition.getPortletDescriptorKey().getWebAppName(), portletDefinition.getPortletDescriptorKey().getPortletName(), portletDefinition.getPortletDescriptorKey().isFrameworkPortlet(), portletDefinition.getPortletDefinitionId()); MarketplaceRatingPK tempPK = new MarketplaceRatingPK(userName, tempPortlet); temp.setMarketplaceRatingPK(tempPK); temp.setRating(rating); temp.setReview(review); return this.createOrUpdateRating(temp); } /** @return List of all ratings */ @Override @PortalTransactionalReadOnly @OpenEntityManager(unitName = PERSISTENCE_UNIT_NAME) public Set<IMarketplaceRating> getAllRatings() { final TypedQuery<MarketplaceRatingImpl> query = this.createCachedQuery(this.findAllMarketPlaceRating); return new HashSet<IMarketplaceRating>(query.getResultList()); } /** * @since 5.0 * @param marketplaceRatingPK the primary key of the entity you want * @return Set of ratings per portlet definition */ @PortalTransactionalReadOnly @OpenEntityManager(unitName = PERSISTENCE_UNIT_NAME) public Set<IMarketplaceRating> getRatingsByFname(String fname) { //Build criteria to fetch MarketplaceRatingImpl based on the incoming portlet name. final EntityManager entityManager = this.getEntityManager(); final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); final CriteriaQuery<IMarketplaceRating> getByPortlet = cb.createQuery(IMarketplaceRating.class); final Root<MarketplaceRatingImpl> imr = getByPortlet.from(MarketplaceRatingImpl.class); getByPortlet.select(imr); //Define the path to the portlet fName final Path<MarketplaceRatingPK> mrPK = imr.get("marketplaceRatingPK"); final Path<PortletDefinitionImpl> mrIPD = mrPK.get("portletDefinition"); final ParameterExpression<String> portletFName = cb.parameter(String.class, "portletFName"); getByPortlet.where(cb.equal(mrIPD.get("fname"), portletFName)); TypedQuery<IMarketplaceRating> tq = entityManager.createQuery(getByPortlet); tq.setParameter("portletFName", fname); List<IMarketplaceRating> resultList = tq.getResultList(); Set<IMarketplaceRating> resultSet = new HashSet<IMarketplaceRating>(resultList); return resultSet; } @Override @PortalTransactional public IMarketplaceRating getRating(String userName, IPortletDefinition portletDefinition) { PortletDefinitionImpl tempPortlet = new PortletDefinitionImpl( portletDefinition.getType(), portletDefinition.getFName(), portletDefinition.getName(), portletDefinition.getTitle(), portletDefinition.getPortletDescriptorKey().getWebAppName(), portletDefinition.getPortletDescriptorKey().getPortletName(), portletDefinition.getPortletDescriptorKey().isFrameworkPortlet(), portletDefinition.getPortletDefinitionId()); MarketplaceRatingPK tempPK = new MarketplaceRatingPK(userName, tempPortlet); return this.getRating(tempPK); } /** * @param marketplaceRatingPK the primary key of the entity you want * @return an attached entity if found, null otherwise */ @PortalTransactionalReadOnly @OpenEntityManager(unitName = PERSISTENCE_UNIT_NAME) public IMarketplaceRating getRating(MarketplaceRatingPK marketplaceRatingPK) { final MarketplaceRatingPK tempRatingPK = marketplaceRatingPK; MarketplaceRatingImpl temp = new MarketplaceRatingImpl(); temp.setMarketplaceRatingPK(marketplaceRatingPK); final EntityManager entityManager = this.getEntityManager(); if (entityManager.contains(temp)) { temp = entityManager.merge(temp); return temp; } else { final TypedQuery<MarketplaceRatingImpl> query = this.createQuery( this.createCriteriaQuery( new Function< CriteriaBuilder, CriteriaQuery<MarketplaceRatingImpl>>() { @Override public CriteriaQuery<MarketplaceRatingImpl> apply( CriteriaBuilder input) { final CriteriaQuery<MarketplaceRatingImpl> criteriaQuery = input.createQuery( MarketplaceRatingImpl.class); final Root<MarketplaceRatingImpl> definitionRoot = criteriaQuery.from(MarketplaceRatingImpl.class); Predicate conditionUser = input.equal( definitionRoot .get("marketplaceRatingPK") .get("userName"), tempRatingPK.getUserName()); Predicate conditionPortlet = input.equal( definitionRoot .get("marketplaceRatingPK") .get("portletDefinition"), tempRatingPK.getPortletDefinition()); Predicate allConditions = input.and(conditionPortlet, conditionUser); criteriaQuery.where(allConditions); return criteriaQuery; } })); List<MarketplaceRatingImpl> results = query.getResultList(); if (!results.isEmpty()) { return results.get(0); } else { return null; } } } /** @param entity to delete - can not be null */ @Override @PortalTransactional public void deleteRating(IMarketplaceRating marketplaceRatingImplementation) { Validate.notNull( marketplaceRatingImplementation, "marketplaceRatingImplementation can not be null"); final IMarketplaceRating persistantMarketplaceRatingImpl; final EntityManager entityManager = this.getEntityManager(); if (entityManager.contains(marketplaceRatingImplementation)) { persistantMarketplaceRatingImpl = marketplaceRatingImplementation; } else { persistantMarketplaceRatingImpl = entityManager.merge(marketplaceRatingImplementation); } entityManager.remove(persistantMarketplaceRatingImpl); } @Override @PortalTransactional public void clearRatingsForPortlet(IPortletDefinition portletDefinition) { Validate.notNull(portletDefinition, "portletDefinition can not be null"); final EntityManager em = getEntityManager(); final Query query = em.createQuery(CLEAR_RATINGS_JPQL); query.setParameter("portletDefinition", portletDefinition); final int deleteCount = query.executeUpdate(); logger.info( "Cleared {} ratings from portlet {}", deleteCount, portletDefinition.getFName()); } @Override @PortalTransactional public void aggregateMarketplaceRating() { //setup EntityManager em = this.getEntityManager(); //get list of average ratings Query aggregatedQuery = em.createQuery( "SELECT AVG(m.rating) as rating, " + " count(m.marketplaceRatingPK.portletDefinition.internalPortletDefinitionId) as theCount, " + " m.marketplaceRatingPK.portletDefinition.internalPortletDefinitionId as portletId " + " FROM MarketplaceRatingImpl m " + " GROUP BY m.marketplaceRatingPK.portletDefinition.internalPortletDefinitionId"); @SuppressWarnings("unchecked") List<Object[]> aggregatedResults = aggregatedQuery.getResultList(); //update the portlet definition with the average rating for (Object[] result : aggregatedResults) { if (result != null && result.length == 3) { try { Double averageRating = (Double) result[0]; Long usersRated = (Long) result[1]; String portletId = ((Long) result[2]).toString(); IPortletDefinition portletDefinition = portletDefinitionDao.getPortletDefinition(portletId); if (portletDefinition != null) { portletDefinition.setRating(averageRating); portletDefinition.setUsersRated(usersRated); em.persist(portletDefinition); } } catch (Exception ex) { logger.warn("Issue aggregating portlet ratings, recoverable", ex); } } } } }