Project: bioclipse.opentox
/* Copyright (C) 2010  Egon Willighagen <[email protected]>
 *  
 * 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.BufferedReader; 
import java.io.IOException; 
import java.io.StringReader; 
import java.io.StringWriter; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
 
import net.bioclipse.cdk.business.CDKManager; 
import net.bioclipse.core.business.BioclipseException; 
import net.bioclipse.core.domain.IMolecule; 
import net.bioclipse.core.domain.StringMatrix; 
import net.bioclipse.rdf.business.IRDFStore; 
import net.bioclipse.rdf.business.RDFManager; 
 
import org.apache.commons.httpclient.HttpClient; 
import org.apache.commons.httpclient.methods.DeleteMethod; 
import org.apache.commons.httpclient.methods.GetMethod; 
import org.apache.commons.httpclient.methods.PostMethod; 
import org.apache.commons.httpclient.methods.PutMethod; 
import org.apache.commons.httpclient.util.URIUtil; 
import org.apache.log4j.Logger; 
import org.eclipse.core.runtime.IProgressMonitor; 
import org.eclipse.core.runtime.NullProgressMonitor; 
import org.openscience.cdk.AtomContainer; 
import org.openscience.cdk.io.SDFWriter; 
 
public class Dataset { 
 
 private static final Logger logger = Logger.getLogger(Dataset.class); 
  
    private final static String QUERY_PREDICTED_FEATURES = 
        "SELECT ?desc ?label ?numval {" + 
        "  ?entry a <http://www.opentox.org/api/1.1#DataEntry> ;" + 
        "     <http://www.opentox.org/api/1.1#values> ?value ." + 
        "  ?value <http://www.opentox.org/api/1.1#feature> ?feature;" + 
        "     <http://www.opentox.org/api/1.1#value> ?numval ." + 
        "  ?feature <http://www.opentox.org/api/1.1#hasSource> ?desc ." + 
        "  ?feature <http://purl.org/dc/elements/1.1/title> ?label ." + 
        "}"
 
 static CDKManager cdk = new CDKManager(); 
 static RDFManager rdf = new RDFManager(); 
  
 @SuppressWarnings("serial"
 public static List<String> getListOfAvailableDatasets(String service) 
 throws IOException { 
  HttpClient client = new HttpClient(); 
  GetMethod method = new GetMethod(service + "dataset"); 
  HttpMethodHelper.addMethodHeaders(method, 
   new HashMap<String,String>() {{ put("Accept""text/uri-list"); }} 
  ); 
  client.executeMethod(method); 
 
  List<String> datasets = new ArrayList<String>(); 
  BufferedReader reader = new BufferedReader( 
   new StringReader(method.getResponseBodyAsString()) 
  ); 
  String line; 
  while ((line = reader.readLine()) != null) { 
   line = line.trim(); 
   if (line.length() > 0) datasets.add(line); 
  
  reader.close(); 
  method.releaseConnection(); 
  return datasets; 
 
 
 public static String normalizeURI(String datasetURI) { 
  datasetURI = datasetURI.replaceAll("\\n"""); 
  datasetURI = datasetURI.replaceAll("\\r"""); 
  if (!datasetURI.endsWith("/")) datasetURI += "/"
  return datasetURI; 
 
  
 @SuppressWarnings("serial"
 public static List<String> getCompoundList(String datasetURI) 
 throws IOException { 
  HttpClient client = new HttpClient(); 
  datasetURI = normalizeURI(datasetURI); 
  GetMethod method = new GetMethod(datasetURI + "compounds"); 
  HttpMethodHelper.addMethodHeaders(method, 
   new HashMap<String,String>() {{ put("Accept""text/uri-list"); }} 
  ); 
  client.executeMethod(method); 
  List<String> compounds = new ArrayList<String>(); 
  BufferedReader reader = new BufferedReader( 
   new StringReader(method.getResponseBodyAsString()) 
  ); 
  String line; 
  while ((line = reader.readLine()) != null) { 
   line = line.trim(); 
   if (line.length() > 0) compounds.add(line); 
  
  reader.close(); 
  method.releaseConnection(); 
  return compounds; 
 
 
 @SuppressWarnings("serial"
 public static StringMatrix listPredictedFeatures(String datasetURI) 
 throws Exception { 
  logger.debug("Listing features for: " + datasetURI); 
  datasetURI = datasetURI.replaceAll("\n"""); 
  if (datasetURI.contains("feature_uris[]=")) { 
   String baseURI = datasetURI.substring(0, datasetURI.indexOf("feature_uris[]=")); 
   String featureURIs = datasetURI.substring(datasetURI.indexOf("feature_uris[]=")+15); 
   featureURIs = URIUtil.decode(featureURIs); 
   String fullURI = baseURI + "feature_uris[]=" + featureURIs; 
   datasetURI = URIUtil.encodeQuery(fullURI); 
  
  HttpClient client = new HttpClient(); 
  GetMethod method = new GetMethod(datasetURI); 
  HttpMethodHelper.addMethodHeaders(method, 
   new HashMap<String,String>() {{ put("Accept""application/rdf+xml"); }} 
  ); 
  client.executeMethod(method); 
  String result = method.getResponseBodyAsString(); // without this things will fail?? 
  IRDFStore store = rdf.createInMemoryStore(); 
  rdf.importFromStream(store, method.getResponseBodyAsStream(), "RDF/XML"null); 
  method.releaseConnection(); 
  String dump = rdf.asRDFN3(store); 
  StringMatrix matrix = rdf.sparql(store, QUERY_PREDICTED_FEATURES); 
  return matrix; 
 
 
 public static void deleteDataset(String datasetURI) 
 throws Exception { 
  HttpClient client = new HttpClient(); 
  DeleteMethod method = new DeleteMethod(datasetURI); 
  HttpMethodHelper.addMethodHeaders(method, null); 
  client.executeMethod(method); 
  int status = method.getStatusCode(); 
  method.releaseConnection(); 
  if (status == 404
   throw new IllegalArgumentException( 
    "Dataset does not exist." 
   ); 
  if (status == 503
   throw new IllegalStateException("Service error: " + status); 
 
 
 public static void addMolecule(String datasetURI, IMolecule mol) 
 throws Exception { 
  StringWriter strWriter = new StringWriter(); 
  SDFWriter writer = new SDFWriter(strWriter); 
  writer.write(cdk.asCDKMolecule(mol).getAtomContainer()); 
  writer.close(); 
  addMolecules(datasetURI, strWriter.toString(), null); 
 
 
 public static void addMolecules(String datasetURI, List<IMolecule> mols) 
 throws Exception { 
  StringWriter strWriter = new StringWriter(); 
  SDFWriter writer = new SDFWriter(strWriter); 
  for (IMolecule mol : mols) { 
   writer.write(cdk.asCDKMolecule(mol).getAtomContainer()); 
  
  writer.close(); 
  addMolecules(datasetURI, strWriter.toString(), null); 
 
 
 public static void setMetadata(String datasetURI, String predicate, String value) 
 throws Exception { 
  HttpClient client = new HttpClient(); 
  PutMethod method = new PutMethod(normalizeURI(datasetURI) + "metadata"); 
  HttpMethodHelper.addMethodHeaders(method, 
   new HashMap<String,String>() {{ put("Content-type""text/n3"); }} 
  ); 
  String triples = 
   "<" + datasetURI + 
   "> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> " + 
   "<http://www.opentox.org/api/1.1#Dataset> .\n" + 
   "<" + datasetURI + 
   "> <" + predicate + "> " + value + 
   " ."
  System.out.println("Triples:\n" + triples); 
  method.setRequestBody(triples); 
  client.executeMethod(method); 
  int status = method.getStatusCode(); 
  if (status == 200) { 
   // OK, that was quick! 
   String response = method.getResponseBodyAsString(); 
   System.out.println("Set value response: " + response); 
  else if (status == 202) { 
   // OK, we got a task... let's wait until it is done 
   String task = method.getResponseBodyAsString(); 
   Thread.sleep(1000); // let's be friendly, and wait 1 sec 
   TaskState state = Task.getState(task); 
   while (!state.isFinished()) { 
    Thread.sleep(3000); // let's be friendly, and wait 3 sec 
    state = Task.getState(task); 
    if (state.isRedirected()) { 
     task = state.getResults(); 
    
   
   // OK, it should be finished now 
   String dataset = state.getResults(); 
  else { 
   throw new BioclipseException("Status : " + status); 
  
  method.releaseConnection(); 
 
 
 public static void setLicense(String datasetURI, String license) 
 throws Exception { 
  setMetadata( 
   datasetURI, 
   "http://purl.org/dc/terms/license"
   "<" + license + ">" 
  ); 
 
 
 public static void setRightsHolder(String datasetURI, String holder) 
 throws Exception { 
  setMetadata( 
   datasetURI, 
   "http://purl.org/dc/terms/rightsHolder"
   "<" + holder + ">" 
  ); 
 
 
 public static void setTitle(String datasetURI, String title) 
 throws Exception { 
  setMetadata( 
   datasetURI, 
   "http://purl.org/dc/elements/1.1/title"
   "\"" + title + "\"" 
  ); 
 
 
 @SuppressWarnings("serial"
 public static void addMolecules(String datasetURI, String sdFile, IProgressMonitor monitor) 
 throws Exception { 
  if (monitor == null) monitor = new NullProgressMonitor(); 
 
  HttpClient client = new HttpClient(); 
  datasetURI = normalizeURI(datasetURI); 
  PutMethod method = new PutMethod(datasetURI); 
  HttpMethodHelper.addMethodHeaders(method, 
   new HashMap<String,String>() {{ 
    put("Accept""text/uri-list"); 
    put("Content-type""chemical/x-mdl-sdfile"); 
   }} 
  ); 
  method.setRequestBody(sdFile); 
  client.executeMethod(method); 
  int status = method.getStatusCode(); 
  String dataset = ""
  String responseString = method.getResponseBodyAsString(); 
  logger.debug("Response: " + responseString); 
  int tailing = 1
  if (status == 200) { 
   // OK, that was quick! 
   dataset = method.getResponseBodyAsString(); 
   logger.debug("No Task, Data set: " + dataset); 
  else if (status == 202 || status == 201) { 
   // OK, we got a task... let's wait until it is done 
   String task = method.getResponseBodyAsString(); 
   Thread.sleep(1000); // let's be friendly, and wait 1 sec 
   TaskState state = Task.getState(task); 
   while (!state.isFinished() && !monitor.isCanceled()) { 
    // 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("  new task, 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 { 
   logger.warn("Unexpected return code when adding molecules: " + status); 
  
  method.releaseConnection(); 
 
 
 public static String createNewDataset(String service, 
  List<IMolecule> molecules, IProgressMonitor monitor) 
 throws Exception { 
  StringWriter strWriter = new StringWriter(); 
  SDFWriter writer = new SDFWriter(strWriter); 
  for (IMolecule mol : molecules) { 
   writer.write(cdk.asCDKMolecule(mol).getAtomContainer()); 
  
  writer.close(); 
  return createNewDataset(normalizeURI(service), strWriter.toString(), monitor); 
 
 
 public static String createNewDataset(String service, IMolecule mol, 
  IProgressMonitor monitor) 
 throws Exception { 
  StringWriter strWriter = new StringWriter(); 
  SDFWriter writer = new SDFWriter(strWriter); 
  writer.write(cdk.asCDKMolecule(mol).getAtomContainer()); 
  writer.close(); 
  return createNewDataset(service, strWriter.toString(), monitor); 
 
 
 public static String createNewDataset(String service, IProgressMonitor monitor) 
 throws Exception { 
  StringWriter strWriter = new StringWriter(); 
  SDFWriter writer = new SDFWriter(strWriter); 
  writer.write(new AtomContainer()); 
  writer.close(); 
  return createNewDataset(service, strWriter.toString(), monitor); 
 
 
 public static String createNewDataset
  String service, String sdFile, IProgressMonitor monitor) 
 throws Exception { 
  if (monitor == null) monitor = new NullProgressMonitor(); 
 
  HttpClient client = new HttpClient(); 
  PostMethod method = new PostMethod(service + "dataset"); 
  HttpMethodHelper.addMethodHeaders(method, 
   new HashMap<String,String>() {{ 
    put("Accept""text/uri-list"); 
    put("Content-type""chemical/x-mdl-sdfile"); 
   }} 
  ); 
  System.out.println("Method: " + method.toString()); 
  method.setRequestBody(sdFile); 
  client.executeMethod(method); 
  int status = method.getStatusCode(); 
  String dataset = ""
  String responseString = method.getResponseBodyAsString(); 
  logger.debug("Response: " + responseString); 
  int tailing = 1
  if (status == 200 || status == 201 || status == 202) { 
   if (responseString.contains("/task/")) { 
    logger.debug("Task: " + responseString); 
    // OK, we got a task... let's wait until it is done 
    String task = method.getResponseBodyAsString(); 
    Thread.sleep(1000); // let's be friendly, and wait 1 sec 
    TaskState state = Task.getState(task); 
    while (!state.isFinished() && !monitor.isCanceled()) { 
     // 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("  new task, 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 = method.getResponseBodyAsString(); 
    logger.debug("No Task, Data set: " + dataset); 
   
  
  method.releaseConnection(); 
  if (monitor.isCanceled()) return ""
  logger.debug("Data set: " + dataset); 
  dataset = dataset.replaceAll("\n"""); 
  return dataset; 
 
 
 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())); 
 
 
 public static void main(String[] args) throws Exception { 
//  String service = "http://194.141.0.136:8080/"; 
  String service = "http://apps.ideaconsult.net:8080/ambit2/"
//  List<String> sets = getListOfAvailableDatasets(service); 
//  for (String set : sets) System.out.println(set); 
  String dataset = createNewDataset(service, null); 
  List<IMolecule> mols = new ArrayList<IMolecule>(); 
  mols.add(cdk.fromSMILES("COC")); 
  mols.add(cdk.fromSMILES("CNC")); 
  mols.add(cdk.fromSMILES("CC")); 
  addMolecules(dataset, mols); 
//  deleteDataset(dataset); 
 
 
}