Friday, February 27, 2015

Using SSH to transfer files in Java

In this example, I'll be using JSch library to copy a file from my local server to a remote host. If using Maven, add the following dependency to your pom.xml file:
        <!-- for ssh -->
        <dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>${jsch.version}</version>
        </dependency>
Define an interface for your remote file operations:
public interface RemoteFileUtilities {
    public void copyFile(String filename, HostInfo hostInfo);
    public List<String> lsDir(String dir, HostInfo hostInfo);
}
SSH implementation class:
public class SshUtilities implements RemoteFileUtilities {

    @Override
    public void copyFile(String filename, HostInfo hostInfo) {
        JSch jsch = new JSch();
        Session session = null;
        ChannelSftp channel = null;
        try {
            session = jsch.getSession(hostInfo.getUsername(),
                    hostInfo.getHostname(), hostInfo.getPort());
            session.setPassword(hostInfo.getPassword());
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();
            channel = (ChannelSftp) session.openChannel("sftp");
            channel.connect();
            File localFile = new File(filename);
            // If you want you can change the directory using the following line.
            channel.cd(hostInfo.getPath());
            channel.put(new FileInputStream(localFile), localFile.getName());   
        } 
        catch (JSchException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (SftpException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        channel.disconnect();
        session.disconnect();
    }

    @Override
    public List<String> lsDir(String dir, HostInfo hostInfo) {
        JSch jsch = new JSch();
        Session session = null;
        ChannelSftp channel = null;
        try {
            session = jsch.getSession(hostInfo.getUsername(), hostInfo.getHostname(), hostInfo.getPort());
            session.setPassword(hostInfo.getPassword());
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();
            channel = (ChannelSftp) session.openChannel("sftp");
            channel.connect();
            return channel.ls(dir);  
        } 
        catch (JSchException e) {
            e.printStackTrace();
        } 
        catch (SftpException e) {
             e.printStackTrace();
        }
        channel.disconnect();
        session.disconnect();
        return null;
    }     
}

A supporting class to hold information related to your host:
public class HostInfo {
    
    private String hostname;
    private String username;
    private String password;
    private String path;
    private int port;
    
    
    public HostInfo(String hostname, String username, String password, String path, int port) {
        super();
        this.hostname = hostname;
        this.username = username;
        this.password = password;
        this.path = path;
        this.port = port;
    }
    
    public String getHostname() {
        return hostname;
    }
    public void setHostname(String hostname) {
        this.hostname = hostname;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getPath() {
        return path;
    }
    public void setPath(String path) {
        this.path = path;
    }
    public int getPort() {
        return port;
    }
    public void setPort(int port) {
        this.port = port;
    } 
}
And finally, a JUnit test class:
public class SshUtilitiesTest {

    @Test
    public void test() {
        HostInfo hostInfo = new HostInfo("dev-core-ccm-1", "noushin", "nbcg14g~", "/home/noushin/ssh-test", 22);
        SshUtilities sshUtils = new SshUtilities();
        sshUtils.copyFile("/tmp/log/error.log", hostInfo);
        List<String> files = sshUtils.lsDir(hostInfo.getPath(), hostInfo);
        if (files != null) {
            for (int i = 0; i < files.size(); i++)
                assert(files.get(i).contains("error.log"));
        }
    }
}

Sending and receiving files via RESTful web services in Java

In this blog, I'll show you how to pass the content of a file to a RESTful web service and have it stored on the server it was received. First write your CXF service and annotate it as follows:
@POST
@Path("saveFile")
@Produces({MediaType.APPLICATION_JSON})
@Consumes({MediaType.MULTIPART_FORM_DATA})
public UploadFile saveFile(MultipartBody body) {
     List<Attachment> attachments = body.getAllAttachments();
     Attachment att = attachments.get(0);
     File destinationFile = new File("/tmp/log/fileX.txt");

     try {
          att.transferTo(destinationFile);
     } 
     catch (IOException ioe) {
          ioe.printStackTrace();
     }
     UploadFile savedFile = new UploadFile();
     savedFile.setFilename("/tmp/log/fileX.txt");
     return savedFile;
}
To call this service, I am using Apache httpcomponents package. Add the following dependencies to your pom.xml:
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.0-beta2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpmime</artifactId>
            <version>4.0-beta2</version>
        </dependency>
And here is the test snippet to call the web service:
    @Test
    public void restSaveFile()  {
        String url = "http://localhost:8080/mywebapp/services/";
        ResponseEntity<AuthenticationToken> authToken = restClient.authenticate(url + "authenticate");
        String token = null;
        if (authToken != null)
            token = authToken.getBody().getToken();
        try {
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost(url + "saveFile");
            // Assuming ~mywebapp/src/test/resource/data/test-file.txt
            FileBody body = new FileBody(new File(Thread.currentThread().getContextClassLoader().getResource("data/test-file.txt").getFile()));
            StringBody comment = new StringBody("Test data for saving a file.");
            httpPost.addHeader("X-Auth-Token", token);
            httpPost.addHeader("Content-Type", MediaType.MULTIPART_FORM_DATA_VALUE);       
            MultipartEntity requestEntity = new MultipartEntity();
            requestEntity.addPart("file", body);
            requestEntity.addPart("comment", comment);
            httpPost.setEntity(requestEntity);        
            System.out.println("Executing request " + httpPost.getRequestLine());
            HttpResponse response = httpclient.execute(httpPost);
            HttpEntity responseEntity = response.getEntity();
            System.out.println("----------------------------------------------");
            System.out.println(response.getStatusLine());
            if (responseEntity != null) {
                System.out.println("Response content length: " + responseEntity.getContentLength());
                System.out.println("Response content type: " + responseEntity.getContentType().getValue());
            }
            if (responseEntity != null) {           
                responseEntity.consumeContent();
            }
            System.out.println("----------------------------------------------");
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }        
    }

JAXB & Xml Binding Using Annotations

Create an entity bean and annotate it for JAXB Xml binding:
package com.noushin.soaws.model;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name="book")
@XmlType(propOrder={"name", "author", "isbn", "publisher"})
public class Book {

    private String name;
    private String author;
    private String isbn;
    private String publisher;
    
    public Book() {}
    
    public Book(String author) {
        this.author = author;        
    }
    
    public String getAuthor() {
        return author;
    }
    
    public void setAuthor(String author) {
        this.author = author;
    }

    @XmlElement(name="title")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public String getPublisher() {
        return publisher;
    }

    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }

}

Create a class to manage the entity bean, read to and write from XML files:
package com.noushin.soaws.service;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;

import javax.jws.WebService;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

import com.noushin.soaws.model.Book;

@XmlRootElement(namespace="com.noushin.soaws")
public class BookService {

    @XmlElementWrapper(name="books")
    @XmlElement(name="book")
    ArrayList<Book> books;

    public void setBooks() {
        books = new ArrayList<Book>();

        // create books
        Book book1 = new Book();
        book1.setIsbn("978-0060554736");
        book1.setName("The Game");
        book1.setAuthor("Neil Strauss");
        book1.setPublisher("Harpercollins");
        books.add(book1);

        Book book2 = new Book();
        book2.setIsbn("978-3832180577");
        book2.setName("Feuchtgebiete");
        book2.setAuthor("Charlotte Roche");
        book2.setPublisher("Dumont Buchverlag");
        books.add(book2);

    }

    public ArrayList<Book> getBooks() {
        return books;
    }

    public Book getBook() {
        return new Book("Mark Twain");
    }

    public static void manage() {
        BookService bookService = new BookService();
        bookService.setBooks();
        
        // create JAXB context and instantiate marshaller
        JAXBContext context;
        try {
            context = JAXBContext.newInstance(BookService.class);

            Marshaller m = context.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            // Write to System.out
            m.marshal(bookService, System.out);

            // Write to File
            m.marshal(bookService, new File("/tmp/books.xml"));

            // get variables from our xml file, created before
            System.out.println();
            System.out.println("Output from our XML File: ");
            Unmarshaller um = context.createUnmarshaller();
            BookService bookService2 = (BookService) um.unmarshal(new FileReader("books.xml"));
            ArrayList<Book> list = bookService2.getBooks();
            for (Book book : list) {
                System.out.println("Book: " + book.getName() + " from " + book.getAuthor());
            }
        } 
        catch (JAXBException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}


Using Junit, write a test case to test the functionality:
package com.noushin.soaws.service;

import static org.junit.Assert.*;

import org.junit.Test;

public class BookServiceTest {

    @Test
    public void test() {
        BookService bookService = new BookService();
        bookService.manage();
    }

}