WidgetConfigUpdateHandler.java 17.1 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.cq.commons.jcr.JcrUtil
 *  com.day.cq.contentsync.config.ConfigEntry
 *  com.day.cq.contentsync.handler.AbstractSlingResourceUpdateHandler
 *  com.day.cq.dam.api.Asset
 *  com.day.cq.dam.api.Rendition
 *  com.day.cq.dam.api.renditions.RenditionMaker
 *  com.day.cq.dam.api.renditions.RenditionTemplate
 *  javax.jcr.Binary
 *  javax.jcr.Node
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.ValueFactory
 *  org.apache.commons.lang.StringUtils
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.resource.PersistenceException
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceUtil
 *  org.apache.sling.api.resource.ValueMap
 *  org.apache.sling.jcr.resource.JcrResourceResolverFactory
 *  org.osgi.framework.BundleContext
 *  org.osgi.framework.ServiceReference
 *  org.osgi.service.component.ComponentContext
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.cq.mobile.platform.impl.contentsync.handler;

import com.adobe.cq.mobile.phonegap.impl.AppInstanceProviderImpl;
import com.adobe.cq.mobile.platform.MobileResource;
import com.adobe.cq.mobile.platform.MobileResourceLocator;
import com.adobe.cq.mobile.platform.MobileResourceType;
import com.adobe.cq.mobile.platform.impl.MobileAppProvider;
import com.adobe.cq.mobile.platform.impl.WidgetConfigDocument;
import com.adobe.cq.mobile.platform.impl.store.IconDefinition;
import com.adobe.cq.mobile.platform.impl.store.MobilePlatformProvider;
import com.day.cq.commons.jcr.JcrUtil;
import com.day.cq.contentsync.config.ConfigEntry;
import com.day.cq.contentsync.handler.AbstractSlingResourceUpdateHandler;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.Rendition;
import com.day.cq.dam.api.renditions.RenditionMaker;
import com.day.cq.dam.api.renditions.RenditionTemplate;
import java.awt.Dimension;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.ValueFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.jcr.resource.JcrResourceResolverFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

@Component(factory="com.day.cq.contentsync.handler.ContentUpdateHandler/widgetconfig", inherit=1)
@Service
public class WidgetConfigUpdateHandler
extends AbstractSlingResourceUpdateHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(WidgetConfigUpdateHandler.class);
    private static final String PN_TARGET_ICON_DIRECTORY = "targetIconDirectory";
    private static final String PN_TARGET_ICON_PREFIX = "targetIconPrefix";
    private static final String[] DEFAULT_ICON_DIRECTORY_LIST = new String[]{""};
    private static final String DEFAULT_ICON_PREFIX = "res/icons";
    private static final String DEFAULT_ICON_NAME = "icon.png";
    private static final String CONFIG_DOC_NAME = "config.xml";
    @Reference
    private RenditionMaker renditionMaker;
    private ComponentContext context;

    public boolean updateCacheEntry(ConfigEntry configEntry, Long lastUpdated, String configCacheRoot, Session adminSession, Session userSession) {
        String[] configIconDirList = configEntry.getValues("targetIconDirectory");
        configIconDirList = configIconDirList != null ? configIconDirList : DEFAULT_ICON_DIRECTORY_LIST;
        String configIconPrefix = configEntry.getValue("targetIconPrefix");
        configIconPrefix = configIconPrefix != null ? configIconPrefix : "res/icons";
        try {
            if (adminSession.nodeExists(configCacheRoot)) {
                ResourceResolver resourceResolver = this.resolverFactory.getResourceResolver(adminSession);
                Resource resource = resourceResolver.getResource(this.getResolvedContentPath(configEntry));
                MobileResourceLocator mobileResMgr = (MobileResourceLocator)resourceResolver.adaptTo(MobileResourceLocator.class);
                MobileResource instanceResource = mobileResMgr.findClosestResourceByType(resource, MobileResourceType.INSTANCE.getType(), new String[0]);
                if (instanceResource != null) {
                    MobileAppProvider appProvider = (MobileAppProvider)instanceResource.adaptTo(MobileAppProvider.class);
                    if (appProvider instanceof AppInstanceProviderImpl) {
                        String widgetConfigPath = (String)appProvider.getProperties().get("widgetConfigPath", String.class);
                        Resource appContent = ((AppInstanceProviderImpl)appProvider).getContentResource();
                        WidgetConfigDocument configDocument = WidgetConfigDocument.loadConfigDocument(widgetConfigPath, appContent);
                        String[] platforms = (String[])appProvider.getProperties().get("widget/platforms", String[].class);
                        for (String configIconDir : configIconDirList) {
                            String configIconRoot = configCacheRoot;
                            configIconRoot = configIconRoot + (StringUtils.isNotBlank((String)configIconDir) ? new StringBuilder().append("/").append(configIconDir).toString() : "");
                            configIconRoot = configIconRoot + "/" + configIconPrefix;
                            this.addIconRenditions(configDocument, platforms, configIconRoot, configIconPrefix, adminSession, resourceResolver);
                        }
                        configCacheRoot = this.getConfigCacheRoot(configEntry, configCacheRoot);
                        this.addDefaultIcon(configDocument, configCacheRoot, configEntry.getValue("targetRootDirectory"), adminSession);
                        this.addConfigFile(configDocument, configCacheRoot + "/" + "config.xml", adminSession);
                        adminSession.save();
                    } else {
                        LOGGER.error("Invalid App Provider");
                    }
                } else {
                    LOGGER.error("Instance resource not found: " + resource.getPath());
                }
            } else {
                LOGGER.error("Cache root not found: " + configCacheRoot);
            }
        }
        catch (Exception ex) {
            LOGGER.error("Unexpected error while updating cache for config: " + configEntry.getPath(), (Throwable)ex);
        }
        return false;
    }

    private void addConfigFile(WidgetConfigDocument configDoc, String cachePath, Session adminSession) throws RepositoryException, TransformerException {
        JcrUtil.createPath((String)cachePath, (String)"sling:Folder", (String)"nt:file", (Session)adminSession, (boolean)false);
        Node cacheContentNode = JcrUtil.createPath((String)(cachePath + "/jcr:content"), (String)"nt:resource", (Session)adminSession);
        Calendar calTS = Calendar.getInstance();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        DOMSource xmlSource = new DOMSource(configDoc.adaptTo(Document.class));
        StreamResult outputTarget = new StreamResult(outputStream);
        Transformer xmlTransformer = TransformerFactory.newInstance().newTransformer();
        xmlTransformer.setOutputProperty("indent", "yes");
        xmlTransformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
        xmlTransformer.transform(xmlSource, outputTarget);
        cacheContentNode.setProperty("jcr:data", adminSession.getValueFactory().createBinary((InputStream)new ByteArrayInputStream(outputStream.toByteArray())));
        cacheContentNode.setProperty("jcr:lastModified", calTS);
    }

    private Asset getIconFileReference(WidgetConfigDocument configDoc, Session adminSession) {
        Element iconConfigElement = configDoc.getDefaultIconElement();
        if (iconConfigElement != null) {
            String iconFileRef = iconConfigElement.getAttribute("fileReference");
            ResourceResolver resourceResolver = this.resolverFactory.getResourceResolver(adminSession);
            Resource iconResource = resourceResolver.getResource(iconFileRef);
            if (iconResource != null && !ResourceUtil.isNonExistingResource((Resource)iconResource)) {
                return (Asset)iconResource.adaptTo(Asset.class);
            }
        }
        return null;
    }

    private void addDefaultIcon(WidgetConfigDocument configDoc, String cachePath, String prefixPath, Session adminSession) {
        Asset iconImgAsset = this.getIconFileReference(configDoc, adminSession);
        if (iconImgAsset != null) {
            try {
                Element iconConfigElement = configDoc.getDefaultIconElement();
                String iconSrc = iconConfigElement.getAttribute("src");
                if (StringUtils.isBlank((String)iconSrc)) {
                    iconSrc = "icon.png";
                    iconConfigElement.setAttribute("src", iconSrc);
                }
                if (StringUtils.isNotEmpty((String)prefixPath) && StringUtils.startsWith((String)iconSrc, (String)prefixPath)) {
                    iconSrc = iconSrc.substring(prefixPath.length());
                }
                if (iconSrc.lastIndexOf("/") > -1) {
                    if (iconSrc.lastIndexOf("/") > 0) {
                        cachePath = cachePath + "/" + iconSrc.substring(0, iconSrc.lastIndexOf("/"));
                    }
                    iconSrc = iconSrc.substring(iconSrc.lastIndexOf("/") + 1);
                }
                Rendition original = iconImgAsset.getRendition("original");
                Node cachePathNode = JcrUtil.createPath((String)cachePath, (String)"sling:Folder", (String)"sling:Folder", (Session)adminSession, (boolean)false);
                JcrUtil.copy((Node)((Node)original.adaptTo(Node.class)), (Node)cachePathNode, (String)iconSrc);
            }
            catch (RepositoryException re) {
                LOGGER.error("Failed to add app Icon", (Throwable)re);
            }
        }
    }

    private void addIconRenditions(WidgetConfigDocument configDoc, String[] platforms, String cachePath, String prefixPath, Session adminSession, ResourceResolver resourceResolver) {
        Asset iconImgAsset = this.getIconFileReference(configDoc, adminSession);
        if (iconImgAsset != null) {
            try {
                Resource iconsResource = resourceResolver.getResource(cachePath);
                if (iconsResource != null) {
                    resourceResolver.delete(iconsResource);
                    resourceResolver.commit();
                }
            }
            catch (PersistenceException pe) {
                LOGGER.error("Failed to delete: " + cachePath, (Throwable)pe);
            }
            for (String platform : platforms) {
                this.generatePlatformIcons(configDoc, platform, iconImgAsset, cachePath, prefixPath, adminSession);
            }
        }
    }

    private void generatePlatformIcons(WidgetConfigDocument configDoc, String platform, Asset icon, String cachePath, String prefixPath, Session session) {
        String filter = "(cq.mobile.apps.platformprovider=" + platform + ")";
        try {
            ServiceReference[] refs = this.context.getBundleContext().getServiceReferences(MobilePlatformProvider.class.getName(), filter);
            if (refs == null) {
                filter = "(cq.mobile.apps.platformprovider=default)";
                refs = this.context.getBundleContext().getServiceReferences(MobilePlatformProvider.class.getName(), filter);
            }
            if (refs == null || refs.length == 0) {
                return;
            }
            ServiceReference ref = refs[0];
            MobilePlatformProvider provider = (MobilePlatformProvider)this.context.getBundleContext().getService(ref);
            Iterable<IconDefinition> platformIcons = provider.getSupportedIcons();
            if (platformIcons == null) {
                return;
            }
            Document sourceDoc = configDoc.adaptTo(Document.class);
            NodeList nList = sourceDoc.getElementsByTagName("icon");
            for (int i = nList.getLength() - 1; i >= 0; --i) {
                Element eElement = (Element)nList.item(i);
                Element eParent = (Element)eElement.getParentNode();
                if (eElement == null || eParent == null || !platform.equals(eElement.getAttribute("platform")) && !platform.equals(eParent.getAttribute("name"))) continue;
                eParent.removeChild(eElement);
                if (!"platform".equals(eParent.getNodeName()) || eParent.hasChildNodes()) continue;
                eParent.getParentNode().removeChild(eParent);
            }
            Element platformElement = sourceDoc.createElement("platform");
            sourceDoc.getDocumentElement().appendChild(platformElement);
            platformElement.setAttribute("name", platform);
            List<Rendition> iconRenditions = this.generateRenditions(platformIcons, icon);
            Node platformsIconsNode = JcrUtil.createPath((String)(cachePath + "/" + platform), (String)"sling:Folder", (String)"sling:Folder", (Session)session, (boolean)false);
            for (IconDefinition iconDef : platformIcons) {
                Rendition iconRendition = this.locateRendition(iconDef, icon, iconRenditions);
                if (iconRendition == null) continue;
                String iconName = icon.getName();
                int i2 = iconName.contains(".") ? iconName.lastIndexOf(46) : iconName.length();
                StringBuilder finalName = new StringBuilder(iconName.substring(0, i2));
                if (StringUtils.isNotBlank((String)iconDef.getName())) {
                    finalName.append("-").append(iconDef.getName());
                }
                finalName.append(iconName.substring(i2));
                JcrUtil.copy((Node)((Node)iconRendition.adaptTo(Node.class)), (Node)platformsIconsNode, (String)finalName.toString());
                Element iconElement = sourceDoc.createElement("icon");
                iconElement.setAttribute("src", prefixPath + "/" + platform + "/" + finalName);
                if (StringUtils.isNotBlank((String)iconDef.getDensity())) {
                    iconElement.setAttribute("density", iconDef.getDensity());
                } else {
                    iconElement.setAttribute("width", Integer.toString(iconDef.getSize().width));
                    iconElement.setAttribute("height", Integer.toString(iconDef.getSize().height));
                }
                platformElement.appendChild(iconElement);
            }
        }
        catch (Throwable e) {
            LOGGER.warn("Unable to generate icon renditions for {}", (Object)platform);
        }
    }

    private Rendition locateRendition(IconDefinition iconDef, Asset icon, List<Rendition> renditions) {
        StringBuilder searchValue = new StringBuilder("cq5dam.thumbnail.");
        searchValue.append(Integer.toString(iconDef.getSize().width)).append(".");
        searchValue.append(Integer.toString(iconDef.getSize().height));
        for (Rendition r : renditions) {
            if (!r.getName().contains(searchValue.toString())) continue;
            return r;
        }
        return null;
    }

    private List<Rendition> generateRenditions(Iterable<IconDefinition> iconDefinitions, Asset asset) {
        ArrayList<RenditionTemplate> templates = new ArrayList<RenditionTemplate>();
        for (IconDefinition icon : iconDefinitions) {
            templates.add(this.renditionMaker.createThumbnailTemplate(asset, icon.getSize().width, icon.getSize().height, false));
        }
        this.renditionMaker.generateRenditions(asset, templates.toArray((T[])new RenditionTemplate[templates.size()]));
        return asset.getRenditions();
    }

    protected void activate(ComponentContext context) throws RepositoryException {
        this.context = context;
    }

    protected void bindRenditionMaker(RenditionMaker renditionMaker) {
        this.renditionMaker = renditionMaker;
    }

    protected void unbindRenditionMaker(RenditionMaker renditionMaker) {
        if (this.renditionMaker == renditionMaker) {
            this.renditionMaker = null;
        }
    }
}