PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/core/src/main/java/org/yes/cart/service/domain/impl/ProductServiceImpl.java

http://yes-cart.googlecode.com/
Java | 527 lines | 329 code | 73 blank | 125 comment | 37 complexity | 69074275abd3978df0f12579ab64f304 MD5 | raw file
  1. package org.yes.cart.service.domain.impl;
  2. import org.apache.lucene.search.Query;
  3. import org.hibernate.criterion.Criterion;
  4. import org.hibernate.criterion.MatchMode;
  5. import org.hibernate.criterion.Restrictions;
  6. import org.springframework.util.CollectionUtils;
  7. import org.yes.cart.cache.Cacheable;
  8. import org.yes.cart.dao.GenericDAO;
  9. import org.yes.cart.domain.entity.*;
  10. import org.yes.cart.domain.misc.Pair;
  11. import org.yes.cart.domain.misc.navigation.range.RangeList;
  12. import org.yes.cart.domain.misc.navigation.range.RangeNode;
  13. import org.yes.cart.domain.queryobject.FiteredNavigationRecord;
  14. import org.yes.cart.domain.queryobject.impl.FiteredNavigationRecordImpl;
  15. import org.yes.cart.service.domain.ProductService;
  16. import java.math.BigDecimal;
  17. import java.util.*;
  18. /**
  19. * User: Igor Azarny iazarny@yahoo.com
  20. * Date: 09-May-2011
  21. * Time: 14:12:54
  22. */
  23. public class ProductServiceImpl extends BaseGenericServiceImpl<Product> implements ProductService {
  24. private final static String PROD_SERV_METHOD_CACHE = "productServiceImplMethodCache";
  25. private final GenericDAO<Product, Long> productDao;
  26. private final GenericDAO<ProductSku, Long> productSkuDao;
  27. private final GenericDAO<ProductType, Long> productTypeDao;
  28. private final Random rand;
  29. public ProductServiceImpl(final GenericDAO<Product, Long> productDao,
  30. final GenericDAO<ProductSku, Long> productSkuDao,
  31. final GenericDAO<ProductType, Long> productTypeDao) {
  32. super(productDao);
  33. this.productDao = productDao;
  34. this.productSkuDao = productSkuDao;
  35. this.productTypeDao = productTypeDao;
  36. rand = new Random();
  37. rand.setSeed((new Date().getTime()));
  38. }
  39. /**
  40. * Persist product. Default sku will be created.
  41. *
  42. * @param instance instance to persist
  43. * @return persisted instanse
  44. */
  45. public Product create(final Product instance) {
  46. ProductSku sku = productDao.getEntityFactory().getByIface(ProductSku.class);
  47. sku.setCode(instance.getCode());
  48. sku.setName(instance.getName());
  49. sku.setDescription(instance.getDescription());
  50. sku.setProduct(instance);
  51. instance.getSku().add(sku);
  52. return getGenericDao().create(instance);
  53. }
  54. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  55. public Product getById(final Long productId) {
  56. return productDao.findById(productId);
  57. }
  58. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  59. public ProductSku getSkuById(final Long skuId) {
  60. return productSkuDao.findById(skuId);
  61. }
  62. /**
  63. * {@inheritDoc}
  64. */
  65. public List<Product> getProductByCategory(final long categoryId) {
  66. return productDao.findByNamedQuery("PRODUCTS.BY.CATEGORYID", categoryId, new Date());
  67. }
  68. /**
  69. * {@inheritDoc}
  70. */
  71. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  72. public Product getRandomProductByCategory(final Category category) {
  73. if (!category.getProductCategory().isEmpty()) {
  74. int idx = rand.nextInt(category.getProductCategory().size());
  75. ProductCategory productCategory = (ProductCategory) category.getProductCategory().toArray()[idx];
  76. return getById(productCategory.getProduct().getProductId());
  77. }
  78. return null;
  79. }
  80. /**
  81. * Get the grouped product attributes, with values.
  82. *
  83. * @param attributable product or sku
  84. * @param productTypeId product type id
  85. * @return List of pair group names - list of attribute name and value.
  86. */
  87. public List<Pair<String, List<AttrValue>>> getProductAttributes(final Attributable attributable, final long productTypeId) {
  88. final ProductType productType = productTypeDao.findById(productTypeId);
  89. final Collection<ProdTypeAttributeViewGroup> attributeViewGroup = productType.getAttributeViewGroup();
  90. final List<Pair<String, List<AttrValue>>> attributesToShow =
  91. new ArrayList<Pair<String, List<AttrValue>>>(attributeViewGroup.size());
  92. Collection<AttrValue> attrValues = attributable.getAllAttibutes();
  93. for (ProdTypeAttributeViewGroup viewGroup : attributeViewGroup) {
  94. final List<AttrValue> attrNameValues = getProductAttributeValues(attrValues, viewGroup);
  95. attributesToShow.add(
  96. new Pair<String, List<AttrValue>>(
  97. viewGroup.getAttributeViewGroup().getName(),
  98. attrNameValues)
  99. );
  100. }
  101. return attributesToShow;
  102. }
  103. private List<AttrValue> getProductAttributeValues(
  104. final Collection<AttrValue> attrValueCollection,
  105. final ProdTypeAttributeViewGroup viewGroup) {
  106. final String[] attributesNames = viewGroup.getAttrCodeList().split(",");
  107. final List<AttrValue> attrNameValues = new ArrayList<AttrValue>(attributesNames.length);
  108. for (String attrName : attributesNames) {
  109. for (AttrValue attrValue : attrValueCollection) {
  110. final String candidatCode = attrValue.getAttribute().getCode();
  111. if (candidatCode.equals(attrName) || candidatCode.equals("SKU" + attrName)) {
  112. attrNameValues.add(attrValue);
  113. }
  114. }
  115. }
  116. return attrNameValues;
  117. }
  118. /**
  119. * {@inheritDoc}
  120. */
  121. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  122. public ProductSku getProductSkuByCode(final String skuCode) {
  123. final List<ProductSku> skus = productSkuDao.findByNamedQuery("PRODUCT.SKU.BY.CODE", skuCode);
  124. if (CollectionUtils.isEmpty(skus)) {
  125. return null;
  126. //throw new ObjectNotFoundException(ProductSku.class, "skuCode", skuCode);
  127. }
  128. return skus.get(0);
  129. }
  130. /**
  131. * Get product by sku code.
  132. *
  133. * @param skuCode sku code
  134. * @return product sku for this sku code
  135. */
  136. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  137. public Product getProductBySkuCode(final String skuCode) {
  138. return (Product) productDao.getScalarResultByNamedQuery("PRODUCT.BY.SKU.CODE", skuCode);
  139. }
  140. /**
  141. * {@inheritDoc}
  142. */
  143. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  144. public Product getProductById(final Long productId) {
  145. return productDao.findById(productId);
  146. }
  147. /**
  148. * {@inheritDoc}
  149. */
  150. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  151. public List<Product> getProductByQuery(
  152. final Query query,
  153. final int firtsResult,
  154. final int maxResults) {
  155. return productDao.fullTextSearch(query, firtsResult, maxResults);
  156. }
  157. /**
  158. * {@inheritDoc}
  159. */
  160. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  161. public List<Product> getFeaturedProducts(final Collection categories, final int limit) {
  162. List<Product> list = productDao.findQueryObjectsByNamedQueryWithList(
  163. "PRODUCT.FEATURED",
  164. categories,
  165. new Date()); //TODO v2 time machine
  166. Collections.shuffle(list);
  167. int toIndex = limit; //to index exclusive
  168. if (list.size() < limit) {
  169. toIndex = list.size();
  170. }
  171. if (toIndex < 0) {
  172. toIndex = 0;
  173. }
  174. return new ArrayList<Product>(list.subList(0, toIndex));
  175. }
  176. /**
  177. * {@inheritDoc}
  178. */
  179. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  180. public List<Product> getNewArrivalsProductInCategory(
  181. final long categoryId,
  182. final int maxResults) {
  183. return productDao.findRangeByNamedQuery("NEW.PRODUCTS.IN.CATEGORYID",
  184. 0,
  185. maxResults,
  186. categoryId,
  187. new Date() //TODO time machine
  188. );
  189. }
  190. /**
  191. * {@inheritDoc}
  192. */
  193. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  194. public List<Product> getProductByQuery(
  195. final Query query,
  196. final int firtsResult,
  197. final int maxResults,
  198. final String sortFieldName,
  199. final boolean reverse) {
  200. return productDao.fullTextSearch(query, firtsResult, maxResults, sortFieldName, reverse);
  201. }
  202. /**
  203. * {@inheritDoc}
  204. */
  205. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  206. public int getProductQty(final Query query) {
  207. return productDao.getResultCount(query);
  208. }
  209. /**
  210. * {@inheritDoc}
  211. */
  212. public List<Product> getProductByCategory(
  213. final long categoryId,
  214. final int firtsResult,
  215. final int maxResults) {
  216. return productDao.findRangeByNamedQuery("PRODUCTS.BY.CATEGORYID",
  217. firtsResult,
  218. maxResults,
  219. categoryId,
  220. new Date() //TODO time machine
  221. );
  222. }
  223. /**
  224. * {@inheritDoc}
  225. */
  226. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  227. public List<Object> getDistinctAttributeValues(final long productTypeId, final String code) {
  228. return productDao.findQueryObjectByNamedQuery(
  229. "PRODUCTS.ATTRIBUTE.VALUES.BY.CODE.PRODUCTTYPEID",
  230. productTypeId,
  231. code);
  232. }
  233. /**
  234. * {@inheritDoc}
  235. */
  236. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  237. public List<Product> getProductByIdList(final List idList) {
  238. if (idList == null || idList.isEmpty()){
  239. return Collections.EMPTY_LIST;
  240. }
  241. return productDao.findQueryObjectsByNamedQueryWithList("PRODUCTS.LIST.BY.IDS", idList, null);
  242. }
  243. /**
  244. * {@inheritDoc}
  245. */
  246. public List<FiteredNavigationRecord> getDistinctBrands(final List categories) {
  247. List<Object[]> list = productDao.findQueryObjectsByNamedQueryWithList(
  248. "PRODUCTS.ATTR.CODE.VALUES.BY.ASSIGNED.CATEGORIES",
  249. categories);
  250. return constructBrandFilteredNavigationRecords(list);
  251. }
  252. /**
  253. * Get the ranked by ProductTypeAttr.rank list of unique product attribute values by given product type
  254. * and attribute code.
  255. *
  256. * @param productTypeId product type id
  257. * @return list of distinct attib values
  258. */
  259. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  260. public List<FiteredNavigationRecord> getDistinctAttributeValues(final long productTypeId) {
  261. final List<FiteredNavigationRecord> records = new ArrayList<FiteredNavigationRecord>();
  262. records.addAll(getSingleValueNavigationRecords(productTypeId));
  263. records.addAll(getRangeValueNavigationRecords(productTypeId));
  264. Collections.sort(
  265. records,
  266. new Comparator<FiteredNavigationRecord>() {
  267. public int compare(final FiteredNavigationRecord record1, final FiteredNavigationRecord record2) {
  268. int rez = record1.getRank() - record2.getRank();
  269. if (rez == 0) {
  270. rez = record1.getName().compareTo(record2.getName());
  271. if (rez == 0) {
  272. rez = record1.getValue().compareTo(record2.getValue());
  273. }
  274. }
  275. return rez;
  276. }
  277. });
  278. return records;
  279. }
  280. /**
  281. * Get the navigation records for range values.
  282. *
  283. * @param productTypeId product type id
  284. * @return list of {@link FiteredNavigationRecord}
  285. */
  286. private List<FiteredNavigationRecord> getRangeValueNavigationRecords(final long productTypeId) {
  287. final ProductType productType = productTypeDao.findById(productTypeId);
  288. final List<FiteredNavigationRecord> records = new ArrayList<FiteredNavigationRecord>();
  289. for (ProductTypeAttr entry : productType.getAttribute()) {
  290. if (entry.getNavigationType().equals("R")) {
  291. RangeList<RangeNode> rangeList = entry.getRangeList();
  292. if (rangeList != null) {
  293. for (RangeNode node : rangeList) {
  294. records.add(
  295. new FiteredNavigationRecordImpl(
  296. entry.getAttribute().getName(),
  297. entry.getAttribute().getCode(),
  298. node.getRange().getFirst() + '-' + node.getRange().getSecond(),
  299. node.getRange().getFirst() + '-' + node.getRange().getSecond(),
  300. 0,
  301. entry.getRank(),
  302. "R"
  303. )
  304. );
  305. }
  306. }
  307. }
  308. }
  309. return records;
  310. }
  311. /**
  312. * Construct filtered navigation records.
  313. *
  314. * @param list of raw object arrays after, result of named query
  315. * @return constructed list of navigation records.
  316. */
  317. private List<FiteredNavigationRecord> constructFilteredNavigationRecords(final List<Object[]> list) {
  318. List<FiteredNavigationRecord> result = new ArrayList<FiteredNavigationRecord>(list.size());
  319. for (Object[] objArray : list) {
  320. result.add(
  321. new FiteredNavigationRecordImpl(
  322. (String) objArray[0],
  323. (String) objArray[1],
  324. (String) objArray[2],
  325. (String) objArray[3],
  326. (Integer) objArray[4],
  327. (Integer) objArray[5],
  328. "S"
  329. )
  330. );
  331. }
  332. return result;
  333. }
  334. /**
  335. * Collect the single attribute value navigation see ProductTypeAttr#navigationType
  336. *
  337. * @param productTypeId product type id
  338. * @return list of {@link FiteredNavigationRecord}
  339. */
  340. private List<FiteredNavigationRecord> getSingleValueNavigationRecords(final long productTypeId) {
  341. List<Object[]> list = productDao.findQueryObjectsByNamedQuery(
  342. "PRODUCTS.ATTR.CODE.VALUES.BY.PRODUCTTYPEID",
  343. productTypeId);
  344. return constructFilteredNavigationRecords(list);
  345. }
  346. /**
  347. * Construct filtered navigation records.
  348. *
  349. * @param list of raw object arrays after, result of named query
  350. * @return constructed list of navigation records.
  351. */
  352. private List<FiteredNavigationRecord> constructBrandFilteredNavigationRecords(final List<Object[]> list) {
  353. List<FiteredNavigationRecord> result = new ArrayList<FiteredNavigationRecord>(list.size());
  354. for (Object[] objArray : list) {
  355. result.add(
  356. new FiteredNavigationRecordImpl(
  357. (String) objArray[0],
  358. (String) objArray[1],
  359. (String) objArray[2],
  360. (Integer) objArray[3]
  361. )
  362. );
  363. }
  364. return result;
  365. }
  366. /**
  367. * {@inheritDoc}
  368. */
  369. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  370. public Long getProductIdBySeoUri(final String seoUri) {
  371. List<Product> list = productDao.findByNamedQuery("PRODUCT.BY.SEO.URI", seoUri);
  372. if (list != null && !list.isEmpty()) {
  373. return list.get(0).getProductId();
  374. }
  375. return null;
  376. }
  377. /**
  378. * {@inheritDoc}
  379. */
  380. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  381. public Long getProductSkuIdBySeoUri(final String seoUri) {
  382. List<ProductSku> list = productSkuDao.findByNamedQuery("SKU.BY.SEO.URI", seoUri);
  383. if (list != null && !list.isEmpty()) {
  384. return list.get(0).getSkuId();
  385. }
  386. return null;
  387. }
  388. /**
  389. * {@inheritDoc}
  390. */
  391. @Cacheable(value = PROD_SERV_METHOD_CACHE)
  392. public int getProductQty(final long categoryId) {
  393. return Integer.valueOf(
  394. String.valueOf(productDao.getScalarResultByNamedQuery("PRODUCTS.QTY.BY.CATEGORYID", categoryId, new Date())));
  395. }
  396. /**
  397. * {@inheritDoc}
  398. */
  399. public int reindexProducts() {
  400. return productDao.fullTextSearchReindex();
  401. }
  402. /**
  403. * {@inheritDoc}
  404. */
  405. public int reindexProduct(final Long pk) {
  406. return productDao.fullTextSearchReindex(pk);
  407. }
  408. /**
  409. * Get the total quantity of product skus on all warehouses.
  410. *
  411. * @param product product
  412. * @return quantity of product.
  413. */
  414. public BigDecimal getProductQuantity(final Product product) {
  415. return productDao.findSingleByNamedQuery("SKU.QTY.BY.PRODUCT", product);
  416. }
  417. /**
  418. * {@inheritDoc}
  419. */
  420. public BigDecimal getProductQuantity(final Product product, final Shop shop) {
  421. return productDao.findSingleByNamedQuery("SKU.QTY.BY.PRODUCT.SHOP", product, shop);
  422. }
  423. /**
  424. * {@inheritDoc}
  425. */
  426. public void clearEmptyAttributes() {
  427. productDao.executeNativeUpdate("DELETE FROM TPRODUCTATTRVALUE WHERE VAL IS NULL OR VAL =''");
  428. }
  429. /**
  430. * {@inheritDoc}
  431. */
  432. public List<Product> getProductByConeNameBrandType(
  433. final String code,
  434. final String name,
  435. final Long brandId,
  436. final Long productTypeId) {
  437. final List<Criterion> criterionList = new ArrayList<Criterion>();
  438. if (code != null) {
  439. criterionList.add(Restrictions.like("code", code, MatchMode.ANYWHERE));
  440. }
  441. if (name != null) {
  442. criterionList.add(Restrictions.like("name", name, MatchMode.ANYWHERE));
  443. }
  444. if (brandId != null) {
  445. criterionList.add(Restrictions.eq("brand.brandId", brandId));
  446. }
  447. if (productTypeId != null) {
  448. criterionList.add(Restrictions.eq("producttype.producttypeId", productTypeId));
  449. }
  450. return productDao.findByCriteria(
  451. criterionList.toArray(new Criterion[criterionList.size()])
  452. );
  453. }
  454. }