com.dinochiesa.edgecallouts.FtpPut.java Source code

Java tutorial

Introduction

Here is the source code for com.dinochiesa.edgecallouts.FtpPut.java

Source

// FtpPut.java
//
// This is an Apigee Edge custom policy that performs an FTP PUT. 
//
// This code is licensed under the Apache 2.0 license. See the LICENSE
// file that accompanies this source.
//
// Friday, 25 March 2016, 12:11
//
// ------------------------------------------------------------------

package com.dinochiesa.edgecallouts;

import java.util.Map;
import java.util.HashMap;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;

import com.dinochiesa.edgecallouts.ftputil.FtpCalloutResult;
import com.dinochiesa.edgecallouts.ftputil.FtpCommandListener;
import com.dinochiesa.util.TemplateString;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Base64InputStream;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.lang.text.StrSubstitutor;
import org.apache.commons.lang.exception.ExceptionUtils;

import com.apigee.flow.execution.ExecutionContext;
import com.apigee.flow.execution.ExecutionResult;
import com.apigee.flow.execution.spi.Execution;
import com.apigee.flow.message.MessageContext;
import com.apigee.flow.message.Message;
import java.io.IOException;

public class FtpPut implements Execution {
    private static final String _varPrefix = "ftp_";
    private Map properties; // read-only

    public FtpPut(Map properties) {
        this.properties = properties;
    }

    private static final String varName(String s) {
        return _varPrefix + s;
    }

    private boolean getDebug() {
        String value = (String) this.properties.get("debug");
        if (value == null)
            return false;
        if (value.trim().toLowerCase().equals("true"))
            return true;
        return false;
    }

    private boolean getWantBase64Decode(MessageContext msgCtxt) {
        String value = (String) this.properties.get("want-base64-decode");
        if (value == null)
            return false;
        value = resolvePropertyValue(value.trim(), msgCtxt);
        if ((value == null) || value.equals(""))
            return false;
        return value.trim().toLowerCase().equals("true");
    }

    private String getSourceVar(MessageContext msgCtxt) {
        String value = (String) this.properties.get("source-variable");
        if (value == null)
            return null;
        return resolvePropertyValue(value.trim(), msgCtxt);
    }

    private String getFtpServer(MessageContext msgCtxt) throws Exception {
        return getSimpleRequiredProperty("ftp-server", msgCtxt);
    }

    private String getFtpUser(MessageContext msgCtxt) throws Exception {
        return getSimpleRequiredProperty("ftp-user", msgCtxt);
    }

    private String getFtpPassword(MessageContext msgCtxt) throws Exception {
        return getSimpleRequiredProperty("ftp-password", msgCtxt);
    }

    private String getRemoteFileName(MessageContext msgCtxt) throws Exception {
        return getSimpleRequiredProperty("remote-file-name", msgCtxt);
    }

    private String getInitialDirectory(MessageContext msgCtxt) throws Exception {
        String dest = getSimpleOptionalProperty("initial-directory", msgCtxt);
        if (dest == null) {
            return "/";
        }
        return dest;
    }

    private int getFtpPort(MessageContext msgCtxt) throws Exception {
        String port = getSimpleOptionalProperty("ftp-port", msgCtxt);
        if (port == null || port.equals("")) {
            return 21;
        }
        return Integer.parseInt(port, 10);
    }

    private String getSimpleOptionalProperty(String propName, MessageContext msgCtxt) throws Exception {
        String value = (String) this.properties.get(propName);
        if (value == null) {
            return null;
        }
        value = value.trim();
        if (value.equals("")) {
            return null;
        }
        value = resolvePropertyValue(value, msgCtxt);
        if (value == null || value.equals("")) {
            return null;
        }
        return value;
    }

    private String getSimpleRequiredProperty(String propName, MessageContext msgCtxt) throws Exception {
        String value = (String) this.properties.get(propName);
        if (value == null) {
            throw new IllegalStateException(propName + " resolves to an empty string.");
        }
        value = value.trim();
        if (value.equals("")) {
            throw new IllegalStateException(propName + " resolves to an empty string.");
        }
        value = resolvePropertyValue(value, msgCtxt);
        if (value == null || value.equals("")) {
            throw new IllegalStateException(propName + " resolves to an empty string.");
        }
        return value;
    }

    // If the value of a property value begins and ends with curlies,
    // eg, {apiproxy.name}, then "resolve" the value by de-referencing
    // the context variable whose name appears between the curlies.
    private String resolvePropertyValue(String spec, MessageContext msgCtxt) {
        if (spec.indexOf('{') > -1 && spec.indexOf('}') > -1) {
            // Replace ALL curly-braced items in the spec string with
            // the value of the corresponding context variable.
            TemplateString ts = new TemplateString(spec);
            Map<String, String> valuesMap = new HashMap<String, String>();
            for (String s : ts.variableNames) {
                valuesMap.put(s, (String) msgCtxt.getVariable(s));
            }
            StrSubstitutor sub = new StrSubstitutor(valuesMap);
            String resolvedString = sub.replace(ts.template);
            return resolvedString;
        }
        return spec;
    }

    public ExecutionResult execute(MessageContext messageContext, ExecutionContext execContext) {
        FtpCalloutResult info = new FtpCalloutResult();
        try {
            // The executes in the IO thread!
            String sourceVar = getSourceVar(messageContext);
            InputStream src = null;
            boolean wantBase64Decode = getWantBase64Decode(messageContext);
            if (sourceVar == null) {
                src = messageContext.getMessage().getContentAsStream();
                // conditionally wrap a decoder around it
                if (wantBase64Decode) {
                    src = new Base64InputStream(src);
                }
            } else {
                info.addMessage("Retrieving data from " + sourceVar);
                String sourceData = messageContext.getVariable(sourceVar);
                byte[] b = (wantBase64Decode) ? Base64.decodeBase64(sourceData)
                        : sourceData.getBytes(StandardCharsets.UTF_8);
                src = new ByteArrayInputStream(b);
            }
            String remoteName = getRemoteFileName(messageContext);
            remoteName = remoteName.replaceAll(":", "").replaceAll("/", "-");

            String ftpServer = getFtpServer(messageContext);
            int ftpPort = getFtpPort(messageContext);
            String user = getFtpUser(messageContext);
            String password = getFtpPassword(messageContext);

            info.addMessage("connecting to server " + ftpServer);
            FTPClient ftp = new FTPClient();
            ftp.addProtocolCommandListener(new FtpCommandListener(info));
            ftp.connect(ftpServer, ftpPort);
            ftp.enterLocalPassiveMode();
            int reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                info.setStatus("FAIL");
                info.addMessage("The FTP server refused the connection.");
                messageContext.setVariable(varName("result"), info.toJsonString());
                return ExecutionResult.ABORT;
            }

            if (!ftp.login(user, password)) {
                ftp.disconnect();
                info.setStatus("FAIL");
                info.addMessage("Login failure");
                messageContext.setVariable(varName("result"), info.toJsonString());
                return ExecutionResult.ABORT;
            }
            info.addMessage("logged in as " + user);

            String initialDirectory = getInitialDirectory(messageContext);
            if ((initialDirectory != null) && (!initialDirectory.equals(""))) {
                ftp.changeWorkingDirectory(initialDirectory);
            }

            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            OutputStream os = ftp.storeFileStream(remoteName);
            if (os == null) {
                // cannot open output stream
                info.addMessage("cannot open output stream to " + remoteName);
                info.setStatus("FAIL");
            } else {
                byte[] buf = new byte[2048];
                int n;
                while ((n = src.read(buf)) > 0) {
                    os.write(buf, 0, n);
                }
                os.close();
                src.close();
                boolean completed = ftp.completePendingCommand();
                info.addMessage("transfer completed: " + completed);
                info.setStatus("OK");
            }

            ftp.disconnect();
            info.addMessage("All done.");
            messageContext.setVariable(varName("result"), info.toJsonString());
        } catch (java.lang.Exception exc1) {
            if (getDebug()) {
                System.out.println(ExceptionUtils.getStackTrace(exc1));
            }
            String error = exc1.toString();
            messageContext.setVariable(varName("exception"), error);
            info.setStatus("FAIL");
            info.addMessage(error);
            messageContext.setVariable(varName("result"), info.toJsonString());
            int ch = error.lastIndexOf(':');
            if (ch >= 0) {
                messageContext.setVariable(varName("error"), error.substring(ch + 2).trim());
            } else {
                messageContext.setVariable(varName("error"), error);
            }
            messageContext.setVariable(varName("stacktrace"), ExceptionUtils.getStackTrace(exc1));
            return ExecutionResult.ABORT;
        }

        return ExecutionResult.SUCCESS;
    }
}