package com.salesmanager.core.business.modules.cms.product.infinispan; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.net.FileNameMap; import java.net.URLConnection; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.commons.io.IOUtils; import org.infinispan.tree.Fqn; import org.infinispan.tree.Node; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.salesmanager.core.business.constants.Constants; import com.salesmanager.core.business.exception.ServiceException; import com.salesmanager.core.business.modules.cms.impl.CacheManager; import com.salesmanager.core.business.modules.cms.product.ProductImageGet; import com.salesmanager.core.business.modules.cms.product.ProductImagePut; import com.salesmanager.core.business.modules.cms.product.ProductImageRemove; import com.salesmanager.core.model.catalog.product.Product; import com.salesmanager.core.model.catalog.product.file.ProductImageSize; import com.salesmanager.core.model.catalog.product.image.ProductImage; import com.salesmanager.core.model.content.FileContentType; import com.salesmanager.core.model.content.ImageContentFile; import com.salesmanager.core.model.content.OutputContentFile; import com.salesmanager.core.model.merchant.MerchantStore; /** * Manager for storing in retrieving image files from the CMS This is a layer on top of Infinispan * https://docs.jboss.org/author/display/ISPN/Tree+API+Module * * Manages * - Product images * @author Carl Samson */ public class CmsImageFileManagerImpl implements ProductImagePut, ProductImageGet, ProductImageRemove { private static final Logger LOGGER = LoggerFactory.getLogger( CmsImageFileManagerImpl.class ); private static CmsImageFileManagerImpl fileManager = null; private final static String ROOT_NAME = "product-merchant"; private final static String SMALL = "SMALL"; private final static String LARGE = "LARGE"; private String rootName = ROOT_NAME; private CacheManager cacheManager; /** * Requires to stop the engine when image servlet un-deploys */ public void stopFileManager() { try { cacheManager.getManager().stop(); LOGGER.info( "Stopping CMS" ); } catch ( Exception e ) { LOGGER.error( "Error while stopping CmsImageFileManager", e ); } } public static CmsImageFileManagerImpl getInstance() { if ( fileManager == null ) { fileManager = new CmsImageFileManagerImpl(); } return fileManager; } private CmsImageFileManagerImpl() { } /** * root -productFiles -merchant-id PRODUCT-ID(key) -> CacheAttribute(value) - image 1 - image 2 - image 3 */ @Override public void addProductImage( ProductImage productImage, ImageContentFile contentImage ) throws ServiceException { if ( cacheManager.getTreeCache() == null ) { throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" ); } try { // node StringBuilder nodePath = new StringBuilder(); nodePath.append(productImage.getProduct().getMerchantStore().getCode()).append(Constants.SLASH).append(productImage.getProduct().getSku()).append(Constants.SLASH); if(contentImage.getFileContentType().name().equals(FileContentType.PRODUCT.name())) { nodePath.append(SMALL); } else if(contentImage.getFileContentType().name().equals(FileContentType.PRODUCTLG.name())) { nodePath.append(LARGE); } Node<String, Object> productNode = this.getNode(nodePath.toString()); InputStream isFile = contentImage.getFile(); ByteArrayOutputStream output = new ByteArrayOutputStream(); IOUtils.copy( isFile, output ); // object for a given product containing all images productNode.put(contentImage.getFileName(), output.toByteArray()); } catch ( Exception e ) { throw new ServiceException( e ); } } @Override public OutputContentFile getProductImage( ProductImage productImage ) throws ServiceException { return getProductImage(productImage.getProduct().getMerchantStore().getCode(),productImage.getProduct().getSku(),productImage.getProductImage()); } public List<OutputContentFile> getImages( MerchantStore store, FileContentType imageContentType ) throws ServiceException { return getImages(store.getCode(),imageContentType); } @Override public List<OutputContentFile> getImages( Product product ) throws ServiceException { if ( cacheManager.getTreeCache() == null ) { throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" ); } List<OutputContentFile> images = new ArrayList<OutputContentFile>(); try { FileNameMap fileNameMap = URLConnection.getFileNameMap(); StringBuilder nodePath = new StringBuilder(); nodePath.append(product.getMerchantStore().getCode()); Node<String, Object> merchantNode = this.getNode(nodePath.toString()); if ( merchantNode == null ) { return null; } for(String key : merchantNode.getKeys()) { byte[] imageBytes = (byte[])merchantNode.get( key ); OutputContentFile contentImage = new OutputContentFile(); InputStream input = new ByteArrayInputStream( imageBytes ); ByteArrayOutputStream output = new ByteArrayOutputStream(); IOUtils.copy( input, output ); String contentType = fileNameMap.getContentTypeFor( key ); contentImage.setFile( output ); contentImage.setMimeType( contentType ); contentImage.setFileName( key ); images.add( contentImage ); } } catch ( Exception e ) { throw new ServiceException( e ); } finally { } return images; } @SuppressWarnings("unchecked") @Override public void removeImages( final String merchantStoreCode ) throws ServiceException { if ( cacheManager.getTreeCache() == null ) { throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" ); } try { final StringBuilder merchantPath = new StringBuilder(); merchantPath.append( getRootName()).append(merchantStoreCode ); cacheManager.getTreeCache().getRoot().remove(merchantPath.toString()); } catch ( Exception e ) { throw new ServiceException( e ); } finally { } } @Override public void removeProductImage( ProductImage productImage ) throws ServiceException { if ( cacheManager.getTreeCache() == null ) { throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" ); } try { StringBuilder nodePath = new StringBuilder(); nodePath.append(productImage.getProduct().getMerchantStore().getCode()).append(Constants.SLASH).append(productImage.getProduct().getSku()); Node<String, Object> productNode = this.getNode(nodePath.toString()); productNode.remove(productImage.getProductImage()); } catch ( Exception e ) { throw new ServiceException( e ); } finally { } } @Override public void removeProductImages( Product product ) throws ServiceException { if ( cacheManager.getTreeCache() == null ) { throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" ); } try { StringBuilder nodePath = new StringBuilder(); nodePath.append(product.getMerchantStore().getCode()); Node<String, Object> merchantNode = this.getNode(nodePath.toString()); merchantNode.remove(product.getSku()); } catch ( Exception e ) { throw new ServiceException( e ); } finally { } } @Override public List<OutputContentFile> getImages(final String merchantStoreCode, FileContentType imageContentType) throws ServiceException { if ( cacheManager.getTreeCache() == null ) { throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" ); } List<OutputContentFile> images = new ArrayList<OutputContentFile>(); FileNameMap fileNameMap = URLConnection.getFileNameMap(); try { StringBuilder nodePath = new StringBuilder(); nodePath.append(merchantStoreCode); Node<String, Object> merchantNode = this.getNode(nodePath.toString()); Set<Node<String,Object>> childs = merchantNode.getChildren(); Iterator<Node<String,Object>> iterator = childs.iterator(); //TODO image sizes while(iterator.hasNext()) { Node<String,Object> node = iterator.next(); for(String key : node.getKeys()) { byte[] imageBytes = (byte[])merchantNode.get( key ); OutputContentFile contentImage = new OutputContentFile(); InputStream input = new ByteArrayInputStream( imageBytes ); ByteArrayOutputStream output = new ByteArrayOutputStream(); IOUtils.copy( input, output ); String contentType = fileNameMap.getContentTypeFor( key ); contentImage.setFile( output ); contentImage.setMimeType( contentType ); contentImage.setFileName( key ); images.add( contentImage ); } } } catch ( Exception e ) { throw new ServiceException( e ); } finally { } return images; } @Override public OutputContentFile getProductImage(String merchantStoreCode, String productCode, String imageName) throws ServiceException { return getProductImage(merchantStoreCode, productCode, imageName, ProductImageSize.SMALL.name()); } @Override public OutputContentFile getProductImage(String merchantStoreCode, String productCode, String imageName, ProductImageSize size) throws ServiceException { return getProductImage(merchantStoreCode, productCode, imageName, size.name()); } private OutputContentFile getProductImage(String merchantStoreCode, String productCode, String imageName, String size) throws ServiceException { if ( cacheManager.getTreeCache() == null ) { throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" ); } InputStream input = null; OutputContentFile contentImage = new OutputContentFile(); try { FileNameMap fileNameMap = URLConnection.getFileNameMap(); //SMALL by default StringBuilder nodePath = new StringBuilder(); nodePath.append(merchantStoreCode).append(Constants.SLASH).append(productCode).append(Constants.SLASH).append(size); Node<String,Object> productNode = this.getNode(nodePath.toString()); byte[] imageBytes = (byte[])productNode.get( imageName ); if(imageBytes==null) { LOGGER.warn("Image " + imageName + " does not exist"); return null;//no post processing will occur } input = new ByteArrayInputStream( imageBytes ); ByteArrayOutputStream output = new ByteArrayOutputStream(); IOUtils.copy( input, output ); String contentType = fileNameMap.getContentTypeFor( imageName ); contentImage.setFile( output ); contentImage.setMimeType( contentType ); contentImage.setFileName( imageName ); } catch ( Exception e ) { throw new ServiceException( e ); } finally { if ( input != null ) { try { input.close(); } catch ( Exception ignore ) { } } } return contentImage; } @SuppressWarnings("unchecked") private Node<String, Object> getNode( final String node ) { LOGGER.debug( "Fetching node for store {} from Infinispan", node ); final StringBuilder merchantPath = new StringBuilder(); merchantPath.append( getRootName() ).append(node); Fqn contentFilesFqn = Fqn.fromString(merchantPath.toString()); Node<String,Object> nd = cacheManager.getTreeCache().getRoot().getChild(contentFilesFqn); if(nd==null) { cacheManager.getTreeCache().getRoot().addChild(contentFilesFqn); nd = cacheManager.getTreeCache().getRoot().getChild(contentFilesFqn); } return nd; } public CacheManager getCacheManager() { return cacheManager; } public void setCacheManager(CacheManager cacheManager) { this.cacheManager = cacheManager; } public void setRootName(String rootName) { this.rootName = rootName; } public String getRootName() { return rootName; } }