PromotionManagerImpl.java 13.9 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.Workspace
 *  javax.jcr.observation.EventIterator
 *  javax.jcr.observation.EventListener
 *  javax.jcr.observation.ObservationManager
 *  org.apache.commons.lang.StringUtils
 *  org.apache.felix.scr.annotations.Activate
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Deactivate
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.ReferenceCardinality
 *  org.apache.felix.scr.annotations.ReferencePolicy
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.SlingHttpServletRequest
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceResolverFactory
 *  org.apache.sling.commons.osgi.OsgiUtil
 *  org.osgi.service.component.ComponentContext
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.cq.commerce.impl.promotion;

import com.adobe.cq.commerce.api.CommerceException;
import com.adobe.cq.commerce.api.promotion.Promotion;
import com.adobe.cq.commerce.api.promotion.PromotionHandler;
import com.adobe.cq.commerce.api.promotion.PromotionManager;
import com.adobe.cq.commerce.api.promotion.Voucher;
import com.adobe.cq.commerce.common.promotion.AbstractJcrVoucher;
import com.adobe.cq.commerce.impl.promotion.JcrPromotionImpl;
import com.adobe.cq.commerce.impl.promotion.JcrVoucherImpl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Workspace;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.ObservationManager;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.commons.osgi.OsgiUtil;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(immediate=1, metatype=1, label="Adobe CQ Commerce Promotion Manager", description="Manages caching and lookup of promotions and promotion handlers.")
@Service(value={PromotionManager.class})
@Property(name="service.description", value={"Manages caching and lookup of promotions and promotion handlers"})
public class PromotionManagerImpl
implements PromotionManager,
EventListener {
    private final Logger log = LoggerFactory.getLogger(PromotionManagerImpl.class);
    static final String DEFAULT_PROMOTION_ROOT = "/content/campaigns";
    @Property(label="%Promotions Root", description="%Search root for promotions", value={"/content/campaigns"})
    private static final String PROMOTION_ROOT_PROP_NAME = "cq.commerce.promotion.root";
    @Reference
    private ResourceResolverFactory resolverFactory = null;
    @Reference(referenceInterface=PromotionHandler.class, bind="bindPromotionHandler", unbind="unbindPromotionHandler", cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE, policy=ReferencePolicy.DYNAMIC)
    private Map<String, PromotionHandler> promotionHandlers = new HashMap<String, PromotionHandler>();
    private String promotionRoot;
    private ResourceResolver serviceResolver;
    private ObservationManager observationManager;
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private List<Promotion> promotionsCache = new ArrayList<Promotion>();
    private boolean cachesDirty = true;
    private Map<String, List<Voucher>> vouchersCache = new HashMap<String, List<Voucher>>();

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    protected void bindPromotionHandler(PromotionHandler condition, Map<?, ?> properties) {
        this.lock.writeLock().lock();
        try {
            this.promotionHandlers.put((String)properties.get("commerce.promotion.type"), condition);
        }
        finally {
            this.lock.writeLock().unlock();
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    protected void unbindPromotionHandler(PromotionHandler condition, Map<?, ?> properties) {
        this.lock.writeLock().lock();
        try {
            this.promotionHandlers.remove((String)properties.get("commerce.promotion.type"));
        }
        finally {
            this.lock.writeLock().unlock();
        }
    }

    @Activate
    protected void activate(ComponentContext context) throws Exception {
        this.promotionRoot = OsgiUtil.toString(context.getProperties().get("cq.commerce.promotion.root"), (String)"/content/campaigns");
        HashMap<String, String> authenticationInfo = new HashMap<String, String>();
        authenticationInfo.put("sling.service.subservice", "frontend");
        this.serviceResolver = this.resolverFactory.getServiceResourceResolver(authenticationInfo);
        Session serviceSession = (Session)this.serviceResolver.adaptTo(Session.class);
        this.observationManager = serviceSession.getWorkspace().getObservationManager();
        this.observationManager.addEventListener((EventListener)this, 63, this.promotionRoot, true, null, null, true);
    }

    @Deactivate
    protected void deactivate(ComponentContext context) throws RepositoryException {
        if (this.serviceResolver != null && this.serviceResolver.isLive()) {
            if (this.observationManager != null) {
                this.observationManager.removeEventListener((EventListener)this);
            }
            this.serviceResolver.close();
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public void onEvent(EventIterator events) {
        this.lock.writeLock().lock();
        try {
            this.cachesDirty = true;
            for (PromotionHandler handler : this.promotionHandlers.values()) {
                try {
                    handler.invalidateCaches();
                }
                catch (Exception x) {
                    this.log.error("Failed to invalidate cache {}", (Throwable)x);
                }
            }
        }
        finally {
            this.lock.writeLock().unlock();
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    @Override
    public Map<String, String> getPromotionsMap(SlingHttpServletRequest request) {
        this.lock.readLock().lock();
        try {
            this.validateCaches();
            HashMap<String, String> map = new HashMap<String, String>();
            Session session = (Session)request.getResourceResolver().adaptTo(Session.class);
            for (Promotion promo : this.promotionsCache) {
                try {
                    if (!promo.isValid() || !session.nodeExists(promo.getPath())) continue;
                    map.put(promo.getPath(), StringUtils.join(promo.getSegments(), (String)","));
                }
                catch (RepositoryException e) {}
            }
            HashMap<String, String> i$ = map;
            return i$;
        }
        finally {
            this.lock.readLock().unlock();
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    @Override
    public List<Promotion> getAvailablePromotions(ResourceResolver resourceResolver) {
        this.lock.readLock().lock();
        try {
            this.validateCaches();
            ArrayList<Promotion> list = new ArrayList<Promotion>();
            Session session = (Session)resourceResolver.adaptTo(Session.class);
            for (Promotion promo : this.promotionsCache) {
                try {
                    if (!session.nodeExists(promo.getPath())) continue;
                    list.add(promo);
                }
                catch (RepositoryException e) {}
            }
            ArrayList<Promotion> i$ = list;
            return i$;
        }
        finally {
            this.lock.readLock().unlock();
        }
    }

    @Deprecated
    @Override
    public AbstractJcrVoucher getVoucher(SlingHttpServletRequest request, String code) {
        Voucher voucher = this.findVoucher(request, code);
        if (voucher == null) {
            return null;
        }
        try {
            return new AbstractJcrVoucher(request.getResourceResolver().getResource(voucher.getPath()));
        }
        catch (CommerceException e) {
            return null;
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    @Override
    public Voucher findVoucher(SlingHttpServletRequest request, String code) {
        List<Voucher> vouchers;
        this.lock.readLock().lock();
        try {
            this.validateCaches();
            Session session = (Session)request.getResourceResolver().adaptTo(Session.class);
            vouchers = this.vouchersCache.get(code);
            if (vouchers == null) {
                Voucher voucher = null;
                return voucher;
            }
            Voucher first = null;
            Voucher firstValid = null;
            for (Voucher voucher : vouchers) {
                if (voucher == null || !session.nodeExists(voucher.getPath())) continue;
                if (first == null) {
                    first = voucher;
                }
                if (!voucher.isValid(request)) continue;
                if (firstValid == null) {
                    firstValid = voucher;
                    continue;
                }
                this.log.warn("Multiple vouchers using the code '{0}' are currently valid.", (Object)code);
            }
            Iterator<Voucher> i$ = firstValid != null ? firstValid : first;
            return i$;
        }
        catch (RepositoryException e) {
            vouchers = null;
            return vouchers;
        }
        finally {
            this.lock.readLock().unlock();
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private void validateCaches() {
        if (this.cachesDirty) {
            this.lock.readLock().unlock();
            this.lock.writeLock().lock();
            try {
                if (this.cachesDirty) {
                    this.promotionsCache.clear();
                    this.vouchersCache.clear();
                    this.collector(this.serviceResolver.getResource(this.promotionRoot));
                    this.cachesDirty = false;
                }
            }
            finally {
                this.lock.readLock().lock();
                this.lock.writeLock().unlock();
            }
        }
    }

    private void collector(Resource resource) {
        if (resource == null) {
            return;
        }
        if (resource.isResourceType("commerce/components/voucher")) {
            try {
                JcrVoucherImpl voucher = new JcrVoucherImpl(resource.getParent());
                List<Voucher> list = this.vouchersCache.get(voucher.getCode());
                if (list == null) {
                    list = new ArrayList<Voucher>();
                    this.vouchersCache.put(voucher.getCode(), list);
                }
                list.add(voucher);
                Collections.sort(list, VoucherPrioritySorter.INSTANCE);
            }
            catch (CommerceException e) {
                this.log.error(e.getMessage());
            }
        } else if (resource.isResourceType("commerce/components/promotion")) {
            try {
                JcrPromotionImpl promotion = new JcrPromotionImpl(resource.getParent());
                this.promotionsCache.add(promotion);
            }
            catch (CommerceException e) {
                this.log.error(e.getMessage());
            }
        } else {
            Iterator i = resource.listChildren();
            while (i.hasNext()) {
                this.collector((Resource)i.next());
            }
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    @Override
    public PromotionHandler getHandler(String promotionType) {
        this.lock.readLock().lock();
        try {
            PromotionHandler promotionHandler = this.promotionHandlers.get(promotionType);
            return promotionHandler;
        }
        finally {
            this.lock.readLock().unlock();
        }
    }

    protected void bindResolverFactory(ResourceResolverFactory resourceResolverFactory) {
        this.resolverFactory = resourceResolverFactory;
    }

    protected void unbindResolverFactory(ResourceResolverFactory resourceResolverFactory) {
        if (this.resolverFactory == resourceResolverFactory) {
            this.resolverFactory = null;
        }
    }

    static class VoucherPrioritySorter
    implements Comparator<Voucher> {
        public static final VoucherPrioritySorter INSTANCE = new VoucherPrioritySorter();

        private VoucherPrioritySorter() {
        }

        @Override
        public int compare(Voucher o1, Voucher o2) {
            long p2;
            long p1 = o1.getPriority();
            return p1 < (p2 = o2.getPriority()) ? 1 : (p1 != p2 ? -1 : 0);
        }
    }

}