001package org.biopax.paxtools.client; 002 003/* 004 * #%L 005 * BioPAX Validator Client 006 * %% 007 * Copyright (C) 2008 - 2013 University of Toronto (baderlab.org) and Memorial Sloan-Kettering Cancer Center (cbio.mskcc.org) 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU Lesser General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Lesser Public License for more details. 018 * 019 * You should have received a copy of the GNU General Lesser Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/lgpl-3.0.html>. 022 * #L% 023 */ 024 025import org.apache.commons.logging.Log; 026import org.apache.commons.logging.LogFactory; 027import org.apache.http.Header; 028import org.apache.http.HttpEntity; 029import org.apache.http.HttpResponse; 030import org.apache.http.client.ClientProtocolException; 031import org.apache.http.client.ResponseHandler; 032import org.apache.http.client.fluent.Executor; 033import org.apache.http.client.fluent.Request; 034import org.apache.http.entity.ContentType; 035import org.apache.http.entity.mime.MultipartEntityBuilder; 036import org.biopax.validator.jaxb.Behavior; 037import org.biopax.validator.jaxb.ValidatorResponse; 038 039import javax.xml.bind.JAXBContext; 040import javax.xml.bind.JAXBException; 041import javax.xml.bind.Unmarshaller; 042import javax.xml.transform.Source; 043import javax.xml.transform.stream.StreamSource; 044 045import java.io.BufferedReader; 046import java.io.File; 047import java.io.IOException; 048import java.io.OutputStream; 049import java.io.PrintWriter; 050import java.io.StringReader; 051import java.nio.charset.Charset; 052 053/** 054 * Simple (example) BioPAX Validator client 055 * to upload and check BioPAX OWL files. 056 * 057 * @author rodche 058 * 059 */ 060public class BiopaxValidatorClient { 061 private static final Log log = LogFactory.getLog(BiopaxValidatorClient.class); 062 063 /** 064 * Default BioPAX Validator's URL 065 */ 066 public static final String 067 DEFAULT_VALIDATOR_URL = "http://www.biopax.org/validator/check.html"; 068 069 /** 070 * The Java Option to set a BioPAX Validator URL 071 * (if set, overrides the default and URL provided by the Constructor arg.) 072 */ 073 public static final String JVM_PROPERTY_URL = "biopax.validator.url"; 074 075 public static enum RetFormat { 076 HTML,// errors as HTML/Javascript 077 XML, // errors as XML 078 OWL; // modified BioPAX only (when 'autofix' or 'normalize' is true) 079 } 080 081 private String url; 082 083 084 /** 085 * Main Constructor 086 * 087 * It configures for the validator's URL 088 * (defined by DEFAULT_VALIDATOR_URL constant) 089 * and result format (). 090 * 091 * @param url - validator's file-upload form address 092 */ 093 public BiopaxValidatorClient(String url) { 094// if(url == null || url.isEmpty()) 095// this.url = System.getProperty(JVM_PROPERTY_URL, DEFAULT_VALIDATOR_URL); 096// else 097// this.url = url; 098// 099 // 1) use the arg (if not empty/null) or the default URL 100 this.url = (url == null || url.isEmpty()) 101 ? DEFAULT_VALIDATOR_URL : url; 102 103 // 2) override if the JVM option is set to another value 104 this.url = System.getProperty(JVM_PROPERTY_URL, this.url); 105 106 // 3) get actual location (force through redirects, if any) 107 try { 108 this.url = location(this.url); 109// System.out.println("Location: " + this.url); 110 } catch (IOException e) { 111 log.warn("Failed to resolve to actual web service " + 112 "URL using: " + url + " (if there is a 301/302/307 HTTP redirect, " + 113 "then validation requests (using HTTP POST method) will probably fail...)", e); 114 } 115 } 116 117 118 /** 119 * Default Constructor 120 * 121 * It configures for the default validator URL. 122 */ 123 public BiopaxValidatorClient() { 124 this(null); 125 } 126 127 128 /** 129 * Checks a BioPAX OWL file(s) or resource 130 * using the online BioPAX Validator 131 * and prints the results to the output stream. 132 * 133 * @param autofix true/false (experimental) 134 * @param profile validation profile name 135 * @param retFormat xml, html, or owl (no errors, just modified owl, if autofix=true) 136 * @param filterBy filter validation issues by the error/warning level 137 * @param maxErrs errors threshold - max no. critical errors to collect before quitting 138 * (warnings not counted; null/0/negative value means unlimited) 139 * @param biopaxUrl check the BioPAX at the URL 140 * @param biopaxFiles an array of BioPAX files to validate 141 * @param out validation report data output stream 142 * @throws IOException when there is an I/O error 143 */ 144 public void validate(boolean autofix, String profile, RetFormat retFormat, Behavior filterBy, 145 Integer maxErrs, String biopaxUrl, File[] biopaxFiles, OutputStream out) throws IOException 146 { 147 MultipartEntityBuilder meb = MultipartEntityBuilder.create(); 148 meb.setCharset(Charset.forName("UTF-8")); 149 150 if(autofix) 151 meb.addTextBody("autofix", "true"); 152//TODO add extra options (normalizer.fixDisplayName, normalizer.inferPropertyOrganism, normalizer.inferPropertyDataSource, normalizer.xmlBase)? 153 if(profile != null && !profile.isEmpty()) 154 meb.addTextBody("profile", profile); 155 if(retFormat != null) 156 meb.addTextBody("retDesired", retFormat.toString().toLowerCase()); 157 if(filterBy != null) 158 meb.addTextBody("filter", filterBy.toString()); 159 if(maxErrs != null && maxErrs > 0) 160 meb.addTextBody("maxErrors", maxErrs.toString()); 161 if(biopaxFiles != null && biopaxFiles.length > 0) 162 for (File f : biopaxFiles) //important: use MULTIPART_FORM_DATA content-type 163 meb.addBinaryBody("file", f, ContentType.MULTIPART_FORM_DATA, f.getName()); 164 else if(biopaxUrl != null) { 165 meb.addTextBody("url", biopaxUrl); 166 } else { 167 log.error("Nothing to do (no BioPAX data specified)!"); 168 return; 169 } 170 171 //execute the query and get results as string 172 HttpEntity httpEntity = meb.build(); 173// httpEntity.writeTo(System.err); 174 String content = Executor.newInstance()//Executor.newInstance(httpClient) 175 .execute(Request.Post(url).body(httpEntity)) 176 .returnContent().asString(); 177 178 //save: append to the output stream (file) 179 BufferedReader res = new BufferedReader(new StringReader(content)); 180 String line; 181 PrintWriter writer = new PrintWriter(out); 182 while((line = res.readLine()) != null) { 183 writer.println(line); 184 } 185 writer.flush(); 186 res.close(); 187 } 188 189 public void setUrl(String url) { 190 this.url = url; 191 } 192 193 public String getUrl() { 194 return url; 195 } 196 197 /** 198 * Converts a biopax-validator XML response to the java object. 199 * 200 * @param xml input XML data - validation report - to import 201 * @return validation report object 202 * @throws JAXBException when there is an JAXB unmarshalling error 203 */ 204 public static ValidatorResponse unmarshal(String xml) throws JAXBException { 205 JAXBContext jaxbContext = JAXBContext.newInstance("org.biopax.validator.jaxb"); 206 Unmarshaller un = jaxbContext.createUnmarshaller(); 207 Source src = new StreamSource(new StringReader(xml)); 208 ValidatorResponse resp = un.unmarshal(src, ValidatorResponse.class).getValue(); 209 return resp; 210 } 211 212 213 private String location(final String url) throws IOException { 214 String location = url; //initially the same 215 // discover actual location, avoid going in circles: 216 int i=0; 217 for(String loc = url; loc != null && i<5; i++ ) 218 { 219 //do POST for location (Location header present if there's a 301/302/307 redirect on the way) 220 loc = Request.Post(loc).execute() 221 .handleResponse(new ResponseHandler<String>() { 222 @Override 223 public String handleResponse(HttpResponse httpResponse) 224 throws ClientProtocolException, IOException { 225 Header header = httpResponse.getLastHeader("Location"); 226// System.out.println("header=" + header); 227 return (header != null) ? header.getValue().trim() : null; 228 } 229 }); 230 231 if(loc != null) { 232 location = loc; 233 log.info("BioPAX Validator location: " + loc); 234 } 235 } 236 237 return location; 238 } 239 240}