ProductAssetManagerImpl.java 17.1 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.cq.dam.api.Asset
 *  com.day.cq.dam.commons.util.DamUtil
 *  org.apache.commons.codec.DecoderException
 *  org.apache.commons.codec.net.URLCodec
 *  org.apache.commons.lang.StringUtils
 *  org.apache.sling.api.resource.ModifiableValueMap
 *  org.apache.sling.api.resource.PersistenceException
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.cq.commerce.impl.asset;

import com.adobe.cq.commerce.api.CommerceException;
import com.adobe.cq.commerce.api.Product;
import com.adobe.cq.commerce.api.asset.ProductAssetHandler;
import com.adobe.cq.commerce.api.asset.ProductAssetHandlerProvider;
import com.adobe.cq.commerce.api.asset.ProductAssetManager;
import com.adobe.cq.commerce.common.AbstractJcrProduct;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.commons.util.DamUtil;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.net.URLCodec;
import org.apache.commons.lang.StringUtils;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ProductAssetManagerImpl
implements ProductAssetManager {
    private static final Logger log = LoggerFactory.getLogger(ProductAssetManagerImpl.class);
    private static final String ASSET_REFERENCE_PLACEHOLDER = "/libs/dam/gui/components/admin/resources/emptydir.png";
    private static final String NN_PRODUCT_ASSET_BASE = "assets";
    private static final String NN_PRODUCT_ASSET = "asset";
    private static final String NN_PRODUCT_IMAGE = "image";
    private static final String PN_PRODUCT_REFERENCE = "cq:productReference";
    private static final String PN_PRODUCT_ID = "dam:productID";
    private ResourceResolver resolver;
    private List<ProductAssetHandler> productAssetHandlers;
    private String productAssetHandlerFallback;

    public ProductAssetManagerImpl(ResourceResolver resolver, ProductAssetHandlerProvider productAssetHandlerProvider) {
        this.resolver = resolver;
        this.productAssetHandlers = productAssetHandlerProvider.getProductAssetHandlers();
        this.productAssetHandlerFallback = productAssetHandlerProvider.getFallbackHandler();
    }

    @Override
    public boolean isSupportedReferencedAsset(String assetReference) {
        ProductAssetHandler handler = this.getHandler(assetReference);
        if (handler != null) {
            return handler.isSupportedReferencedAsset(this.resolver, assetReference);
        }
        return false;
    }

    @Override
    public boolean isSupportedAsset(String productAssetPath) {
        Resource productAssetResource = this.resolver.getResource(productAssetPath);
        if (!this.isProductAsset(productAssetResource)) {
            return false;
        }
        ProductAssetHandler handler = this.getHandler(productAssetResource);
        if (handler != null) {
            return handler.isSupportedAsset(productAssetResource);
        }
        return false;
    }

    @Override
    public String getReferencedAsset(String productAssetPath) {
        Resource productAssetResource = this.resolver.getResource(productAssetPath);
        if (!this.isProductAsset(productAssetResource)) {
            return null;
        }
        ProductAssetHandler handler = this.getHandler(productAssetResource);
        if (handler != null) {
            return handler.getReferencedAsset(productAssetResource);
        }
        return null;
    }

    @Override
    public Resource getAsset(Product product) {
        if (product == null) {
            throw new IllegalArgumentException("The product is not defined.");
        }
        return product.getAsset();
    }

    @Override
    public List<Resource> getAssets(Product product) {
        if (product == null) {
            throw new IllegalArgumentException("The product is not defined.");
        }
        return product.getAssets();
    }

    @Override
    public String getThumbnailUrl(Product product, String selectorString) {
        Resource productAssetRes = this.getAsset(product);
        if (productAssetRes != null) {
            return this.getThumbnailUrl(productAssetRes.getPath(), selectorString);
        }
        return null;
    }

    @Override
    public String getThumbnailUrl(String productAssetPath, String selectorString) {
        Resource productAssetResource = this.resolver.getResource(productAssetPath);
        if (!this.isProductAsset(productAssetResource)) {
            return null;
        }
        ProductAssetHandler handler = this.getHandler(productAssetResource);
        if (handler != null) {
            return handler.getThumbnailUrl(productAssetResource, selectorString);
        }
        return null;
    }

    @Override
    public Resource addAsset(Product product, String assetReference) throws CommerceException {
        if (product == null) {
            throw new IllegalArgumentException("The product is not defined.");
        }
        Map<String, Object> assetProperties = null;
        if (StringUtils.isEmpty((String)assetReference)) {
            ProductAssetHandler fallbackHandler = this.getHandlerByName(this.productAssetHandlerFallback);
            if (fallbackHandler == null) {
                throw new CommerceException("Failed to add an asset to product at " + product.getPath());
            }
            assetProperties = fallbackHandler.getAssetProperties(this.resolver, "/libs/dam/gui/components/admin/resources/emptydir.png");
        } else {
            ProductAssetHandler handler = this.getHandler(assetReference);
            if (handler == null) {
                throw new CommerceException("No product asset handler found: cannot add the asset to the product at: " + product.getPath());
            }
            assetProperties = handler.getAssetProperties(this.resolver, assetReference);
        }
        return this.addAsset(product, assetProperties);
    }

    private Resource createUniqueResource(Resource parent, String nameHint, Map<String, Object> properties) throws PersistenceException {
        String childName;
        Resource child = parent.getChild(nameHint);
        if (child == null) {
            return this.resolver.create(parent, nameHint, properties);
        }
        int i = 0;
        do {
            childName = nameHint + String.valueOf(i);
            ++i;
        } while (parent.getChild(childName) != null);
        return this.resolver.create(parent, childName, properties);
    }

    @Override
    public Resource addAsset(Product product, Map<String, Object> productAssetProperties) throws CommerceException {
        Resource productAssetRes;
        if (product == null) {
            throw new IllegalArgumentException("The product is not defined.");
        }
        try {
            Resource productRes = (Resource)product.adaptTo(Resource.class);
            Resource productAssetBase = productRes.getChild("assets");
            if (productAssetBase == null) {
                productAssetBase = this.resolver.create(productRes, "assets", null);
                this.resolver.commit();
            }
            productAssetProperties.put("jcr:lastModifiedBy", this.resolver.getUserID());
            productAssetProperties.put("jcr:lastModified", Calendar.getInstance());
            productAssetRes = this.createUniqueResource(productAssetBase, "asset", productAssetProperties);
            String productAssetPath = productAssetRes.getPath();
            String productPath = product.getPath();
            String assetReference = this.getReferencedAsset(productAssetPath);
            this.addProductRefToDAMAsset(productPath, assetReference);
            this.resolver.commit();
        }
        catch (PersistenceException e) {
            throw new CommerceException("Failed to add an asset to product at " + product.getPath(), (Throwable)e);
        }
        return productAssetRes;
    }

    @Override
    public Resource updateAsset(String productAssetPath, String assetReference) throws CommerceException {
        ProductAssetHandler handler = this.getHandler(assetReference);
        if (handler == null) {
            throw new CommerceException("No product asset handler found: cannot update the product asset at: " + productAssetPath);
        }
        Map<String, Object> assetProperties = handler.getAssetProperties(this.resolver, assetReference);
        return this.updateAsset(productAssetPath, assetProperties);
    }

    @Override
    public Resource updateAsset(String productAssetPath, Map<String, Object> productAssetProperties) throws CommerceException {
        Resource productAssetResource = this.resolver.getResource(productAssetPath);
        if (productAssetResource == null) {
            throw new CommerceException("Failed to update product asset at " + productAssetPath);
        }
        if (!this.isProductAsset(productAssetResource)) {
            throw new CommerceException("This is not a product asset: " + productAssetPath);
        }
        String oldAssetReference = this.getReferencedAsset(productAssetPath);
        ModifiableValueMap currentProps = (ModifiableValueMap)productAssetResource.adaptTo(ModifiableValueMap.class);
        currentProps.putAll(productAssetProperties);
        HashSet keys = new HashSet(currentProps.keySet());
        for (String key : keys) {
            if (productAssetProperties.containsKey(key) || key.contains("jcr:")) continue;
            currentProps.remove((Object)key);
        }
        currentProps.put((Object)"jcr:lastModifiedBy", (Object)this.resolver.getUserID());
        currentProps.put((Object)"jcr:lastModified", (Object)Calendar.getInstance());
        String productPath = this.getProductPath(productAssetPath);
        String newAssetReference = this.getReferencedAsset(productAssetPath);
        this.removeProductRefFromDAMAsset(productPath, oldAssetReference);
        this.addProductRefToDAMAsset(productPath, newAssetReference);
        try {
            this.resolver.commit();
        }
        catch (PersistenceException e) {
            throw new CommerceException("Failed to update product asset at " + productAssetPath, (Throwable)e);
        }
        return productAssetResource;
    }

    @Override
    public void removeAsset(String productAssetPath) throws CommerceException {
        Resource productAssetResource = this.resolver.getResource(productAssetPath);
        if (productAssetResource == null) {
            throw new CommerceException("Failed to remove product asset at " + productAssetPath);
        }
        if (!this.isProductAsset(productAssetResource)) {
            throw new CommerceException("This is not a product asset: " + productAssetPath);
        }
        try {
            String productPath = this.getProductPath(productAssetPath);
            String assetReference = this.getReferencedAsset(productAssetPath);
            this.removeProductRefFromDAMAsset(productPath, assetReference);
            this.resolver.delete(productAssetResource);
            this.resolver.commit();
        }
        catch (PersistenceException e) {
            throw new CommerceException("Failed to remove product asset at " + productAssetPath, (Throwable)e);
        }
    }

    private void addProductRefToDAMAsset(String productPath, String assetReference) {
        Asset asset = this.getAsset(this.resolver, assetReference);
        if (asset == null) {
            return;
        }
        Product product = this.getProduct(productPath);
        if (product != null) {
            String productId = product.getSKU();
            Resource assetRes = (Resource)asset.adaptTo(Resource.class);
            Resource metadata = assetRes.getChild("jcr:content/metadata");
            ModifiableValueMap vm = (ModifiableValueMap)metadata.adaptTo(ModifiableValueMap.class);
            vm.put((Object)"cq:productReference", (Object)productPath);
            vm.put((Object)"dam:productID", (Object)productId);
        }
    }

    private void removeProductRefFromDAMAsset(String productPath, String assetReference) {
        Asset asset = this.getAsset(this.resolver, assetReference);
        if (asset == null) {
            return;
        }
        Resource assetRes = (Resource)asset.adaptTo(Resource.class);
        Resource metadata = assetRes.getChild("jcr:content/metadata");
        ModifiableValueMap vm = (ModifiableValueMap)metadata.adaptTo(ModifiableValueMap.class);
        String productReference = (String)vm.get("cq:productReference", String.class);
        if (productReference != null && productReference.equals(productPath)) {
            vm.remove((Object)"cq:productReference");
            vm.remove((Object)"dam:productID");
        }
    }

    private Product getProduct(String productPath) {
        Resource res = this.resolver.getResource(productPath);
        if (res != null) {
            Product product = (Product)res.adaptTo(Product.class);
            return product;
        }
        return null;
    }

    private Asset getAsset(ResourceResolver resolver, String assetReference) {
        if (StringUtils.isEmpty((String)assetReference)) {
            return null;
        }
        try {
            assetReference = new URLCodec().decode(assetReference);
        }
        catch (DecoderException e) {
            log.error("Error while decoding fileReference: {}", (Object)assetReference);
        }
        Resource assetRes = resolver.getResource(assetReference);
        if (assetRes == null) {
            return null;
        }
        return DamUtil.resolveToAsset((Resource)assetRes);
    }

    private String getProductPath(String productAssetPath) {
        Resource productAssetRes = this.resolver.getResource(productAssetPath);
        Resource parent = productAssetRes.getParent();
        Product product = (Product)parent.adaptTo(Product.class);
        if (product != null) {
            return product.getPath();
        }
        Resource grandParent = parent.getParent();
        product = (Product)grandParent.adaptTo(Product.class);
        if (product != null) {
            return product.getPath();
        }
        return null;
    }

    private ProductAssetHandler getHandler(String assetReference) {
        if (StringUtils.isEmpty((String)assetReference)) {
            throw new IllegalArgumentException("The asset reference is not defined.");
        }
        log.debug("Looking for handler for asset: " + assetReference);
        for (ProductAssetHandler handler : this.productAssetHandlers) {
            if (!handler.isActive() || !handler.isSupportedReferencedAsset(this.resolver, assetReference)) continue;
            log.debug("Handler found for asset: " + assetReference);
            return handler;
        }
        log.debug("No handler found for asset: " + assetReference);
        log.debug("Using the fallback handler (name = " + this.productAssetHandlerFallback + ")");
        return this.getHandlerByName(this.productAssetHandlerFallback);
    }

    private ProductAssetHandler getHandler(Resource productAssetResource) {
        if (productAssetResource == null) {
            throw new IllegalArgumentException("The product asset is not defined.");
        }
        if (!this.isProductAsset(productAssetResource)) {
            throw new IllegalArgumentException("This is not a product asset: " + productAssetResource.getPath());
        }
        log.debug("Looking for handler for asset: " + productAssetResource.getPath());
        for (ProductAssetHandler handler : this.productAssetHandlers) {
            if (!handler.isActive() || !handler.isSupportedAsset(productAssetResource)) continue;
            log.debug("Handler found for asset: " + productAssetResource.getPath());
            return handler;
        }
        log.debug("No handler found for asset: " + productAssetResource.getPath());
        log.debug("Using the fallback handler (name = " + this.productAssetHandlerFallback + ")");
        return this.getHandlerByName(this.productAssetHandlerFallback);
    }

    private ProductAssetHandler getHandlerByName(String name) {
        log.debug("Looking for handler with name: " + name);
        for (ProductAssetHandler handler : this.productAssetHandlers) {
            if (!handler.isActive() || !StringUtils.isNotEmpty((String)name) || !name.equals(handler.getHandlerName())) continue;
            log.debug("Handler found for name: " + name);
            return handler;
        }
        log.error("No handler found for name: " + name);
        return null;
    }

    private boolean isProductAsset(Resource resource) {
        if (resource == null) {
            return false;
        }
        String path = resource.getPath();
        Resource parent = resource.getParent();
        if (path == null || parent == null) {
            return false;
        }
        return path.endsWith("/image") && AbstractJcrProduct.isAProductOrVariant(parent) || path.contains("/assets/asset") && AbstractJcrProduct.isAProductOrVariant(parent.getParent());
    }
}