jeeves.utils.BinaryFile.java Source code

Java tutorial

Introduction

Here is the source code for jeeves.utils.BinaryFile.java

Source

//=============================================================================
//===   Copyright (C) 2001-2005 Food and Agriculture Organization of the
//===   United Nations (FAO-UN), United Nations World Food Programme (WFP)
//===   and United Nations Environment Programme (UNEP)
//===
//===   This library is free software; you can redistribute it and/or
//===   modify it under the terms of the GNU Lesser General Public
//===   License as published by the Free Software Foundation; either
//===   version 2.1 of the License, or (at your option) any later version.
//===
//===   This library is distributed in the hope that it will be useful,
//===   but WITHOUT ANY WARRANTY; without even the implied warranty of
//===   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//===   Lesser General Public License for more details.
//===
//===   You should have received a copy of the GNU Lesser General Public
//===   License along with this library; if not, write to the Free Software
//===   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//===
//===   Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
//===   Rome - Italy. email: GeoNetwork@fao.org
//==============================================================================

package jeeves.utils;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.UserInfo;

import org.apache.commons.io.IOUtils;

import org.globus.ftp.DataSink;
import org.globus.ftp.FTPClient;
import org.globus.ftp.Session;
import org.jdom.Element;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;

//=============================================================================

/** class to encode/decode binary files to base64 strings
  */

public final class BinaryFile {
    /**
     * Default constructor.
     * Builds a BinaryFile.
     */
    private BinaryFile() {
    }

    private static final int BUF_SIZE = 8192;
    private static boolean remoteFile = false;
    private static String remoteUser = "";
    private static String remotePassword = "";
    private static String remoteSite = "";
    private static String remotePath = "";
    private static String remoteProtocol = "";

    /**
     * Gets the remotePassword.
     * @return the remotePassword.
     */
    public static String getRemotePassword() {
        return remotePassword;
    }

    //---------------------------------------------------------------------------
    // Read the first 2000 chars from the file to get the info we want if the
    // file is remote

    static String readInput(String path) {
        StringBuffer buffer = new StringBuffer();

        Reader in = null;

        try {
            FileInputStream fis = new FileInputStream(path);
            InputStreamReader isr = new InputStreamReader(fis, "UTF8");
            in = new BufferedReader(isr);
            int ch;
            int numRead = 0;
            while (((ch = in.read()) > -1) && (numRead < 2000)) {
                buffer.append((char) ch);
                numRead++;
            }

            return buffer.toString();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    //---------------------------------------------------------------------------

    private static String getRemoteProtocol(String header) {
        String remoteProtocol;

        if (header.startsWith("#geonetworkremotescp")) {
            remoteProtocol = "scp";
        } else if (header.startsWith("#geonetworkremoteftp")) {
            remoteProtocol = "ftp";
        } else {
            remoteProtocol = "unknown";
        }
        return remoteProtocol;
    }

    //---------------------------------------------------------------------------

    private static void checkForRemoteFile(String path) {
        String fileContents = readInput(path);
        if ((fileContents != null) && (fileContents.toLowerCase().startsWith("#geonetworkremotescp")
                || fileContents.toLowerCase().startsWith("#geonetworkremoteftp"))) {
            String[] tokens = fileContents.split("\n");
            if (tokens.length == 5) {
                remoteUser = tokens[1].trim();
                remotePassword = tokens[2].trim();
                remoteSite = tokens[3].trim();
                remotePath = tokens[4].trim();
                remoteProtocol = getRemoteProtocol(fileContents.toLowerCase());
                remoteFile = true;
                if (Log.isDebugEnabled(Log.RESOURCES))
                    Log.debug(Log.RESOURCES, "REMOTE: " + remoteUser + ":********:" + remoteSite + ":" + remotePath
                            + ":" + remoteProtocol);
            } else {
                if (Log.isDebugEnabled(Log.RESOURCES))
                    Log.debug(Log.RESOURCES, "ERROR: remote file details were not valid");
                remoteFile = false;
            }
        } else {
            remoteFile = false;
        }
    }

    //---------------------------------------------------------------------------

    public static Element encode(int responseCode, String path, String name, boolean remove) {
        Element response = encode(responseCode, path, remove);
        response.setAttribute("name", name);
        return response;
    }

    //---------------------------------------------------------------------------

    public static Element encode(int responseCode, String path) {
        return encode(responseCode, path, false);
    }

    //---------------------------------------------------------------------------

    public static Element encode(int responseCode, String path, boolean remove) {
        Element response = new Element("response");
        checkForRemoteFile(path);

        response.setAttribute("responseCode", responseCode + "");
        response.setAttribute("path", path);
        response.setAttribute("remove", remove ? "y" : "n");
        if (remoteFile) {
            response.setAttribute("remotepath", remoteUser + "@" + remoteSite + ":" + remotePath);
            response.setAttribute("remotefile", new File(remotePath).getName());
        }
        return response;
    }

    //---------------------------------------------------------------------------

    public static String getContentType(Element response) {
        String path = response.getAttributeValue("path");
        if (path == null)
            return null;
        return getContentType(path);
    }

    //---------------------------------------------------------------------------

    public static String getContentLength(Element response) {
        String path = response.getAttributeValue("path");
        if (path == null)
            return null;
        String length = "-1";
        if (!remoteFile) {
            File f = new File(path);
            length = f.length() + "";
        }
        return length;
    }

    //---------------------------------------------------------------------------

    public static void removeIfTheCase(Element response) {
        boolean remove = "y".equals(response.getAttributeValue("remove"));

        if (remove) {
            String path = response.getAttributeValue("path");
            File file = new File(path);
            if (!file.delete() && file.exists()) {
                Log.warning(Log.JEEVES, "[" + BinaryFile.class.getName() + "#removeIfTheCase]"
                        + "Unable to remove binary file after sending to user.");
            }
        }
    }

    //---------------------------------------------------------------------------

    public static String getContentDisposition(Element response) {
        String name = response.getAttributeValue("name");
        if (name == null) {
            name = response.getAttributeValue("path");
            if (name == null)
                return null;
            name = new File(name).getName();
        }

        return org.apache.commons.lang.StringEscapeUtils.escapeHtml("attachment;filename=" + name);
    }

    //---------------------------------------------------------------------------

    public static int getResponseCode(Element response) {
        return Integer.parseInt(response.getAttributeValue("responseCode"));
    }

    //---------------------------------------------------------------------------

    public static void write(Element response, OutputStream output) throws IOException {
        //----------------------------------------------------------------------
        // Local class required by jsch for scp
        class MyUserInfo implements UserInfo {
            String passwd = getRemotePassword();

            public String getPassword() {
                return passwd;
            }

            public String getPassphrase() {
                return passwd;
            }

            public void showMessage(String message) {
            }

            public boolean promptYesNo(String message) {
                return true;
            }

            public boolean promptPassword(String message) {
                return true;
            }

            public boolean promptPassphrase(String message) {
                return true;
            }
        }

        //---------------------------------------------------------------------
        // Local class needed by globus ftpclient for ftp 
        class DataSinkStream implements DataSink {
            protected OutputStream out;
            protected boolean autoFlush;
            protected boolean ignoreOffset;
            protected long offset = 0;

            public DataSinkStream(OutputStream out) {
                this(out, false, false);
            }

            public DataSinkStream(OutputStream out, boolean autoFlush, boolean ignoreOffset) {
                this.out = out;
                this.autoFlush = autoFlush;
                this.ignoreOffset = ignoreOffset;
            }

            public void write(org.globus.ftp.Buffer buffer) throws IOException {
                long bufOffset = buffer.getOffset();
                if (ignoreOffset || bufOffset == -1 || bufOffset == offset) {
                    out.write(buffer.getBuffer(), 0, buffer.getLength());
                    if (autoFlush)
                        out.flush();
                    offset += buffer.getLength();
                } else {
                    throw new IOException("Random offsets not supported.");
                }
            }

            public void close() { // don't close the output stream
            }
        }

        String path = response.getAttributeValue("path");
        if (path == null)
            return;
        if (!remoteFile) {
            File f = new File(path);
            InputStream input = new FileInputStream(f);
            copy(input, output, true, false);
        } else {
            if (remoteProtocol.equals("scp")) {
                try {
                    // set up JSch: channel to scp
                    JSch jsch = new JSch();
                    com.jcraft.jsch.Session session = jsch.getSession(remoteUser, remoteSite, 22);
                    UserInfo ui = new MyUserInfo();
                    session.setUserInfo(ui);
                    session.connect();

                    String command = "scp -f " + remotePath;
                    Channel channel = session.openChannel("exec");
                    ((ChannelExec) channel).setCommand(command);

                    // get I/O streams for remote scp
                    OutputStream outScp = channel.getOutputStream();
                    InputStream inScp = channel.getInputStream();
                    channel.connect();

                    copy(inScp, outScp, output);

                    session.disconnect();
                } catch (Exception e) {
                    Log.error(Log.RESOURCES,
                            "Problem with scp from site: " + remoteUser + "@" + remoteSite + ":" + remotePath);
                    e.printStackTrace();
                }
            } else if (remoteProtocol.equals("ftp")) {
                // set up globus FTP client
                try {
                    FTPClient ftp = new FTPClient(remoteSite, 21);
                    ftp.authorize(remoteUser, remotePassword);
                    ftp.setType(Session.TYPE_IMAGE);
                    DataSinkStream outputSink = new DataSinkStream(output);
                    ftp.get(remotePath, outputSink, null);
                } catch (Exception e) {
                    Log.error(Log.RESOURCES,
                            "Problem with ftp from site: " + remoteUser + "@" + remoteSite + ":" + remotePath);
                    e.printStackTrace();
                }
            } else {
                Log.error(Log.RESOURCES, "Unknown remote protocol in config file");
            }
        }
    }

    //----------------------------------------------------------------------------
    // copies an input stream from a JSch object to an output stream

    private static int checkAck(InputStream in) throws IOException {
        int b = in.read();
        // b may be 0 for success,
        //          1 for error,
        //          2 for fatal error,
        //         -1
        if (b == 0)
            return b;
        if (b == -1)
            return b;
        if (b == 1 || b == 2) {
            StringBuffer sb = new StringBuffer();
            int c;
            do {
                c = in.read();
                sb.append((char) c);
            } while (c != '\n');
            if (b == 1) { // error
                Log.error(Log.RESOURCES, "scp: Protocol error: " + sb.toString());
            }
            if (b == 2) { // fatal error
                Log.error(Log.RESOURCES, "scp: Protocol error: " + sb.toString());
            }
        }
        return b;
    }

    //----------------------------------------------------------------------------
    // copies an input stream from a JSch object to an output stream

    private static void copy(InputStream inScp, OutputStream outScp, OutputStream output) throws IOException {
        byte[] buf = new byte[1024];

        // send '\0' to scp
        buf[0] = 0;
        outScp.write(buf, 0, 1);
        outScp.flush();
        while (true) {
            int c = checkAck(inScp);
            if (c != 'C')
                break;
            // read '0644 ' from scp
            if (inScp.read(buf, 0, 5) == -1) {
                throw new IllegalStateException("Expected 0664 but got nothing");
            }

            // establish file size from scp
            long filesize = 0L;
            while (true) {
                if (inScp.read(buf, 0, 1) < 0) {
                    // error from scp
                    break;
                }
                if (buf[0] == ' ')
                    break;
                filesize = filesize * 10L + (long) (buf[0] - '0');
            }

            // now get file name from scp
            String file = null;
            for (int i = 0;; i++) {
                if (inScp.read(buf, i, 1) == -1) {
                    throw new IllegalStateException("Unable to read file name");
                }
                if (buf[i] == (byte) 0x0a) {
                    file = new String(buf, 0, i, Charset.forName("UTF-8"));
                    break;
                }
            }

            // now get file name from scp 
            if (Log.isDebugEnabled(Log.RESOURCES))
                Log.debug(Log.RESOURCES, "scp: file returned has filesize=" + filesize + ", file=" + file);

            // send '\0'
            buf[0] = 0;
            outScp.write(buf, 0, 1);
            outScp.flush();

            // read contents from scp
            int foo;
            while (true) {
                if (buf.length < filesize)
                    foo = buf.length;
                else
                    foo = (int) filesize;
                foo = inScp.read(buf, 0, foo);
                if (foo < 0) {
                    // error
                    break;
                }
                output.write(buf, 0, foo);
                filesize -= foo;
                if (filesize == 0L)
                    break;
            }
            if (checkAck(inScp) == 0) {
                // send '\0'
                buf[0] = 0;
                outScp.write(buf, 0, 1);
                outScp.flush();
            }
        }
    }

    /**
     * Copies an input stream (from a file) to an output stream 
     */
    public static void copy(InputStream in, OutputStream out, boolean closeInput, boolean closeOutput)
            throws IOException {

        try {
            if (in instanceof FileInputStream) {
                FileInputStream fin = (FileInputStream) in;
                WritableByteChannel outChannel;
                if (out instanceof FileOutputStream) {
                    outChannel = ((FileOutputStream) out).getChannel();
                } else {
                    outChannel = Channels.newChannel(out);
                }
                fin.getChannel().transferTo(0, Long.MAX_VALUE, outChannel);
            } else {
                BufferedInputStream input = new BufferedInputStream(in);

                byte buffer[] = new byte[BUF_SIZE];
                int nRead;

                while ((nRead = input.read(buffer)) > 0)
                    out.write(buffer, 0, nRead);
            }
        } finally {
            if (closeInput)
                IOUtils.closeQuietly(in);
            if (closeOutput)
                IOUtils.closeQuietly(out);
        }
    }

    /**
     * Copy a directory from one location to another.
     * 
     * @param sourceLocation
     * @param targetLocation
     * @throws IOException
     */
    public static void copyDirectory(File sourceLocation, File targetLocation) throws IOException {

        if (sourceLocation.isDirectory()) {
            if (!targetLocation.mkdirs() && !targetLocation.exists()) {
                throw new IOException("Unable to create target directory " + targetLocation);
            }

            String[] children = sourceLocation.list();
            for (int i = 0; i < children.length; i++) {
                copyDirectory(new File(sourceLocation, children[i]), new File(targetLocation, children[i]));
            }
        } else {
            InputStream in = null;
            OutputStream out = null;
            try {
                in = new FileInputStream(sourceLocation);
                out = new FileOutputStream(targetLocation);
                copy(in, out, false, false);
            } finally {
                if (in != null) {
                    IOUtils.closeQuietly(in);
                }
                if (out != null) {
                    IOUtils.closeQuietly(out);
                }
            }
        }
    }

    //----------------------------------------------------------------------------
    // Returns the mime-type corresponding to the given file extension

    private static String getContentType(String fName) {
        // standard graphical formats
        if (fName.endsWith(".gif"))
            return "image/gif";
        else if (fName.endsWith(".jpg") || fName.endsWith(".jpeg"))
            return "image/jpeg";
        else if (fName.endsWith(".png"))
            return "application/png";
        else if (fName.endsWith(".bmp"))
            return "application/bmp";

        // compressed formats
        else if (fName.endsWith(".zip"))
            return "application/zip";

        // generic document formats
        else if (fName.endsWith(".pdf"))
            return "application/pdf";
        else if (fName.endsWith(".eps"))
            return "application/eps";
        else if (fName.endsWith(".ai"))
            return "application/ai";

        // arcinfo formats
        else if (fName.endsWith(".pmf"))
            return "application/pmf";
        else if (fName.endsWith(".e00"))
            return "application/e00";
        else
            return ("application/binary");
    }

}

//=============================================================================