Thursday, April 23, 2015

Download File or Java Serializable object with REST

In this post I'm going to tell how to export a file or Serialzable java object in the server using a REST api call.

From the client's perspective he is downloading a file.
If you want to enable downloading a file in the server you can do it in the following way.
    @GET
    @Path("/{modelName}")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response exportFile(@PathParam("modelName") String modelName) {

        try {
            MLModelNew model = mlModelHandler.getModel(tenantId, userName, modelName);
            if(model != null) {
                String filePath = model.getStorageDirectory();
                File file = new File(filePath);
                return Response.ok(file).build();
            } else {
                return Response.status(Response.Status.NOT_FOUND).build();
            }
        } catch (MLModelHandlerException e) {
            logger.error(String.format(
                    "Error while retrieving model [name] %s. Cause: %s",
                    modelName, e.getMessage()));
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
        }
    }
There's another useful scenario of downloading a java serializable object as it is. This can be done by sending it as a stream. Here is how you can send a java object as a stream.
This example send an object type of MLModel as a stream.
    @GET
    @Path("/{modelName}")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response exportModel(@PathParam("modelName") String modelName) {

        try {
            MLModelNew model = mlModelHandler.getModel(tenantId, userName, modelName);
            if(model != null) {
                final MLModel generateModel = mlModelHandler.retrieveModel(model.getId());
                StreamingOutput stream = new StreamingOutput() {
                    public void write(OutputStream outputStream) throws IOException {
                        ObjectOutputStream out = new ObjectOutputStream(outputStream);
                        out.writeObject(generateModel);
                    }
                };
                return Response.ok(stream).build();
            } else {
                return Response.status(Response.Status.NOT_FOUND).build();
            }
        } catch (Exception e) {
            logger.error(String.format(
                    "Error while retrieving model [name] %s. Cause: %s",
                    modelName, e.getMessage()));
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
        } 
    }
References :

[1] http://examples.javacodegeeks.com/enterprise-java/rest/jax-rs-download-file/
[2] http://stackoverflow.com/questions/10100936/file-downloading-in-restfull-web-services
[3] http://howtodoinjava.com/2013/05/10/resteasy-file-download-example/
[4] http://rest.elkstein.org/2008/02/using-rest-in-java.html
[5] http://java.dzone.com/articles/streaming-apis-json-vs-xml-and
[6] http://stackoverflow.com/questions/29640523/streaming-the-result-of-rest-api-from-twitter
[7] http://stackoverflow.com/questions/3496209/input-and-output-binary-streams-using-jersey
[8] http://stackoverflow.com/questions/23421967/jax-rs-send-serialized-objects
[9] https://developer.jboss.org/thread/174955
[10] http://www.ibm.com/developerworks/library/j-5things1/
[11] http://www.postseek.com/meta/8ee7d7c8a67ab5f555f0403d19d27dd9 -

Friday, April 17, 2015

Writing a Test Class with In-memory H2 Database

While I was implementing unit tests for one java component, I had a requirement to write @Before method inside which I needed to initialize a database. Further I had to create a DataSource using it and bind it to the InitialContext.

According to the requirement, the database had to be populated with some initial data.

This post is about how I've used an in-memory H2 database inside the test classes.

    public static final String DRIVER_CLASS = "org.h2.Driver"; 
    public static final String CONNECTION_URL = "jdbc:h2:mem:WSO2ML_DB"; 
    public static final String USERNAME = "wso2carbon";
    public static final String PASSWORD = "wso2carbon";

    @Before
    public void createTestDB() throws SQLException, URISyntaxException, 
                                      NamingException, ClassNotFoundException, FileNotFoundException {

        // Create data source
        JdbcDataSource ds = new JdbcDataSource();
        ds.setURL(CONNECTION_URL);
        ds.setUser(USERNAME);
        ds.setPassword(PASSWORD);

        // Create initial context
        System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
        System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");

        // Bind data source -> 
        // DataSource can be accessed by : (DataSource) initContext.lookup("jdbc/WSO2ML_DB");
        InitialContext ic = new InitialContext();
        ic.createSubcontext("jdbc");
        ic.bind("jdbc/WSO2ML_DB", ds);

        Class.forName(DRIVER_CLASS);
        Connection connection = DriverManager.getConnection("jdbc:h2:mem:WSO2ML_DB", USERNAME, PASSWORD);

        // TO dump -> SCRIPT TO '<path-to-directory>/ml-db-dump.sql'
        // TO populate DB -> RUNSCRIPT

        // Populate DB with the given DB-dump
        URL resource = TestDB.class.getResource("/ml-db-dump.sql");
        String filePath = new File(resource.toURI()).getAbsolutePath();
        RunScript.execute(connection, new FileReader(filePath));
    }


References :
[1] http://stackoverflow.com/questions/3461310/how-can-i-bind-a-datasource-to-an-initialcontext-for-junit-testing
[2] http://www.journaldev.com/2509/jdbc-datasource-example-oracle-mysql-and-apache-dbcp-tutorial
[3] http://java.dzone.com/articles/presentation-and-use-h2
[4] http://www.h2database.com/javadoc/org/h2/jdbcx/JdbcDataSource.html
[5] http://stackoverflow.com/questions/3256694/how-in-h2db-get-sql-dump-like-in-mysql
[6] http://h2database.com/html/grammar.html#runscript
[7] http://stackoverflow.com/questions/10675768/executing-script-file-in-h2-database