Package org.fao.geonet.utils

Source Code of org.fao.geonet.utils.BinaryFile

//=============================================================================
//===  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 org.fao.geonet.utils;

import com.google.common.collect.FluentIterable;
import com.google.common.io.Files;
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.fao.geonet.Constants;
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 = null;
      try {
                input = new FileInputStream(f);
          copy(input, output);
      } finally {
          IOUtils.closeQuietly(input);
      }
    } 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);
          try {
              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);
          } finally {
              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(Constants.ENCODING));
          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) throws IOException {
    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);
    }
  }

  /**
   * Copy a directory from one location to another.
   *
   * @param sourceLocation
   * @param targetLocation
   * @throws IOException
   */
  public static void copyDirectory(File sourceLocation , File targetLocation)
    throws IOException {
        final int filePrefixToRemove = sourceLocation.getPath().length();
        final FluentIterable<File> files = Files.fileTreeTraverser().preOrderTraversal(sourceLocation);

        for (File file : files) {
            if (file.isFile()) {
                final String part = file.getPath().substring(filePrefixToRemove);
                final File destFile = new File(targetLocation, part);
                if (!destFile.getParentFile().mkdirs() && !destFile.getParentFile().exists()) {
                    throw new IOException("Unable to create directory: "+destFile.getParentFile());
                }
                copyFile(file, destFile);
            }
        }
    }

    private static void copyFile(File file, File destFile) throws IOException {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            in = new FileInputStream(file);
            out = new FileOutputStream(destFile);
            in.getChannel().transferTo(0, file.length(), out.getChannel());
        } finally {
            IOUtils.closeQuietly(in);
            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");
  }

    public static void copy(File srcFile, File destFile) throws IOException {
        if(srcFile.isFile()) {
            BinaryFile.copyFile(srcFile, destFile);
        } else {
            BinaryFile.copyDirectory(srcFile, destFile);
           
        }
       
    }

    public static void moveTo(File inFile, File outFile, String operationDescription) throws IOException {
        IO.mkdirs(outFile.getParentFile(), "Error creating Parent File for operation: "+operationDescription);
        if (!inFile.renameTo(outFile)) {
            copy(inFile, outFile);
            IO.delete(inFile, false, "org.fao.geonet");
        }
    }
}

//=============================================================================
TOP

Related Classes of org.fao.geonet.utils.BinaryFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.