Java tutorial
/* * Copyright 2010 Research Studios Austria Forschungsgesellschaft mBH * * This file is part of easyrec. * * easyrec is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * easyrec 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with easyrec. If not, see <http://www.gnu.org/licenses/>. */ package org.easyrec.service.web.nodomain.impl; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.jamonapi.Monitor; import com.jamonapi.MonitorFactory; import net.sf.ehcache.Cache; import net.sf.ehcache.Element; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.easyrec.model.core.*; import org.easyrec.model.core.transfer.TimeConstraintVO; import org.easyrec.model.core.web.Item; import org.easyrec.model.core.web.RemoteTenant; import org.easyrec.model.core.web.Session; import org.easyrec.model.web.Recommendation; import org.easyrec.model.web.RecommendedItem; import org.easyrec.model.web.enums.TimeRange; import org.easyrec.rest.nodomain.exception.EasyRecRestException; import org.easyrec.service.core.ClusterService; import org.easyrec.service.core.ProfileService; import org.easyrec.service.core.TenantService; import org.easyrec.service.domain.DomainActionService; import org.easyrec.service.domain.DomainItemAssocService; import org.easyrec.service.domain.DomainRecommenderService; import org.easyrec.service.domain.TypeMappingService; import org.easyrec.service.web.IDMappingService; import org.easyrec.service.web.ItemService; import org.easyrec.service.web.nodomain.ShopRecommenderService; import org.easyrec.store.dao.IDMappingDAO; import org.easyrec.store.dao.core.ItemDAO; import org.easyrec.store.dao.core.types.AssocTypeDAO; import org.easyrec.store.dao.web.RemoteTenantDAO; import org.easyrec.utils.collection.CollectionUtils; import org.easyrec.utils.spring.log.annotation.IOLog; import org.easyrec.utils.spring.profile.annotation.Profiled; import org.easyrec.vocabulary.MSG; import org.easyrec.vocabulary.WS; import java.util.*; /** * Service class to provide functions for web service recommendation functions. * <p/> * <p><b>Company: </b> * SAT, Research Studios Austria</p> * <p/> * <p><b>Copyright: </b> * (c) 2007</p> * <p/> * <p><b>last modified:</b><br/> * $Author: fsalcher $<br/> * $Date: 2012-03-23 15:35:07 +0100 (Fr, 23 Mr 2012) $<br/> * $Revision: 18791 $</p> * * @author Stephan Zavrel */ //@MapThrowableToException(exceptionClazz=ShopRecommenderException.class) public class ShopRecommenderServiceImpl implements ShopRecommenderService { private final Log logger = LogFactory.getLog(this.getClass()); private DomainActionService domainActionService; private DomainRecommenderService domainRecommenderService; private DomainItemAssocService domainItemAssocService; private TypeMappingService typeMappingService; private IDMappingDAO idMappingDAO; private IDMappingService idMappingService; private ItemService itemService; private ItemDAO itemDAO; private RemoteTenantDAO remoteTenantDAO; private Cache cache; private ProfileService profileService; private ClusterService clusterService; private TenantService tenantService; // Jamon Loggers private final static String JAMON_REST_VIEW_CORE = "rest.view.core"; private final static String JAMON_REST_RATE_CORE = "rest.rate.core"; private final static String JAMON_REST_BUY_CORE = "rest.buy.core"; private final static String JAMON_REST_SENDACTION_CORE = "rest.sendaction.core"; private final static String JAMON_REST_ALSO_VIEWED_CORE = "rest.alsoviewed.core"; private final static String JAMON_REST_ALSO_BOUGHT_CORE = "rest.alsobought.core"; private final static String JAMON_REST_ALSO_RATED_CORE = "rest.alsorated.core"; private final static String JAMON_REST_RECS_FOR_USER = "rest.recsforuser.core"; private final static String JAMON_REST_ACTION_HISTORY_CORE = "rest.history.core"; private final static String JAMON_REST_RECOMMENDED_ITEMS_CORE = "rest.recommendeditems.core"; private final static String JAMON_REST_MOST_BOUGHT_CORE = "rest.mostbought.core"; private final static String JAMON_REST_MOST_VIEWED_CORE = "rest.mostviewed.core"; private final static String JAMON_REST_MOST_RATED_CORE = "rest.mostrated.core"; private final static String JAMON_REST_BEST_RATED_CORE = "rest.bestrated.core"; private final static String JAMON_REST_WORST_RATED_CORE = "rest.worstrated.core"; /////////////////////////////////////////////////////////////////////////////////////////////// // interface "ShopRecommenderService" implementation /////////////////////////////////////////////////////////////////////////////////////////////// // Actions /////////////////////////////////////////////////////////////////////////////////////////////// /** * This procedure tells the ProfilerController that an Item is purchased. * Note: * A SessionId is always required. In case no userId is given the sessionId * is used a the userId instead. */ @IOLog @Profiled @Override public Item purchaseItem(RemoteTenant remoteTenant, String userId, String itemId, String itemType, String itemDescription, String itemUrl, String itemImageUrl, Date actionTime, Session session, String actionInfo) { Item item = itemDAO.get(remoteTenant, itemId, itemType); if (item == null) { item = itemDAO.add(remoteTenant.getId(), itemId, itemType, itemDescription, itemUrl, itemImageUrl); if (logger.isDebugEnabled()) { logger.debug(new StringBuilder().append("<ITEMCOLLECT@").append(remoteTenant.getId()).append("> ") .append(itemType).append(" ").append(itemDescription).append(" (id:").append(itemId) .append(")").toString()); } } if (item != null && item.isActive()) { // if userid is empty use sessionid instead of the userid userId = Strings.isNullOrEmpty(userId) ? session.getSessionId() : userId; Monitor monCore = MonitorFactory.start(JAMON_REST_BUY_CORE); if (actionTime == null) { domainActionService.purchaseItem(remoteTenant.getId(), idMappingDAO.lookup(userId), session.getSessionId(), session.getIp(), new ItemVO<>(remoteTenant.getId(), idMappingDAO.lookup(itemId), itemType), actionInfo); } else { domainActionService.purchaseItem(remoteTenant.getId(), idMappingDAO.lookup(userId), session.getSessionId(), session.getIp(), new ItemVO<>(remoteTenant.getId(), idMappingDAO.lookup(itemId), itemType), actionInfo, actionTime); } monCore.stop(); if (logger.isDebugEnabled()) { logger.debug(new StringBuilder().append("<buy@").append(remoteTenant.getId()).append("> ") .append(userId).append(" view ").append(itemDescription).append(" (id:").append(itemId) .append(")").toString()); } } return item; } /** * This procedure tells the ProfilerController that an Item is viewed. * Note: * A SessionId is always required. In case no userId is given the sessionId * is used a the userId instead. */ @IOLog @Profiled @Override public Item viewItem(RemoteTenant remoteTenant, String userId, String itemId, String itemType, String itemDescription, String itemUrl, String itemImageUrl, Date actionTime, Session session, String actionInfo) { Item item = itemDAO.get(remoteTenant, itemId, itemType); if (item == null) { item = itemDAO.add(remoteTenant.getId(), itemId, itemType, itemDescription, itemUrl, itemImageUrl); if (logger.isDebugEnabled()) { logger.debug(new StringBuilder().append("<ITEMCOLLECT@").append(remoteTenant.getId()).append("> ") .append(itemType).append(" ").append(itemDescription).append(" (id:").append(itemId) .append(")").toString()); } } if (item != null && item.isActive()) { // if userid is empty use sessionid instead of the userid userId = Strings.isNullOrEmpty(userId) ? session.getSessionId() : userId; Monitor monCore = MonitorFactory.start(JAMON_REST_VIEW_CORE); if (actionTime == null) { domainActionService.viewItem(remoteTenant.getId(), idMappingDAO.lookup(userId), session.getSessionId(), session.getIp(), new ItemVO<>(remoteTenant.getId(), idMappingDAO.lookup(itemId), itemType), actionInfo); } else { domainActionService.viewItem(remoteTenant.getId(), idMappingDAO.lookup(userId), session.getSessionId(), session.getIp(), new ItemVO<>(remoteTenant.getId(), idMappingDAO.lookup(itemId), itemType), actionInfo, actionTime); } monCore.stop(); if (logger.isDebugEnabled()) { logger.debug(new StringBuilder().append("<view@").append(remoteTenant.getId()).append("> ") .append(userId).append(" view ").append(itemDescription).append(" (id:").append(itemId) .append(")").toString()); } } return item; } /** * This procedure tells the ProfilerController that an Item is rated * with a given value. * Note: * A SessionId is always required. In case no userId is given the sessionId * is used a the userId instead. */ @IOLog @Profiled @Override public Item rateItem(RemoteTenant remoteTenant, String userId, String itemId, String itemType, String itemDescription, String itemUrl, String itemImageUrl, Integer ratingValue, Date actionTime, Session session, String actionInfo) { Item item = itemDAO.get(remoteTenant, itemId, itemType); if (item == null) { item = itemDAO.add(remoteTenant.getId(), itemId, itemType, itemDescription, itemUrl, itemImageUrl); if (logger.isDebugEnabled()) { logger.debug(new StringBuilder().append("<ITEMCOLLECT@").append(remoteTenant.getId()).append("> ") .append(itemType).append(" ").append(itemDescription).append(" (id:").append(itemId) .append(")").toString()); } } if (item != null && item.isActive()) { // if userid is empty use sessionid instead of the userid userId = Strings.isNullOrEmpty(userId) ? session.getSessionId() : userId; Monitor monCore = MonitorFactory.start(JAMON_REST_RATE_CORE); if (actionTime == null) { domainActionService.rateItem(remoteTenant.getId(), idMappingDAO.lookup(userId), session.getSessionId(), session.getIp(), new ItemVO<>(remoteTenant.getId(), idMappingDAO.lookup(itemId), itemType), ratingValue, actionInfo); } else { domainActionService.rateItem(remoteTenant.getId(), idMappingDAO.lookup(userId), session.getSessionId(), session.getIp(), new ItemVO<>(remoteTenant.getId(), idMappingDAO.lookup(itemId), itemType), ratingValue, actionInfo, actionTime); } monCore.stop(); if (logger.isDebugEnabled()) { logger.debug(new StringBuilder().append("<rate@").append(remoteTenant.getId()).append("> ") .append(userId).append(" view ").append(itemDescription).append(" (id:").append(itemId) .append(")").toString()); } } return item; } /** * This procedure tells the ProfilerController that an Item is rated * with a given value. * Note: * A SessionId is always required. In case no userId is given the sessionId * is used as the userId instead. */ @IOLog @Profiled @Override public Item sendAction(RemoteTenant remoteTenant, String userId, String itemId, String itemType, String itemDescription, String itemUrl, String itemImageUrl, String actionType, Integer actionValue, Date actionTime, Session session, String actionInfo) { Item item = itemDAO.get(remoteTenant, itemId, itemType); if (item == null) { item = itemDAO.add(remoteTenant.getId(), itemId, itemType, itemDescription, itemUrl, itemImageUrl); if (logger.isDebugEnabled()) { logger.debug(new StringBuilder().append("<ITEMCOLLECT@").append(remoteTenant.getId()).append("> ") .append(itemType).append(" ").append(itemDescription).append(" (id:").append(itemId) .append(")").toString()); } } if (item != null && item.isActive()) { // if userid is empty use sessionid instead of the userid userId = Strings.isNullOrEmpty(userId) ? session.getSessionId() : userId; Monitor monCore = MonitorFactory.start(JAMON_REST_SENDACTION_CORE); if (actionTime == null) { domainActionService.insertAction(remoteTenant.getId(), idMappingDAO.lookup(userId), session.getSessionId(), session.getIp(), new ItemVO<>(remoteTenant.getId(), idMappingDAO.lookup(itemId), itemType), actionType, actionValue, actionInfo); } else { domainActionService.insertAction(remoteTenant.getId(), idMappingDAO.lookup(userId), session.getSessionId(), session.getIp(), new ItemVO<>(remoteTenant.getId(), idMappingDAO.lookup(itemId), itemType), actionType, actionValue, actionInfo, actionTime); } monCore.stop(); if (logger.isDebugEnabled()) { logger.debug(new StringBuilder().append("<sendAction@").append(remoteTenant.getId()).append("> ") .append(userId).append(" view ").append(itemDescription).append(" (id:").append(itemId) .append(")").toString()); } } return item; } // @IOLog // @Profiled // public void searchItem(Integer tenantId, // String userId, // String sessionId, // String ip, // String itemId, // String itemType, // Boolean searchSucceeded, // Integer numberOfFoundItems, // String description) throws ShopRecommenderException // { // domainActionService.searchItem(tenantId, idMappingDAO.lookup(userId), sessionId, ip, new ItemVO<Integer, String>(tenantId, idMappingDAO.lookup(itemId), itemType), searchSucceeded, numberOfFoundItems, description); // } /////////////////////////////////////////////////////////////////////////////////////////////// // Recommendations /////////////////////////////////////////////////////////////////////////////////////////////// @IOLog @Profiled @Override public Recommendation alsoBoughtItems(Integer tenantId, String userId, String itemId, String itemType, String requestedItemType, Session session, Integer numberOfResults, Integer offset) throws EasyRecRestException { Recommendation rec; offset = CollectionUtils.getSafeOffset(offset); RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); Item i = itemDAO.get(remoteTenant, itemId, itemType); if (i != null) { if (i.isActive()) { if (logger.isDebugEnabled()) { logger.debug("<BOUGHT_SIMILAR@" + remoteTenant.getStringId() + "> " + (!Strings.isNullOrEmpty(userId) ? userId : "anonymous") + " requesting similar bought Items for " + itemType + " " + i.getDescription() + " (id:" + itemId + ")"); } Monitor monCore = MonitorFactory.start(JAMON_REST_ALSO_BOUGHT_CORE); RecommendationVO<Integer, String> recommendation = domainRecommenderService.alsoBoughtItems( tenantId, idMappingDAO.lookup(userId), session.getSessionId(), new ItemVO<>(tenantId, idMappingDAO.lookup(itemId), itemType), requestedItemType); monCore.stop(); List<Item> items = idMappingService.mapRecommendedItems(recommendation, remoteTenant, idMappingDAO.lookup(userId), session, numberOfResults, offset); rec = new Recommendation(remoteTenant.getStringId(), WS.ACTION_OTHER_USERS_ALSO_BOUGHT, userId, session.getSessionId(), i, items); } else { throw new EasyRecRestException(MSG.ITEM_NOT_ACTIVE); } } else { throw new EasyRecRestException(MSG.ITEM_NOT_EXISTS); } return rec; } @IOLog @Profiled @Override public Recommendation alsoViewedItems(Integer tenantId, String userId, String itemId, String itemType, String requestedItemType, Session session, Integer numberOfResults, Integer offset) throws EasyRecRestException { offset = CollectionUtils.getSafeOffset(offset); Recommendation rec; RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); Item i = itemDAO.get(remoteTenant, itemId, itemType); if (i != null) { if (i.isActive()) { if (logger.isDebugEnabled()) { logger.debug("<VIEW_SIMILAR@" + remoteTenant.getStringId() + "> " + (!Strings.isNullOrEmpty(userId) ? userId : "anonymous") + " requesting similar viewed Items for " + itemType + " " + i.getDescription() + " (id:" + itemId + ")"); } Monitor monCore = MonitorFactory.start(JAMON_REST_ALSO_VIEWED_CORE); RecommendationVO<Integer, String> recommendation = domainRecommenderService.alsoViewedItems( tenantId, idMappingDAO.lookup(userId), session.getSessionId(), new ItemVO<>(tenantId, idMappingDAO.lookup(itemId), itemType), requestedItemType); monCore.stop(); List<Item> items = idMappingService.mapRecommendedItems(recommendation, remoteTenant, idMappingDAO.lookup(userId), session, numberOfResults, offset); rec = new Recommendation(remoteTenant.getStringId(), WS.ACTION_OTHER_USERS_ALSO_VIEWED, userId, session.getSessionId(), i, items); } else { throw new EasyRecRestException(MSG.ITEM_NOT_ACTIVE); } } else { throw new EasyRecRestException(MSG.ITEM_NOT_EXISTS); } return rec; } @IOLog @Profiled @Override public Recommendation alsoGoodRatedItems(Integer tenantId, String userId, String itemId, String itemType, String requestedItemType, Session session, Integer numberOfResults, Integer offset) throws EasyRecRestException { Recommendation rec; offset = CollectionUtils.getSafeOffset(offset); RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); Item i = itemDAO.get(remoteTenant, itemId, itemType); if (i != null) { if (i.isActive()) { if (logger.isDebugEnabled()) { logger.debug("<ALSO_RATED_GOOD_SIMILAR@" + remoteTenant.getStringId() + "> " + (!Strings.isNullOrEmpty(userId) ? userId : "anonymous") + " requesting similar also good rated Items for " + itemType + " " + i.getDescription() + " (id:" + itemId + ")"); } Monitor monCore = MonitorFactory.start(JAMON_REST_ALSO_RATED_CORE); RecommendationVO<Integer, String> recommendation = domainRecommenderService.alsoGoodRatedItems( tenantId, idMappingDAO.lookup(userId), session.getSessionId(), new ItemVO<>(tenantId, idMappingDAO.lookup(itemId), itemType), requestedItemType); monCore.stop(); List<Item> items = idMappingService.mapRecommendedItems(recommendation, remoteTenant, idMappingDAO.lookup(userId), session, numberOfResults, offset); rec = new Recommendation(remoteTenant.getStringId(), WS.ACTION_ITEMS_RATED_GOOD_BY_OTHER_USERS, userId, session.getSessionId(), i, items); } else { throw new EasyRecRestException(MSG.ITEM_NOT_ACTIVE); } } else { throw new EasyRecRestException(MSG.ITEM_NOT_EXISTS); } return rec; } /////////////////////////////////////////////////////////////////////////////////////////////// // Rankings /////////////////////////////////////////////////////////////////////////////////////////////// @SuppressWarnings({ "unchecked" }) @IOLog @Profiled @Override public List<Item> mostBoughtItems(Integer tenantId, String itemType, Integer cluster, Integer numberOfResults, Integer offset, String timeRange, TimeConstraintVO constraint, Session session) { List<Item> items; offset = CollectionUtils.getSafeOffset(offset); RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); if (logger.isDebugEnabled()) { logger.debug("<MOST_BOUGHT@" + remoteTenant.getStringId() + "> " + " requesting most bought Items"); } if (timeRange == null) { timeRange = "ALL"; } // default timeRange String cacheKey = tenantId + WS.ACTION_MOST_BOUGHT + itemType + cluster + timeRange; Element e = cache.get(cacheKey); if ((e != null) && (!e.isExpired())) { items = itemService.filterDeactivatedItems((List<Item>) e.getValue()); return CollectionUtils.getSafeSubList(items, offset, numberOfResults); } if (constraint == null) constraint = new TimeConstraintVO(); adjustConstraint(constraint, TimeRange.getEnumFromString(timeRange)); Monitor monCore = MonitorFactory.start(JAMON_REST_MOST_BOUGHT_CORE); List<RankedItemVO<Integer, String>> rankedItems = domainActionService.mostBoughtItems(tenantId, itemType, cluster, WS.MAX_NUMBER_OF_RANKING_RESULTS, constraint, Boolean.TRUE); // filter invisible items Set<String> invisibleItemTypes = typeMappingService.getItemTypes(tenantId, false); if (invisibleItemTypes.size() > 0) { ListIterator<RankedItemVO<Integer, String>> iterator = rankedItems.listIterator(); while (iterator.hasNext()) { RankedItemVO<Integer, String> rankedItemVO = iterator.next(); if (invisibleItemTypes.contains(rankedItemVO.getItem().getType())) iterator.remove(); } } monCore.stop(); items = idMappingService.mapRankedItems(rankedItems, remoteTenant, session, WS.MAX_NUMBER_OF_RANKING_RESULTS, 0); cache.put(new Element(cacheKey, items)); return CollectionUtils.getSafeSubList(items, offset, numberOfResults); } @SuppressWarnings({ "unchecked" }) @IOLog @Profiled @Override public List<Item> mostViewedItems(Integer tenantId, String itemType, Integer cluster, Integer numberOfResults, Integer offset, String timeRange, TimeConstraintVO constraint, Session session) { List<Item> items; offset = CollectionUtils.getSafeOffset(offset); RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); if (logger.isDebugEnabled()) { logger.debug("<MOST_VIEWED@" + remoteTenant.getStringId() + "> " + " requesting most viewed Items"); } if (timeRange == null) { timeRange = "ALL"; } // default timeRange String cacheKey = tenantId + WS.ACTION_MOST_VIEWED + itemType + cluster + timeRange; Element e = cache.get(cacheKey); if ((e != null) && (!e.isExpired())) { logger.debug("most viewed - cache hit"); items = itemService.filterDeactivatedItems((List<Item>) e.getValue()); return CollectionUtils.getSafeSubList(items, offset, numberOfResults); } if (constraint == null) constraint = new TimeConstraintVO(); adjustConstraint(constraint, TimeRange.getEnumFromString(timeRange)); logger.debug("most viewed - cache miss - fetching new data from db"); Monitor monCore = MonitorFactory.start(JAMON_REST_MOST_VIEWED_CORE); List<RankedItemVO<Integer, String>> rankedItems = domainActionService.mostViewedItems(tenantId, itemType, cluster, WS.MAX_NUMBER_OF_RANKING_RESULTS, constraint, Boolean.TRUE); // filter invisible items Set<String> invisibleItemTypes = typeMappingService.getItemTypes(tenantId, false); if (invisibleItemTypes.size() > 0) { ListIterator<RankedItemVO<Integer, String>> iterator = rankedItems.listIterator(); while (iterator.hasNext()) { RankedItemVO<Integer, String> rankedItemVO = iterator.next(); if (invisibleItemTypes.contains(rankedItemVO.getItem().getType())) iterator.remove(); } } monCore.stop(); items = idMappingService.mapRankedItems(rankedItems, remoteTenant, session, WS.MAX_NUMBER_OF_RANKING_RESULTS, 0); cache.put(new Element(cacheKey, items)); return CollectionUtils.getSafeSubList(items, offset, numberOfResults); } @SuppressWarnings({ "unchecked" }) @IOLog @Profiled @Override public List<Item> mostRatedItems(Integer tenantId, String itemType, Integer cluster, Integer numberOfResults, Integer offset, String timeRange, TimeConstraintVO constraint, Session session) { List<Item> items; offset = CollectionUtils.getSafeOffset(offset); RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); if (logger.isDebugEnabled()) { logger.debug("<MOST_RATED@" + remoteTenant.getStringId() + "> " + " requesting most rated Items"); } if (timeRange == null) { timeRange = "ALL"; } // default timeRange String cacheKey = tenantId + WS.ACTION_MOST_RATED + itemType + cluster + timeRange; Element e = cache.get(cacheKey); if ((e != null) && (!e.isExpired())) { items = itemService.filterDeactivatedItems((List<Item>) e.getValue()); return CollectionUtils.getSafeSubList(items, offset, numberOfResults); } if (constraint == null) constraint = new TimeConstraintVO(); adjustConstraint(constraint, TimeRange.getEnumFromString(timeRange)); Monitor monCore = MonitorFactory.start(JAMON_REST_MOST_RATED_CORE); List<RankedItemVO<Integer, String>> rankedItems = domainActionService.mostRatedItems(tenantId, itemType, cluster, WS.MAX_NUMBER_OF_RANKING_RESULTS, constraint, Boolean.TRUE); // filter invisible items Set<String> invisibleItemTypes = typeMappingService.getItemTypes(tenantId, false); if (invisibleItemTypes.size() > 0) { ListIterator<RankedItemVO<Integer, String>> iterator = rankedItems.listIterator(); while (iterator.hasNext()) { RankedItemVO<Integer, String> rankedItemVO = iterator.next(); if (invisibleItemTypes.contains(rankedItemVO.getItem().getType())) iterator.remove(); } } monCore.stop(); items = idMappingService.mapRankedItems(rankedItems, remoteTenant, session, WS.MAX_NUMBER_OF_RANKING_RESULTS, 0); cache.put(new Element(cacheKey, items)); return CollectionUtils.getSafeSubList(items, offset, numberOfResults); } @Override public List<Item> itemsOfCluster(Integer tenant, String clusterName, Integer numberOfResults, Integer offset, String strategy, Boolean useFallback, Integer itemType, Session session) throws EasyRecRestException { List<Item> items; RemoteTenant remoteTenant = remoteTenantDAO.get(tenant); offset = CollectionUtils.getSafeOffset(offset); if (logger.isDebugEnabled()) logger.debug("<ITEMS_OF_CLUSTER@" + remoteTenant.getStringId() + "> " + " requesting items of cluster " + clusterName); logger.info("Use fallback: " + useFallback); ClusterVO cluster = clusterService.loadCluster(tenant, clusterName); if (cluster != null) { List<ItemVO<Integer, Integer>> clusterItems = clusterService.getItemsOfCluster(cluster, strategy, useFallback, numberOfResults, itemType); items = idMappingService.mapClusterItems(clusterItems, remoteTenant, session, WS.MAX_NUMBER_OF_RANKING_RESULTS, 0); return CollectionUtils.getSafeSubList(items, offset, numberOfResults); } else { throw new EasyRecRestException(MSG.CLUSTER_NOT_EXISTS); } } /////////////////////////////////////////////////////////////////////////////////////////////// // Ratings /////////////////////////////////////////////////////////////////////////////////////////////// @SuppressWarnings({ "unchecked" }) @IOLog @Profiled @Override public List<Item> worstRatedItems(Integer tenantId, String userId, String itemType, Integer numberOfResults, Integer offset, String timeRange, TimeConstraintVO constraint, Session session) { List<Item> items; offset = CollectionUtils.getSafeOffset(offset); RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); if (logger.isDebugEnabled()) { logger.debug("<WORST_RATED@" + remoteTenant.getStringId() + "> " + " requesting worst rated Items"); } if (timeRange == null) { timeRange = "ALL"; } // default timeRange if (userId == null) { Element e = cache.get(tenantId + WS.ACTION_WORST_RATED + itemType + timeRange); if ((e != null) && (!e.isExpired())) { items = itemService.filterDeactivatedItems((List<Item>) e.getValue()); return CollectionUtils.getSafeSubList(items, offset, numberOfResults); } if (constraint == null) constraint = new TimeConstraintVO(); adjustConstraint(constraint, TimeRange.getEnumFromString(timeRange)); } Monitor monCore = MonitorFactory.start(JAMON_REST_WORST_RATED_CORE); List<RatingVO<Integer, String>> ratedItems = domainActionService.badItemRatings(tenantId, idMappingDAO.lookup(userId), null, itemType, WS.MAX_NUMBER_OF_RANKING_RESULTS, constraint); // filter invisible items Set<String> invisibleItemTypes = typeMappingService.getItemTypes(tenantId, false); if (invisibleItemTypes.size() > 0) { ListIterator<RatingVO<Integer, String>> iterator = ratedItems.listIterator(); while (iterator.hasNext()) { RatingVO<Integer, String> ratingVO = iterator.next(); if (invisibleItemTypes.contains(ratingVO.getItem().getType())) iterator.remove(); } } monCore.stop(); items = idMappingService.mapRatedItems(ratedItems, remoteTenant, session, WS.MAX_NUMBER_OF_RANKING_RESULTS, 0); if ((userId == null)) cache.put(new Element(tenantId + WS.ACTION_WORST_RATED + itemType + timeRange, items)); return CollectionUtils.getSafeSubList(items, offset, numberOfResults); } @SuppressWarnings({ "unchecked" }) @IOLog @Profiled @Override public List<Item> bestRatedItems(Integer tenantId, String userId, String itemType, Integer numberOfResults, Integer offset, String timeRange, TimeConstraintVO constraint, Session session) { List<Item> items; offset = CollectionUtils.getSafeOffset(offset); RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); if (logger.isDebugEnabled()) { logger.debug("<BEST_RATED@" + remoteTenant.getStringId() + "> " + " requesting best rated Items"); } if (timeRange == null) { timeRange = "ALL"; } // default timeRange if (userId == null) { Element e = cache.get(tenantId + WS.ACTION_BEST_RATED + itemType + timeRange); if ((e != null) && (!e.isExpired())) { items = itemService.filterDeactivatedItems((List<Item>) e.getValue()); return CollectionUtils.getSafeSubList(items, offset, numberOfResults); } if (constraint == null) constraint = new TimeConstraintVO(); adjustConstraint(constraint, TimeRange.getEnumFromString(timeRange)); } Monitor monCore = MonitorFactory.start(JAMON_REST_BEST_RATED_CORE); List<RatingVO<Integer, String>> ratedItems = domainActionService.goodItemRatings(tenantId, idMappingDAO.lookup(userId), null, itemType, WS.MAX_NUMBER_OF_RANKING_RESULTS, constraint); // filter invisible items Set<String> invisibleItemTypes = typeMappingService.getItemTypes(tenantId, false); if (invisibleItemTypes.size() > 0) { ListIterator<RatingVO<Integer, String>> iterator = ratedItems.listIterator(); while (iterator.hasNext()) { RatingVO<Integer, String> ratingVO = iterator.next(); if (invisibleItemTypes.contains(ratingVO.getItem().getType())) iterator.remove(); } } monCore.stop(); items = idMappingService.mapRatedItems(ratedItems, remoteTenant, session, WS.MAX_NUMBER_OF_RANKING_RESULTS, 0); if ((userId == null)) cache.put(new Element(tenantId + WS.ACTION_BEST_RATED + itemType + timeRange, items)); return CollectionUtils.getSafeSubList(items, offset, numberOfResults); } /////////////////////////////////////////////////////////////////////////////////////////////// // Recommendations /////////////////////////////////////////////////////////////////////////////////////////////// @IOLog @Profiled @Override public RecommendedItem[] itemsBasedOnPurchaseHistory(Integer tenantId, String userId, String sessionId, String consideredItemType, Integer numberOfLastActionsConsidered, String assocType, String requestedItemType) throws EasyRecRestException { RecommendationVO<Integer, String> recommendation = domainRecommenderService.itemsBasedOnPurchaseHistory( tenantId, idMappingDAO.lookup(userId), sessionId, consideredItemType, numberOfLastActionsConsidered, assocType, requestedItemType); List<RecommendedItem> recommendedItems = idMappingService .convertListOfRecommendedItemVOs(recommendation.getRecommendedItems()); if (recommendedItems != null && recommendedItems.size() > 0) { return recommendedItems.toArray(new RecommendedItem[recommendedItems.size()]); } else { return new RecommendedItem[0]; } } @IOLog @Profiled @Override public Recommendation itemsBasedOnViewingHistory(Integer tenantId, String userId, Session session, String consideredItemType, Integer numberOfLastActionsConsidered, String assocType, String requestedItemType, Integer numberOfRecommendations) throws EasyRecRestException { Recommendation rec; RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); Monitor monCore = MonitorFactory.start(JAMON_REST_RECS_FOR_USER); RecommendationVO<Integer, String> recommendation = domainRecommenderService.itemsBasedOnViewingHistory( tenantId, idMappingDAO.lookup(userId), null, // no sessionId needed consideredItemType, numberOfLastActionsConsidered, assocType, requestedItemType); monCore.stop(); List<Item> items = idMappingService.mapRecommendedItems(recommendation, remoteTenant, idMappingDAO.lookup(userId), session, // session needed for building backtracking url (session.getRequest()), numberOfRecommendations, 0); // offset = 0 rec = new Recommendation(remoteTenant.getStringId(), WS.ACTION_RECOMMENDATIONS_FOR_USER, userId, null, // no sessionId needed null, // no base item needed items); return rec; } @IOLog @Profiled @Override public Recommendation actionHistory(Integer tenantId, String userId, Session session, String consideredActionType, String consideredItemType, Integer numberOfLastActionsConsidered, Integer numberOfRecommendations, Integer offset) throws EasyRecRestException { Recommendation rec; RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); offset = CollectionUtils.getSafeOffset(offset); Monitor monCore = MonitorFactory.start(JAMON_REST_ACTION_HISTORY_CORE); List<ItemVO<Integer, String>> recommendation = domainRecommenderService.getActionHistory(tenantId, idMappingDAO.lookup(userId), null, consideredActionType, consideredItemType, null, numberOfLastActionsConsidered); monCore.stop(); List<Item> items = idMappingService.mapListOfItemVOs(recommendation, remoteTenant, idMappingDAO.lookup(userId), session, numberOfRecommendations, offset); rec = new Recommendation(remoteTenant.getStringId(), WS.ACTION_HISTORY, userId, null, // no sessionId needed null, // no base item needed items); return rec; } @IOLog @Profiled @Override public Recommendation itemsBasedOnActionHistory(Integer tenantId, String userId, Session session, String consideredActionType, String consideredItemType, Integer numberOfLastActionsConsidered, String assocType, String requestedItemType, Integer numberOfRecommendations, Integer offset) throws EasyRecRestException { Recommendation rec; RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); offset = CollectionUtils.getSafeOffset(offset); Double ratingThreshold = null; if (consideredActionType.equals(TypeMappingService.ACTION_TYPE_RATE)) { ratingThreshold = tenantService.getTenantById(tenantId).getRatingRangeNeutral(); } Monitor monCore = MonitorFactory.start(JAMON_REST_RECS_FOR_USER); RecommendationVO<Integer, String> recommendation = domainRecommenderService.getItemsBasedOnActionHistory( tenantId, idMappingDAO.lookup(userId), null, // no sessionId needed consideredActionType, consideredItemType, ratingThreshold, numberOfLastActionsConsidered, assocType, requestedItemType); monCore.stop(); List<Item> items = idMappingService.mapRecommendedItems(recommendation, remoteTenant, idMappingDAO.lookup(userId), session, numberOfRecommendations, offset); // session needed for building backtracking url (session // .getRequest()) rec = new Recommendation(remoteTenant.getStringId(), WS.ACTION_RECOMMENDATIONS_FOR_USER, userId, null, // no sessionId needed null, // no base item needed items); return rec; } @IOLog @Profiled @Override public Recommendation itemsForUser(Integer tenantId, String userId, Session session, String consideredActionType, String consideredItemType, Integer numberOfLastActionsConsidered, String assocType, String requestedItemType, Integer numberOfRecommendations, Integer offset) throws EasyRecRestException { Recommendation rec = null; RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); // double check: should have been checked before if (remoteTenant.getPluginsEnabled()) { //TODO: add sourceType to query!!! (dm: copy paste from relatedItems - refactor shared code ?) RecommendationVO<Integer, String> recommendation = domainRecommenderService.getAlsoActedItems(tenantId, idMappingDAO.lookup(userId), session.getSessionId(), AssocTypeDAO.ASSOCTYPE_USER_TO_ITEM, new ItemVO<>(tenantId, idMappingDAO.lookup(userId), TypeMappingService.ITEM_TYPE_USER), null, requestedItemType); List<Item> items = idMappingService.mapRecommendedItems(recommendation, remoteTenant, idMappingDAO.lookup(userId), session, numberOfRecommendations, offset); rec = new Recommendation(remoteTenant.getStringId(), WS.ACTION_RECOMMENDATIONS_FOR_USER, userId, null, null, items); } return rec; } @IOLog @Profiled @Override public RecommendedItem[] itemsBasedOnSearchingHistory(Integer tenantId, String userId, String sessionId, String consideredItemType, Integer numberOfLastActionsConsidered, String assocType, String requestedItemType) throws EasyRecRestException { RecommendationVO<Integer, String> recommendation = domainRecommenderService.itemsBasedOnSearchingHistory( tenantId, idMappingDAO.lookup(userId), sessionId, consideredItemType, numberOfLastActionsConsidered, assocType, requestedItemType); List<RecommendedItem> recommendedItems = idMappingService .convertListOfRecommendedItemVOs(recommendation.getRecommendedItems()); if (recommendedItems != null && recommendedItems.size() > 0) { return recommendedItems.toArray(new RecommendedItem[recommendedItems.size()]); } else { return new RecommendedItem[0]; } } /////////////////////////////////////////////////////////////////////////////////////////////// // Plugin supported methods /////////////////////////////////////////////////////////////////////////////////////////////// @Override public Recommendation relatedItems(Integer tenantId, String assocType, String userId, String itemId, String itemType, String requestedItemType, Session session, Integer numberOfResults, Integer offset) throws EasyRecRestException { Recommendation rec = null; offset = CollectionUtils.getSafeOffset(offset); RemoteTenant remoteTenant = remoteTenantDAO.get(tenantId); Item i = null; if (!"USER".equals(itemType)) { i = itemDAO.get(remoteTenant, itemId, itemType); if (i == null) throw new EasyRecRestException(MSG.ITEM_NOT_EXISTS); if (!i.isActive()) throw new EasyRecRestException(MSG.ITEM_NOT_ACTIVE); } else { //create dummy item for User i = new Item(null, tenantId, itemId, itemType, "user id " + itemId, null, null, null, true, null); } // double check: should have been checked before if (remoteTenant.getPluginsEnabled()) { //TODO: add sourceType to query!!! RecommendationVO<Integer, String> recommendation = domainRecommenderService.getAlsoActedItems(tenantId, idMappingDAO.lookup(userId), session.getSessionId(), assocType, new ItemVO<>(tenantId, idMappingDAO.lookup(itemId), itemType), null, requestedItemType); List<Item> items = idMappingService.mapRecommendedItems(recommendation, remoteTenant, idMappingDAO.lookup(userId), session, numberOfResults, offset); rec = new Recommendation(remoteTenant.getStringId(), WS.ACTION_RELATED_ITEMS, userId, session.getSessionId(), i, items); } return rec; } /////////////////////////////////////////////////////////////////////////////////////////////// // Utility Methods /////////////////////////////////////////////////////////////////////////////////////////////// @IOLog @Profiled @Override public String[] getAssocTypes(Integer tenantId) throws EasyRecRestException { return typeMappingService.getAssocTypes(tenantId) .toArray(new String[typeMappingService.getAssocTypes(tenantId).size()]); } @IOLog @Profiled @Override public Set<String> getItemTypes(Integer tenantId) throws EasyRecRestException { return typeMappingService.getItemTypes(tenantId, true); } @IOLog @Profiled @Override public List<ClusterVO> getClusters(Integer tenantId) throws EasyRecRestException { return Lists.newArrayList(clusterService.getClustersForTenant(tenantId).getVertices()); } @IOLog @Profiled @Override public List<ItemAssocVO<String, String>> getRules(Integer tenantId) { List<ItemAssocVO<String, String>> rules; List<ItemAssocVO<Integer, String>> itemAssocs = domainItemAssocService.getItemAssocsFromTenant(tenantId, 2000); rules = idMappingService.mapItemAssocs(itemAssocs, true); return rules; } @IOLog @Profiled @Override public List<ItemAssocVO<String, String>> getRules(Item item) { List<ItemAssocVO<String, String>> rules; ItemVO<Integer, String> itemFrom = new ItemVO<>(item.getTenantId(), idMappingDAO.lookup(item.getItemId()), item.getItemType()); List<ItemAssocVO<Integer, String>> itemAssocs = domainItemAssocService .getItemAssocsForItem(item.getTenantId(), itemFrom, 200); rules = idMappingService.mapItemAssocs(itemAssocs, true); return rules; } /* @IOLog @Profiled public String getProfile(Integer tenantId, String itemId, String itemType) throws ShopRecommenderException { return profileService.getProfile(tenantId, idMappingDAO.lookup(itemId), itemType); } @IOLog @Profiled public String[] getSimilarProfiles(Integer tenantId, String itemId, String itemType) throws ShopRecommenderException { ItemVO<Integer, String> item2 = new ItemVO<Integer, String>(tenantId, idMappingDAO.lookup("1"), itemType); profileMatcherService.match(new ItemVO<Integer, String>(tenantId, idMappingDAO.lookup(itemId), itemType), item2); return new String[0]; } @IOLog @Profiled public void storeProfile(Integer tenantId, String itemId, String itemType, String profileXML) throws ShopRecommenderException { profileService.storeProfile(tenantId, idMappingDAO.lookup(itemId), itemType, profileXML, true); } */ /////////////////////////////////////////////////////////////////////////////////////////////// // Profile aware Methods /////////////////////////////////////////////////////////////////////////////////////////////// // private methods private void adjustConstraint(TimeConstraintVO constraint, TimeRange timeRange) { Calendar cal = Calendar.getInstance(); Date end = cal.getTime(); Date start = null; switch (timeRange) { case DAY: cal.setTimeInMillis(end.getTime() - 86400000); start = cal.getTime(); break; case WEEK: cal.setTimeInMillis(end.getTime() - 604800000); start = cal.getTime(); break; case MONTH: cal.add(Calendar.MONTH, -1); start = cal.getTime(); break; case ALL: //start = null; break; } constraint.setDateFrom(start); constraint.setDateTo(end); } // getter/setter @SuppressWarnings({ "UnusedDeclaration" }) public DomainRecommenderService getDomainRecommenderService() { return domainRecommenderService; } public void setDomainRecommenderService(DomainRecommenderService domainRecommenderService) { this.domainRecommenderService = domainRecommenderService; } @SuppressWarnings({ "UnusedDeclaration" }) public DomainActionService getDomainActionService() { return domainActionService; } public void setDomainActionService(DomainActionService domainActionService) { this.domainActionService = domainActionService; } @SuppressWarnings({ "UnusedDeclaration" }) public DomainItemAssocService getDomainItemAssocService() { return domainItemAssocService; } public void setDomainItemAssocService(DomainItemAssocService domainItemAssocService) { this.domainItemAssocService = domainItemAssocService; } @SuppressWarnings({ "UnusedDeclaration" }) public TypeMappingService getTypeMappingService() { return typeMappingService; } public void setTypeMappingService(TypeMappingService typeMappingService) { this.typeMappingService = typeMappingService; } @SuppressWarnings({ "UnusedDeclaration" }) public IDMappingDAO getIdMappingDAO() { return idMappingDAO; } public void setIdMappingDAO(IDMappingDAO idMappingDAO) { this.idMappingDAO = idMappingDAO; } @SuppressWarnings({ "UnusedDeclaration" }) public IDMappingService getIdMappingService() { return idMappingService; } public void setIdMappingService(IDMappingService idMappingService) { this.idMappingService = idMappingService; } @SuppressWarnings({ "UnusedDeclaration" }) public ItemDAO getItemDAO() { return itemDAO; } public void setItemDAO(ItemDAO itemDAO) { this.itemDAO = itemDAO; } @SuppressWarnings({ "UnusedDeclaration" }) public RemoteTenantDAO getRemoteTenantDAO() { return remoteTenantDAO; } public void setRemoteTenantDAO(RemoteTenantDAO remoteTenantDAO) { this.remoteTenantDAO = remoteTenantDAO; } @SuppressWarnings({ "UnusedDeclaration" }) public ProfileService getProfileService() { return profileService; } @SuppressWarnings({ "UnusedDeclaration" }) public void setProfileService(ProfileService profileService) { this.profileService = profileService; } public void setItemService(ItemService itemService) { this.itemService = itemService; } public void setCache(Cache cache) { this.cache = cache; } @Override public void emptyCache() { cache.removeAll(); } public ClusterService getClusterService() { return clusterService; } public void setClusterService(ClusterService clusterService) { this.clusterService = clusterService; } public TenantService getTenantService() { return tenantService; } public void setTenantService(TenantService tenantService) { this.tenantService = tenantService; } }