net.bioclipse.opentox.api.ModelAlgorithm.java Source code

Java tutorial

Introduction

Here is the source code for net.bioclipse.opentox.api.ModelAlgorithm.java

Source

/* Copyright (C) 2010  Egon Willighagen <egonw@users.sf.net>
 * 
 * This program 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. All we ask is that proper credit is given for our work,
 * which includes - but is not limited to - adding the above copyright notice to
 * the beginning of your source code files, and to any copyright notice that you
 * may distribute with programs based on this work.
 * 
 * This program 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 program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package net.bioclipse.opentox.api;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;

public abstract class ModelAlgorithm extends Algorithm {

    private static final Logger logger = Logger.getLogger(ModelAlgorithm.class);

    @SuppressWarnings("serial")
    public static String calculate(String service, String model, String dataSetURI, IProgressMonitor monitor)
            throws HttpException, IOException, InterruptedException, GeneralSecurityException {
        if (monitor == null)
            monitor = new NullProgressMonitor();
        int worked = 0;

        HttpClient client = new HttpClient();
        dataSetURI = Dataset.normalizeURI(dataSetURI);
        PostMethod method = new PostMethod(model);
        HttpMethodHelper.addMethodHeaders(method, new HashMap<String, String>() {
            {
                put("Accept", "text/uri-list");
            }
        });
        method.setParameter("dataset_uri", dataSetURI);
        method.setParameter("dataset_service", service + "dataset");
        client.executeMethod(method);
        int status = method.getStatusCode();
        String dataset = "";
        // FIXME: I should really start using the RDF response...
        String responseString = method.getResponseBodyAsString();
        logger.debug("Status: " + status);
        int tailing = 1;
        if (status == 200 || status == 202) {
            if (responseString.contains("/task/")) {
                // OK, we got a task... let's wait until it is done
                String task = responseString;
                logger.debug("response: " + task);
                Thread.sleep(andABit(500)); // let's be friendly, and wait 1 sec
                TaskState state = Task.getState(task);
                while (!state.isFinished() && !monitor.isCanceled()) {
                    int onlineWorked = (int) state.getPercentageCompleted();
                    if (onlineWorked > worked) {
                        // work done is difference between done before and online done
                        monitor.worked(onlineWorked - worked);
                        worked = onlineWorked;
                    }
                    // let's be friendly, and wait 2 secs and a bit and increase
                    // that time after each wait
                    int waitingTime = andABit(2000 * tailing);
                    logger.debug("Waiting " + waitingTime + "ms.");
                    waitUnlessInterrupted(waitingTime, monitor);
                    state = Task.getState(task);
                    if (state.isRedirected()) {
                        task = state.getResults();
                        logger.debug("Got a Task redirect. New task:" + task);
                    }
                    // but wait at most 20 secs and a bit
                    if (tailing < 10)
                        tailing++;
                }
                if (monitor.isCanceled())
                    Task.delete(task);
                // OK, it should be finished now
                dataset = state.getResults();
            } else {
                // OK, that was quick!
                dataset = responseString;
                logger.debug("No Task, Data set: " + dataset);
                monitor.worked(100);
            }
        } else if (status == 401) {
            throw new GeneralSecurityException("Not authenticated");
        } else if (status == 403) {
            throw new GeneralSecurityException("Not authorized");
        } else if (status == 404) {
            logger.debug("Model not found (404): " + responseString);
            throw new UnsupportedOperationException("Service not found");
        } else {
            logger.debug("Model error (" + status + "): " + responseString);
            throw new IllegalStateException("Service error: " + status);
        }
        method.releaseConnection();
        dataset = dataset.replaceAll("\n", "");
        return dataset;
    }

    @SuppressWarnings("serial")
    public static String createModel(String algoURI, String datasetURI, List<String> featureURIs,
            String predictionFeatureURI, IProgressMonitor monitor)
            throws HttpException, IOException, InterruptedException, GeneralSecurityException {
        if (monitor == null)
            monitor = new NullProgressMonitor();
        int worked = 0;

        HttpClient client = new HttpClient();
        PostMethod method = new PostMethod(algoURI);
        HttpMethodHelper.addMethodHeaders(method, new HashMap<String, String>() {
            {
                put("Accept", "text/uri-list");
            }
        });
        // add the features etc to the URI
        datasetURI = datasetURI + "?" + asFeatureURIString(featureURIs) + "&max=100";
        logger.debug("create model, datasetURI: " + datasetURI);
        method.setParameter("dataset_uri", datasetURI);
        method.setParameter("prediction_feature", predictionFeatureURI);
        client.executeMethod(method);
        int status = method.getStatusCode();
        String modelURI = "";
        // FIXME: I should really start using the RDF response...
        String responseString = method.getResponseBodyAsString();
        logger.debug("Status: " + status);
        int tailing = 1;
        if (status == 200 || status == 202) {
            if (responseString.contains("/task/")) {
                // OK, we got a task... let's wait until it is done
                String task = responseString;
                logger.debug("response: " + task);
                Thread.sleep(andABit(500)); // let's be friendly, and wait 1 sec
                TaskState state = Task.getState(task);
                while (!state.isFinished() && !monitor.isCanceled()) {
                    int onlineWorked = (int) state.getPercentageCompleted();
                    if (onlineWorked > worked) {
                        // work done is difference between done before and online done
                        monitor.worked(onlineWorked - worked);
                        worked = onlineWorked;
                    }
                    // let's be friendly, and wait 2 secs and a bit and increase
                    // that time after each wait
                    int waitingTime = andABit(2000 * tailing);
                    logger.debug("Waiting " + waitingTime + "ms.");
                    waitUnlessInterrupted(waitingTime, monitor);
                    state = Task.getState(task);
                    if (state.isRedirected()) {
                        task = state.getResults();
                        logger.debug("Got a Task redirect. New task:" + task);
                    }
                    // but wait at most 20 secs and a bit
                    if (tailing < 10)
                        tailing++;
                }
                if (monitor.isCanceled())
                    Task.delete(task);
                // OK, it should be finished now
                modelURI = state.getResults();
            } else {
                // OK, that was quick!
                modelURI = responseString;
                logger.debug("No Task, Data set: " + modelURI);
                monitor.worked(100);
            }
        } else if (status == 401) {
            throw new GeneralSecurityException("Not authenticated");
        } else if (status == 403) {
            throw new GeneralSecurityException("Not authorized");
        } else if (status == 404) {
            logger.debug("Model not found (404): " + responseString);
            throw new UnsupportedOperationException("Service not found");
        } else {
            logger.debug("Model error (" + status + "): " + responseString);
            throw new IllegalStateException("Service error: " + status);
        }
        method.releaseConnection();
        modelURI = modelURI.replaceAll("\n", "");
        return modelURI;
    }

    private static String asFeatureURIString(List<String> featureURIs) {
        if (featureURIs == null || featureURIs.size() == 0)
            return "";

        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < featureURIs.size(); i++) {
            String feature = featureURIs.get(i);
            buffer.append("feature_uris[]=").append(feature);
            if ((i + 1) < featureURIs.size())
                buffer.append("&"); // was this the last? if not...
        }
        return buffer.toString();
    }

    private static void waitUnlessInterrupted(int waitingTime, IProgressMonitor monitor)
            throws InterruptedException {
        int passed = 0;
        final int step = 300; // every 0.3 sec check if the process is canceled 
        while (passed < waitingTime && !monitor.isCanceled()) {
            Thread.sleep(step);
            passed += step;
        }
    }

    private static int andABit(int minimum) {
        return (minimum + (int) Math.round(minimum * Math.random()));
    }

}