CampaignConnectorImpl.java 14.8 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.granite.crypto.CryptoException
 *  com.adobe.granite.crypto.CryptoSupport
 *  com.day.cq.commons.inherit.InheritanceValueMap
 *  com.day.cq.wcm.webservicesupport.Configuration
 *  com.day.cq.wcm.webservicesupport.ConfigurationManager
 *  org.apache.commons.codec.binary.Base64
 *  org.apache.commons.httpclient.HttpClient
 *  org.apache.commons.httpclient.HttpMethod
 *  org.apache.commons.httpclient.NameValuePair
 *  org.apache.commons.httpclient.methods.GetMethod
 *  org.apache.commons.httpclient.methods.PostMethod
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.resource.LoginException
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceResolverFactory
 *  org.apache.sling.api.resource.ResourceUtil
 *  org.apache.sling.api.resource.ValueMap
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.cq.mcm.campaign.impl;

import com.adobe.granite.crypto.CryptoException;
import com.adobe.granite.crypto.CryptoSupport;
import com.day.cq.commons.inherit.InheritanceValueMap;
import com.day.cq.mcm.campaign.ACConnectorException;
import com.day.cq.mcm.campaign.CallResults;
import com.day.cq.mcm.campaign.CampaignCredentials;
import com.day.cq.mcm.campaign.ConfigurationException;
import com.day.cq.mcm.campaign.ConnectionException;
import com.day.cq.mcm.campaign.GenericCampaignConnector;
import com.day.cq.mcm.campaign.impl.CallResultsImpl;
import com.day.cq.mcm.campaign.impl.HttpClientBuilder;
import com.day.cq.mcm.campaign.impl.IntegrationConfig;
import com.day.cq.wcm.webservicesupport.Configuration;
import com.day.cq.wcm.webservicesupport.ConfigurationManager;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
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.LoginException;
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.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(metatype=0)
@Service
public class CampaignConnectorImpl
implements GenericCampaignConnector {
    @Reference
    private CryptoSupport cryptoSupport;
    @Reference
    private IntegrationConfig config;
    @Reference
    private ResourceResolverFactory resolverFactory;
    private final Logger log;
    private static final String CLOUDSERVICE_SERVICE_USER = "campaign-cloudservice";

    public CampaignConnectorImpl() {
        this.log = LoggerFactory.getLogger(this.getClass());
    }

    protected NameValuePair[] createNameValuePairs(Map<String, String> map) {
        NameValuePair[] pairs = new NameValuePair[map.size()];
        int k = 0;
        for (String key : map.keySet()) {
            pairs[k++] = new NameValuePair(key, map.get(key));
        }
        return pairs;
    }

    protected String createDebugQueryString(Map<String, String> map, boolean includeQM) {
        if (map == null) {
            return "";
        }
        StringBuilder qs = new StringBuilder(48);
        boolean isFirst = true;
        for (String key : map.keySet()) {
            if (isFirst) {
                isFirst = false;
                if (includeQM) {
                    qs.append('?');
                }
            } else {
                qs.append('&');
            }
            if (!key.equals("__sessiontoken")) {
                qs.append(key).append('=').append(map.get(key));
                continue;
            }
            qs.append("__sessiontoken").append("=***");
        }
        return qs.toString();
    }

    @Override
    public Configuration getWebserviceConfig(Resource resource) throws ConfigurationException {
        ResourceResolver serviceResolver;
        ConfigurationManager configManager = (ConfigurationManager)resource.getResourceResolver().adaptTo(ConfigurationManager.class);
        Resource configResource = configManager.getConfigurationResource(resource);
        if (configResource == null) {
            throw new ConfigurationException("No webservice config node found.");
        }
        if ((configResource = configResource.getChild("jcr:content")) == null) {
            throw new ConfigurationException("Missing 'jcr:content' on webservice config node.");
        }
        this.log.debug("Webservice config found on resource '{}'", (Object)configResource.getPath());
        ValueMap values = ResourceUtil.getValueMap((Resource)configResource);
        String[] configPaths = (String[])values.get("cq:cloudserviceconfigs", String[].class);
        if (configPaths == null || configPaths.length == 0) {
            throw new ConfigurationException("No cloudservice configuration defined.");
        }
        try {
            Map<String, String> info = Collections.singletonMap("sling.service.subservice", "campaign-cloudservice");
            serviceResolver = this.resolverFactory.getServiceResourceResolver(info);
        }
        catch (LoginException e) {
            throw new ConfigurationException("Unable to login using user service usercampaign-cloudservice");
        }
        configManager = (ConfigurationManager)serviceResolver.adaptTo(ConfigurationManager.class);
        Configuration config = configManager.getConfiguration("campaign", configPaths);
        if (config == null) {
            throw new ConfigurationException("Could not resolve cloudservice configuration.");
        }
        return config;
    }

    @Override
    public CampaignCredentials retrieveCredentials(Configuration config) throws ConfigurationException {
        String password;
        InheritanceValueMap map = config.getProperties();
        String host = (String)map.get("apiendpoint", String.class);
        if (host == null) {
            throw new ConfigurationException("No host available.");
        }
        String user = (String)map.get("username", String.class);
        if (user == null) {
            throw new ConfigurationException("No user available.");
        }
        if (host.endsWith("/")) {
            host = host.substring(0, host.length() - 1);
        }
        try {
            String pwdEncrypted = (String)map.get("password", String.class);
            if (!this.cryptoSupport.isProtected(pwdEncrypted)) {
                throw new ConfigurationException("Unencrypted password detected. Please encrypt the password!");
            }
            password = this.cryptoSupport.unprotect(pwdEncrypted);
        }
        catch (CryptoException ce) {
            throw new ConfigurationException("Could not decrypt service password", (Throwable)ce);
        }
        return new CampaignCredentials(host, user, password);
    }

    @Override
    public CallResults callFunction(String name, Map<String, String> fctParams, CampaignCredentials credentials) throws ConnectionException {
        return this.callGeneric("/jssp/nms/" + name, fctParams, credentials);
    }

    @Override
    public CallResults postFunction(String name, Map<String, String> data, CampaignCredentials credentials) throws ConnectionException {
        return this.postGeneric("/jssp/nms/" + name, data, credentials);
    }

    @Override
    public CallResults callGeneric(String apiEndpoint, Map<String, String> fctParams, CampaignCredentials credentials) throws ConnectionException {
        String url = credentials.getHost() + apiEndpoint;
        String user = credentials.getUser();
        String password = credentials.getPassword();
        String token = "#user#/#password#".replaceAll("#user#", Matcher.quoteReplacement(user)).replaceAll("#password#", Matcher.quoteReplacement(password));
        fctParams.put("__sessiontoken", token);
        GetMethod get = new GetMethod(apiEndpoint);
        try {
            HttpClient hc = HttpClientBuilder.createHttpClient(url, this.config);
            get.setQueryString(this.createNameValuePairs(fctParams));
            int statusCode = hc.executeMethod((HttpMethod)get);
            if (statusCode != 200) {
                String body = get.getResponseBodyAsString();
                if (statusCode >= 500) {
                    this.log.warn("Internal Adobe Campaign error: response body is {}", (Object)body);
                    this.log.info("Requested: {}{}", (Object[])new String[]{get.getPath(), this.createDebugQueryString(fctParams, true)});
                } else {
                    this.log.info("Status code: {}; response body is: {}", (Object[])new String[]{Integer.toString(statusCode), body});
                    this.log.info("Requested: {}{}", (Object[])new String[]{get.getPath(), this.createDebugQueryString(fctParams, true)});
                }
                throw new ConnectionException("Unexpected status code (expected 200, was " + statusCode + ")", statusCode);
            }
            return new CallResultsImpl((HttpMethod)get);
        }
        catch (URISyntaxException use) {
            throw new ConnectionException("Invalid URL: " + url, use);
        }
        catch (IOException ioe) {
            get.releaseConnection();
            throw new ConnectionException("Could not execute request to Adobe Campaign instance.", ioe);
        }
    }

    @Override
    public CallResults postGeneric(String apiEndpoint, Map<String, String> data, CampaignCredentials credentials) throws ConnectionException {
        String url = credentials.getHost() + apiEndpoint;
        String user = credentials.getUser();
        String password = credentials.getPassword();
        String token = "#user#/#password#".replaceAll("#user#", Matcher.quoteReplacement(user)).replaceAll("#password#", Matcher.quoteReplacement(password));
        data.put("__sessiontoken", token);
        PostMethod post = new PostMethod(apiEndpoint);
        try {
            HttpClient hc = HttpClientBuilder.createHttpClient(url, this.config);
            post.setRequestBody(this.createNameValuePairs(data));
            int statusCode = hc.executeMethod((HttpMethod)post);
            if (statusCode != 200) {
                String body = post.getResponseBodyAsString();
                if (statusCode >= 500) {
                    this.log.warn("Internal Adobe Campaign error: response body is: {}", (Object)body);
                    this.log.info("Requested: {} - data: {}", (Object[])new String[]{post.getPath(), this.createDebugQueryString(data, false)});
                } else {
                    this.log.info("Status code: {}; response body is: {}", (Object[])new String[]{Integer.toString(statusCode), body});
                    this.log.info("Requested: {} - data: {}", (Object[])new String[]{post.getPath(), this.createDebugQueryString(data, false)});
                }
                throw new ConnectionException("Unexpected status code (expected 200, was " + statusCode + ")", statusCode);
            }
            return new CallResultsImpl((HttpMethod)post);
        }
        catch (URISyntaxException use) {
            throw new ConnectionException("Invalid URL: " + url, use);
        }
        catch (IOException ioe) {
            post.releaseConnection();
            throw new ConnectionException("Could not execute request to Adobe Campaign instance.", ioe);
        }
    }

    @Override
    public CallResults callGenericWithBasicAuth(String path, String queryString, CampaignCredentials credentials) throws ACConnectorException {
        String url = credentials.getHost() + path;
        GetMethod get = new GetMethod(path);
        try {
            HttpClient hc = HttpClientBuilder.createHttpClient(url, this.config);
            if (queryString != null) {
                get.setQueryString(queryString);
            }
            String authInfo = credentials.getUser() + ":" + credentials.getPassword();
            try {
                authInfo = new String(Base64.encodeBase64((byte[])authInfo.getBytes("UTF-8")), "UTF-8");
                get.addRequestHeader("Authorization", "Basic " + authInfo);
            }
            catch (UnsupportedEncodingException e) {
                // empty catch block
            }
            int statusCode = hc.executeMethod((HttpMethod)get);
            if (statusCode != 200) {
                String body = get.getResponseBodyAsString();
                if (statusCode >= 500) {
                    this.log.warn("Internal Adobe Campaign error: response body is {}", (Object)body);
                    this.log.info("Requested: {}?{}", (Object[])new String[]{get.getPath(), queryString});
                } else {
                    this.log.info("Status code: {}; response body is: {}", (Object[])new String[]{Integer.toString(statusCode), body});
                    this.log.info("Requested: {}?{}", (Object[])new String[]{get.getPath(), queryString});
                }
                throw new ConnectionException("Unexpected status code (expected 200, was " + statusCode + ")", statusCode);
            }
            return new CallResultsImpl((HttpMethod)get);
        }
        catch (URISyntaxException use) {
            throw new ConnectionException("Invalid URL: " + url, use);
        }
        catch (IOException ioe) {
            get.releaseConnection();
            throw new ConnectionException("Could not execute request to Adobe Campaign instance.", ioe);
        }
    }

    protected void bindCryptoSupport(CryptoSupport cryptoSupport) {
        this.cryptoSupport = cryptoSupport;
    }

    protected void unbindCryptoSupport(CryptoSupport cryptoSupport) {
        if (this.cryptoSupport == cryptoSupport) {
            this.cryptoSupport = null;
        }
    }

    protected void bindConfig(IntegrationConfig integrationConfig) {
        this.config = integrationConfig;
    }

    protected void unbindConfig(IntegrationConfig integrationConfig) {
        if (this.config == integrationConfig) {
            this.config = null;
        }
    }

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

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