package net.sf.taverna.biocatalogue.model.connectivity; | |
import java.io.*; | |
import java.net.*; | |
import java.text.DateFormat; | |
import java.text.SimpleDateFormat; | |
import java.util.ArrayList; | |
import java.util.Calendar; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Properties; | |
import net.sf.taverna.biocatalogue.model.BioCataloguePluginConstants; | |
import net.sf.taverna.biocatalogue.model.Pair; | |
import net.sf.taverna.biocatalogue.model.Resource.TYPE; | |
import net.sf.taverna.biocatalogue.model.SoapOperationIdentity; | |
import net.sf.taverna.biocatalogue.model.SoapOperationPortIdentity; | |
import net.sf.taverna.biocatalogue.model.Util; | |
import net.sf.taverna.biocatalogue.model.connectivity.BeansForJSONLiteAPI.ResourceIndex; | |
import net.sf.taverna.t2.ui.perspectives.biocatalogue.integration.config.BioCataloguePluginConfiguration; | |
import org.apache.log4j.Logger; | |
import org.biocatalogue.x2009.xml.rest.Annotations; | |
import org.biocatalogue.x2009.xml.rest.AnnotationsDocument; | |
import org.biocatalogue.x2009.xml.rest.CollectionCoreStatistics; | |
import org.biocatalogue.x2009.xml.rest.Filters; | |
import org.biocatalogue.x2009.xml.rest.FiltersDocument; | |
import org.biocatalogue.x2009.xml.rest.ResourceLink; | |
import org.biocatalogue.x2009.xml.rest.RestMethod; | |
import org.biocatalogue.x2009.xml.rest.RestMethodDocument; | |
import org.biocatalogue.x2009.xml.rest.RestMethods; | |
import org.biocatalogue.x2009.xml.rest.RestMethodsDocument; | |
import org.biocatalogue.x2009.xml.rest.Search; | |
import org.biocatalogue.x2009.xml.rest.SearchDocument; | |
import org.biocatalogue.x2009.xml.rest.Service; | |
import org.biocatalogue.x2009.xml.rest.ServiceDocument; | |
import org.biocatalogue.x2009.xml.rest.ServiceProvider; | |
import org.biocatalogue.x2009.xml.rest.ServiceProviderDocument; | |
import org.biocatalogue.x2009.xml.rest.ServiceProviders; | |
import org.biocatalogue.x2009.xml.rest.ServiceProvidersDocument; | |
import org.biocatalogue.x2009.xml.rest.Services; | |
import org.biocatalogue.x2009.xml.rest.ServicesDocument; | |
import org.biocatalogue.x2009.xml.rest.SoapInput; | |
import org.biocatalogue.x2009.xml.rest.SoapInputDocument; | |
import org.biocatalogue.x2009.xml.rest.SoapOperation; | |
import org.biocatalogue.x2009.xml.rest.SoapOperationDocument; | |
import org.biocatalogue.x2009.xml.rest.SoapOperations; | |
import org.biocatalogue.x2009.xml.rest.SoapOperationsDocument; | |
import org.biocatalogue.x2009.xml.rest.SoapOutput; | |
import org.biocatalogue.x2009.xml.rest.SoapOutputDocument; | |
import org.biocatalogue.x2009.xml.rest.SoapService; | |
import org.biocatalogue.x2009.xml.rest.SoapServiceDocument; | |
import org.biocatalogue.x2009.xml.rest.Tag; | |
import org.biocatalogue.x2009.xml.rest.TagDocument; | |
import org.biocatalogue.x2009.xml.rest.Tags; | |
import org.biocatalogue.x2009.xml.rest.TagsDocument; | |
import org.biocatalogue.x2009.xml.rest.User; | |
import org.biocatalogue.x2009.xml.rest.UserDocument; | |
import org.biocatalogue.x2009.xml.rest.Users; | |
import org.biocatalogue.x2009.xml.rest.UsersDocument; | |
import com.google.gson.Gson; | |
/** | |
* @author Sergejs Aleksejevs | |
*/ | |
public class BioCatalogueClient | |
{ | |
// ******* CONSTANTS ******* | |
// plugin details | |
public static final String PLUGIN_VERSION = "0.1.1"; | |
public static final String PLUGIN_USER_AGENT = "Taverna2-ServiceCatalogue-plugin/" + | |
PLUGIN_VERSION + | |
" Java/" + System.getProperty("java.version"); | |
public static final String XML_MIME_TYPE = "application/xml"; | |
public static final String JSON_MIME_TYPE = "application/json"; | |
public static final String LITE_JSON_MIME_TYPE = "application/biocat-lite+json"; | |
public static final String XML_DATA_FORMAT = ".xml"; | |
public static final String JSON_DATA_FORMAT = ".json"; | |
public static final String LITE_JSON_DATA_FORMAT = ".bljson"; | |
// API URLs | |
public static final String DEFAULT_API_SANDBOX_BASE_URL = "http://sandbox.biocatalogue.org"; | |
public static final String DEFAULT_API_TEST_SERVER_BASE_URL = "http://test.biocatalogue.org"; | |
public static final String DEFAULT_API_LIVE_SERVER_BASE_URL = "http://www.biocatalogue.org"; | |
private static String BASE_URL; // BioCatalogue base URL to use (can be updated at runtime) | |
public static String API_REGISTRIES_URL; | |
public static String API_SERVICE_PROVIDERS_URL; | |
public static String API_USERS_URL; | |
public static String API_USER_FILTERS_URL; | |
public static String API_SERVICES_URL; | |
public static String API_SERVICE_FILTERS_URL; | |
public static String API_SOAP_OPERATIONS_URL; | |
public static String API_SOAP_OPERATION_FILTERS_URL; | |
public static String API_REST_METHODS_URL; | |
public static String API_REST_METHOD_FILTERS_URL; | |
public static String API_TAG_CLOUD_URL; | |
public static String API_SEARCH_URL; | |
public static String API_LOOKUP_URL; | |
// URL modifiers | |
public static final Map<String,String> API_INCLUDE_SUMMARY = Collections.singletonMap("include","summary"); // for fetching Service | |
public static final Map<String,String> API_INCLUDE_ANCESTORS = Collections.singletonMap("include", "ancestors,inputs,outputs"); // for fetching SOAP Operations and REST Methods | |
public static final String[] API_SORT_BY_NAME = {"sort","name"}; // for tag cloud | |
public static final String[] API_SORT_BY_COUNTS = {"sort","counts"}; // for tag cloud | |
public static final String[] API_ALSO_INPUTS_OUTPUTS = {"also","inputs,outputs"}; // for annotations on SOAP operation | |
public static final String API_PER_PAGE_PARAMETER = "per_page"; | |
public static final String API_PAGE_PARAMETER = "page"; | |
public static final String API_LIMIT_PARAMETER = "limit"; | |
public static final String API_SERVICE_MONITORING_URL_SUFFIX = "/monitoring"; | |
public static final String API_FILTERED_INDEX_SUFFIX = "/filtered_index"; | |
// API Request scope | |
public static final String API_SCOPE_PARAMETER = "scope"; | |
public static final String API_SCOPE_SOAP_OPERATIONS = "soap_operations"; | |
public static final String API_SCOPE_REST_METHODS = "rest_methods"; | |
public static final String API_SCOPE_SERVICES = "services"; | |
public static final String API_SCOPE_SERVICE_PROVIDERS = "service_providers"; | |
public static final String API_SCOPE_REGISTRIES = "registries"; | |
public static final String API_SCOPE_USERS = "users"; | |
public static final String API_TAG_PARAMETER = "tag"; | |
public static final String API_LOOKUP_WSDL_LOCATION_PARAMETER = "wsdl_location"; | |
public static final String API_LOOKUP_OPERATION_NAME_PARAMETER = "operation_name"; | |
public static final String API_LOOKUP_SOAP_INPUT_NAME_PARAMETER = "input_name"; | |
public static final String API_LOOKUP_SOAP_OUTPUT_NAME_PARAMETER = "output_name"; | |
// ************************* | |
// universal date formatters | |
private static final DateFormat DATE_FORMATTER = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy"); | |
private static final DateFormat SHORT_DATE_FORMATTER = new SimpleDateFormat("HH:mm 'on' dd/MM/yyyy"); | |
private static final DateFormat API_LOGGING_TIMESTAMP_FORMATTER = DateFormat.getDateTimeInstance(); | |
// SETTINGS | |
private Properties iniSettings; // settings that are read/stored from/to INI file | |
private File fAPIOperationLog; | |
private PrintWriter pwAPILogWriter; | |
// the logger | |
private Logger logger = Logger.getLogger(BioCatalogueClient.class); | |
private static BioCatalogueClient INSTANCE; | |
// default constructor | |
private BioCatalogueClient() | |
{ | |
// TODO: load any config settings (if necessary) | |
// load the BioCatalogue API base URL from the plugin's configuration settings | |
this.setBaseURL(BioCataloguePluginConfiguration.getInstance(). | |
getProperty(BioCataloguePluginConfiguration.SERVICE_CATALOGUE_BASE_URL)); | |
// open API operation log file, if necessary | |
if (BioCataloguePluginConstants.PERFORM_API_RESPONSE_TIME_LOGGING || | |
BioCataloguePluginConstants.PERFORM_API_XML_DATA_BINDING_TIME_LOGGING ) | |
{ | |
try { | |
BioCataloguePluginConstants.LOG_FILE_FOLDER.mkdirs(); // just in case this log file was never written - create the folder as well | |
fAPIOperationLog = new File(BioCataloguePluginConstants.LOG_FILE_FOLDER, | |
BioCataloguePluginConstants.API_OPERATION_LOG_FILENAME); | |
pwAPILogWriter = new PrintWriter(new FileOutputStream(fAPIOperationLog, true), true); // auto-flush makes sure that even if app crashes, log will not be lost | |
} | |
catch (NullPointerException e) { | |
pwAPILogWriter = new PrintWriter(System.out, true); | |
logger.error("ERROR: Folder to log API operation details is unknown (using System.out instead)... Details:", e); | |
} | |
catch (FileNotFoundException e) { | |
logger.error("ERROR: Couldn't open API operation log file... Details:", e); | |
} | |
} | |
} | |
public static synchronized BioCatalogueClient getInstance() { | |
if (INSTANCE == null) { | |
INSTANCE = new BioCatalogueClient(); | |
} | |
return INSTANCE; | |
} | |
public String getBaseURL() { | |
return this.BASE_URL; | |
} | |
/** | |
* Updates the base API URL and also | |
* updates derived URLs of sub-URLs | |
* (e.g. BASE_URL + /services, etc) | |
* | |
* @param baseURL The new value for the BioCatalogue API base URL. | |
*/ | |
public void setBaseURL(String baseURL) | |
{ | |
// make sure the base URL doesn't have a slash at the end | |
// (otherwise double slashes may occur during URL manipulation) | |
while (baseURL.endsWith("/")) { baseURL = baseURL.substring(0, baseURL.length() - 1); } | |
this.BASE_URL = baseURL; | |
API_REGISTRIES_URL = BASE_URL + "/registries"; | |
API_SERVICE_PROVIDERS_URL = BASE_URL + "/service_providers"; | |
API_USERS_URL = BASE_URL + "/users"; | |
API_USER_FILTERS_URL = API_USERS_URL + "/filters"; | |
API_SERVICES_URL = BASE_URL + "/services"; | |
API_SERVICE_FILTERS_URL = API_SERVICES_URL + "/filters"; | |
API_SOAP_OPERATIONS_URL = BASE_URL + "/soap_operations"; | |
API_SOAP_OPERATION_FILTERS_URL = API_SOAP_OPERATIONS_URL + "/filters"; | |
API_REST_METHODS_URL = BASE_URL + "/rest_methods"; | |
API_REST_METHOD_FILTERS_URL = API_REST_METHODS_URL + "/filters"; | |
API_TAG_CLOUD_URL = BASE_URL + "/tags"; | |
API_SEARCH_URL = BASE_URL + "/search"; | |
API_LOOKUP_URL = BASE_URL + "/lookup"; | |
} | |
public File getAPIOperationLog() { | |
return fAPIOperationLog; | |
} | |
public PrintWriter getAPILogWriter() { | |
return pwAPILogWriter; | |
} | |
// ************ METHODS FOR RETRIEVAL OF SPECIALISED OBJECT FROM THE API VIA XML ************ | |
public Annotations getBioCatalogueAnnotations(String strAnnotationsURL) throws Exception { | |
return (parseAPIResponseStream(Annotations.class, doBioCatalogueGET(strAnnotationsURL))); | |
} | |
public Filters getBioCatalogueFilters(String strURL) throws Exception { | |
return (parseAPIResponseStream(Filters.class, doBioCatalogueGET(strURL))); | |
} | |
public Services getBioCatalogueServices(String strURL) throws Exception { | |
return (parseAPIResponseStream(Services.class, doBioCatalogueGET(strURL))); | |
} | |
public Service getBioCatalogueService(String serviceURL) throws Exception { | |
return (parseAPIResponseStream(Service.class, doBioCatalogueGET(serviceURL))); | |
} | |
public Service getBioCatalogueServiceSummary(String serviceURL) throws Exception { | |
return (parseAPIResponseStream(Service.class, doBioCatalogueGET(Util.appendAllURLParameters(serviceURL, API_INCLUDE_SUMMARY)))); | |
} | |
public Service getBioCatalogueServiceMonitoringData(String serviceURL) throws Exception | |
{ | |
return (parseAPIResponseStream(Service.class, | |
doBioCatalogueGET(serviceURL + API_SERVICE_MONITORING_URL_SUFFIX)) | |
); | |
} | |
public SoapService getBioCatalogueSoapService(String soapServiceURL) throws Exception { | |
return (parseAPIResponseStream(SoapService.class, doBioCatalogueGET(soapServiceURL))); | |
} | |
public SoapOperation getBioCatalogueSoapOperation(String soapOperationURL) throws Exception { | |
return (parseAPIResponseStream(SoapOperation.class, doBioCatalogueGET(soapOperationURL))); | |
} | |
public RestMethod getBioCatalogueRestMethod(String restMethodURL) throws Exception { | |
return (parseAPIResponseStream(RestMethod.class, doBioCatalogueGET(restMethodURL))); | |
} | |
public Search getBioCatalogueSearchData(String searchURL) throws Exception { | |
return (parseAPIResponseStream(Search.class, doBioCatalogueGET(searchURL))); | |
} | |
public Tag getBioCatalogueTag(String searchByTagURL) throws Exception { | |
return (parseAPIResponseStream(Tag.class, doBioCatalogueGET(searchByTagURL))); | |
} | |
public Tags getBioCatalogueTags(String tagsURL) throws Exception { | |
return (parseAPIResponseStream(Tags.class, doBioCatalogueGET(tagsURL))); | |
} | |
public ResourceLink getBioCatalogueResource(Class<? extends ResourceLink> classOfResourceToFetch, String resourceURL) throws Exception { | |
return (parseAPIResponseStream(classOfResourceToFetch, doBioCatalogueGET(resourceURL))); | |
} | |
public <T extends ResourceLink> Pair<CollectionCoreStatistics, List<T>> getListOfItemsFromResourceCollectionIndex( | |
Class<T> classOfCollectionOfRequiredReturnedObjects, BioCatalogueAPIRequest filteringRequest) throws Exception | |
{ | |
ResourceLink matchingItems = null; | |
if (filteringRequest.getRequestType() == BioCatalogueAPIRequest.TYPE.GET) { | |
matchingItems = parseAPIResponseStream(classOfCollectionOfRequiredReturnedObjects, doBioCatalogueGET(filteringRequest.getURL())); | |
} | |
else { | |
matchingItems = parseAPIResponseStream(classOfCollectionOfRequiredReturnedObjects, | |
doBioCataloguePOST_SendJSON_AcceptXML(filteringRequest.getURL(), filteringRequest.getData())); | |
} | |
CollectionCoreStatistics statistics = null; | |
List<T> matchingItemList = new ArrayList<T>(); | |
// SOAP Operations | |
if (classOfCollectionOfRequiredReturnedObjects.equals(SoapOperations.class)) { | |
SoapOperations soapOperations = (SoapOperations)matchingItems; | |
matchingItemList.addAll((Collection<? extends T>)(soapOperations.getResults().getSoapOperationList())); | |
statistics = soapOperations.getStatistics(); | |
} | |
// REST Methods | |
else if (classOfCollectionOfRequiredReturnedObjects.equals(RestMethods.class)) { | |
RestMethods restMethods = (RestMethods)matchingItems; | |
matchingItemList.addAll((Collection<? extends T>)(restMethods.getResults().getRestMethodList())); | |
statistics = restMethods.getStatistics(); | |
} | |
// Services | |
else if (classOfCollectionOfRequiredReturnedObjects.equals(Services.class)) { | |
Services services = (Services)matchingItems; | |
matchingItemList.addAll((Collection<? extends T>)(services.getResults().getServiceList())); | |
statistics = services.getStatistics(); | |
} | |
// Service Providers | |
else if (classOfCollectionOfRequiredReturnedObjects.equals(ServiceProviders.class)) { | |
ServiceProviders serviceProviders = (ServiceProviders)matchingItems; | |
matchingItemList.addAll((Collection<? extends T>)(serviceProviders.getResults().getServiceProviderList())); | |
statistics = serviceProviders.getStatistics(); | |
} | |
// Users | |
else if (classOfCollectionOfRequiredReturnedObjects.equals(Users.class)) { | |
Users users = (Users)matchingItems; | |
matchingItemList.addAll((Collection<? extends T>)(users.getResults().getUserList())); | |
statistics = users.getStatistics(); | |
} | |
// no such option - error | |
else { | |
return null; | |
} | |
return new Pair<CollectionCoreStatistics, List<T>>(statistics, matchingItemList); | |
} | |
/** | |
* @param wsdlLocation | |
* @param operationName | |
* @return SoapOperation instance or <code>null</code> if nothing was found (or error occurred). | |
* @throws Exception | |
*/ | |
public SoapOperation lookupSoapOperation(SoapOperationIdentity soapOperationDetails) throws Exception | |
{ | |
// first of all check for any problems with input data | |
if (soapOperationDetails == null || soapOperationDetails.hasError() || | |
soapOperationDetails.getWsdlLocation() == null || soapOperationDetails.getWsdlLocation().length() == 0 || | |
soapOperationDetails.getOperationName() == null || soapOperationDetails.getOperationName().length() == 0) | |
{ | |
// something's not right - return null | |
return (null); | |
} | |
String lookupURL = Util.appendURLParameter(API_LOOKUP_URL, API_LOOKUP_WSDL_LOCATION_PARAMETER, soapOperationDetails.getWsdlLocation()); | |
lookupURL = Util.appendURLParameter(lookupURL, API_LOOKUP_OPERATION_NAME_PARAMETER, soapOperationDetails.getOperationName()); | |
ServerResponseStream lookupResponse = doBioCatalogueGET(lookupURL); | |
if (lookupResponse.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) { | |
return null; | |
} | |
return (parseAPIResponseStream(SoapOperation.class, lookupResponse)); | |
} | |
public <T extends ResourceLink> T lookupSoapOperationPort(Class<T> requiredResultClass, SoapOperationPortIdentity portDetails) throws Exception | |
{ | |
// first of all check for any problems with port details | |
if (portDetails == null || portDetails.hasError() || | |
portDetails.getWsdlLocation() == null || portDetails.getWsdlLocation().length() == 0 || | |
portDetails.getOperationName() == null || portDetails.getOperationName().length() == 0 || | |
portDetails.getPortName() == null || portDetails.getPortName().length() == 0) | |
{ | |
// something's not right - return null | |
return (null); | |
} | |
// now check that specified class matches the port type | |
if (portDetails.isInput() && !requiredResultClass.equals(SoapInput.class) || | |
!portDetails.isInput() && !requiredResultClass.equals(SoapOutput.class)) | |
{ | |
return (null); | |
} | |
String lookupURL = Util.appendURLParameter(API_LOOKUP_URL, API_LOOKUP_WSDL_LOCATION_PARAMETER, portDetails.getWsdlLocation()); | |
lookupURL = Util.appendURLParameter(lookupURL, API_LOOKUP_OPERATION_NAME_PARAMETER, portDetails.getOperationName()); | |
if (portDetails.isInput()) { | |
lookupURL = Util.appendURLParameter(lookupURL, API_LOOKUP_SOAP_INPUT_NAME_PARAMETER, portDetails.getPortName()); | |
} | |
else { | |
lookupURL = Util.appendURLParameter(lookupURL, API_LOOKUP_SOAP_OUTPUT_NAME_PARAMETER, portDetails.getPortName()); | |
} | |
ServerResponseStream lookupResponse = doBioCatalogueGET(lookupURL); | |
if (lookupResponse.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) { | |
return null; | |
} | |
return (parseAPIResponseStream(requiredResultClass, lookupResponse)); | |
} | |
public Service lookupParentService(SoapOperationIdentity soapOperationDetails) throws Exception | |
{ | |
SoapOperation soapOperation = this.lookupSoapOperation(soapOperationDetails); | |
if (soapOperation != null) { | |
return (getBioCatalogueService(soapOperation.getAncestors().getService().getHref())); | |
} | |
else { | |
// lookup didn't find the SOAP operation or there | |
// was some problem with the input data | |
return (null); | |
} | |
} | |
public Service lookupParentServiceMonitoringData(SoapOperationIdentity soapOperationDetails) throws Exception | |
{ | |
SoapOperation soapOperation = this.lookupSoapOperation(soapOperationDetails); | |
if (soapOperation != null) { | |
return (getBioCatalogueServiceMonitoringData(soapOperation.getAncestors().getService().getHref())); | |
} | |
else { | |
// lookup didn't find the SOAP operation or there | |
// was some problem with the input data | |
return (null); | |
} | |
} | |
// ************ METHODS FOR RETRIEVAL OF SPECIALISED OBJECT FROM THE API VIA LITE JSON ************ | |
public BeansForJSONLiteAPI.ResourceIndex getBioCatalogueResourceLiteIndex(TYPE resourceType, String resourceIndexURL) throws Exception | |
{ | |
ServerResponseStream response = doBioCatalogueGET_LITE_JSON(resourceIndexURL); | |
Gson gson = new Gson(); | |
return (ResourceIndex)(gson.fromJson(new InputStreamReader(response.getResponseStream()), resourceType.getJsonLiteAPIBindingBeanClass())); | |
} | |
public BeansForJSONLiteAPI.ResourceIndex postBioCatalogueResourceLiteIndex(TYPE resourceType, String resourceIndexURL, String postData) throws Exception | |
{ | |
ServerResponseStream response = doBioCataloguePOST_SendJSON_AcceptLITEJSON(resourceIndexURL, postData); | |
Gson gson = new Gson(); | |
return (ResourceIndex)(gson.fromJson(new InputStreamReader(response.getResponseStream()), resourceType.getJsonLiteAPIBindingBeanClass())); | |
} | |
// ************ GENERIC API CONNECTIVITY METHODS ************ | |
/** | |
* Generic method to issue GET requests to BioCatalogue server. | |
* | |
* This is a convenience method to be used instead of {@link BioCatalogueClient#doBioCatalogueGET_XML(String)}. | |
* | |
* @param strURL The URL on BioCatalogue to issue GET request to. | |
* @return TODO | |
* @throws Exception | |
*/ | |
public ServerResponseStream doBioCatalogueGET(String strURL) throws Exception { | |
return (doBioCatalogueGET_XML(strURL)); | |
} | |
public ServerResponseStream doBioCatalogueGET_XML(String strURL) throws Exception { | |
return (doBioCatalogueGET(strURL, XML_MIME_TYPE, XML_DATA_FORMAT)); | |
} | |
public ServerResponseStream doBioCatalogueGET_JSON(String strURL) throws Exception { | |
return (doBioCatalogueGET(strURL, JSON_MIME_TYPE, JSON_DATA_FORMAT)); | |
} | |
public ServerResponseStream doBioCatalogueGET_LITE_JSON(String strURL) throws Exception { | |
return (doBioCatalogueGET(strURL, LITE_JSON_MIME_TYPE, LITE_JSON_DATA_FORMAT)); | |
} | |
public ServerResponseStream doBioCatalogueGET(String strURL, String ACCEPT_HEADER, String REQUESTED_DATA_FORMAT) throws Exception | |
{ | |
// TODO - HACK to speed up processing append .xml / .json / .bljson to all URLs to avoid LinkedData content negotiation | |
strURL = Util.appendStringBeforeParametersOfURL(strURL, REQUESTED_DATA_FORMAT); | |
// open server connection using provided URL (with no further modifications to it) | |
URL url = new URL(strURL); | |
Calendar requestStartedAt = Calendar.getInstance(); | |
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); | |
conn.setRequestProperty("User-Agent", PLUGIN_USER_AGENT); | |
conn.setRequestProperty("Accept", ACCEPT_HEADER); | |
// if(LOGGED_IN) { | |
// // if the user has "logged in", also add authentication details | |
// conn.setRequestProperty("Authorization", "Basic " + AUTH_STRING); | |
// } | |
// fetch server's response | |
ServerResponseStream serverResponse = doBioCatalogueReceiveServerResponse(conn, strURL, true); | |
if (BioCataloguePluginConstants.PERFORM_API_RESPONSE_TIME_LOGGING) { | |
logAPIOperation(requestStartedAt, "GET", serverResponse); | |
} | |
return (serverResponse); | |
} | |
public ServerResponseStream doBioCataloguePOST_SendJSON_AcceptXML(String strURL, String strDataBody) throws Exception { | |
return (doBioCataloguePOST(strURL, strDataBody, JSON_MIME_TYPE, XML_MIME_TYPE, XML_DATA_FORMAT)); | |
} | |
public ServerResponseStream doBioCataloguePOST_SendJSON_AcceptLITEJSON(String strURL, String strDataBody) throws Exception { | |
return (doBioCataloguePOST(strURL, strDataBody, JSON_MIME_TYPE, LITE_JSON_MIME_TYPE, LITE_JSON_DATA_FORMAT)); | |
} | |
/** | |
* Generic method to execute POST requests to BioCatalogue server. | |
* | |
* @param strURL The URL on BioCatalogue to POST to. | |
* @param strDataBody Body of the message to be POSTed to <code>strURL</code>. | |
* @return An object containing server's response body as an InputStream and | |
* a response code. | |
* @param CONTENT_TYPE_HEADER MIME type of the sent data. | |
* @param ACCEPT_HEADER MIME type of the data to be received. | |
* @param REQUESTED_DATA_FORMAT | |
* @throws Exception | |
*/ | |
public ServerResponseStream doBioCataloguePOST(String strURL, String strDataBody, String CONTENT_TYPE_HEADER, | |
String ACCEPT_HEADER, String REQUESTED_DATA_FORMAT) throws Exception | |
{ | |
// TODO - HACK to speed up processing append .xml / .json / .bljson to all URLs to avoid LinkedData content negotiation | |
strURL = Util.appendStringBeforeParametersOfURL(strURL, REQUESTED_DATA_FORMAT); | |
// open server connection using provided URL (with no further modifications to it) | |
URL url = new URL (strURL); | |
Calendar requestStartedAt = Calendar.getInstance(); | |
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); | |
urlConn.setRequestMethod("POST"); | |
urlConn.setDoOutput(true); | |
urlConn.setRequestProperty("User-Agent", PLUGIN_USER_AGENT); | |
urlConn.setRequestProperty("Content-Type", CONTENT_TYPE_HEADER); | |
urlConn.setRequestProperty("Accept", ACCEPT_HEADER); | |
// prepare and POST XML data | |
OutputStreamWriter out = new OutputStreamWriter(urlConn.getOutputStream()); | |
out.write(strDataBody); | |
out.close(); | |
// fetch server's response | |
ServerResponseStream serverResponse = doBioCatalogueReceiveServerResponse(urlConn, strURL, false); | |
if (BioCataloguePluginConstants.PERFORM_API_RESPONSE_TIME_LOGGING) { | |
logAPIOperation(requestStartedAt, "POST", serverResponse); | |
} | |
return (serverResponse); | |
} | |
/** | |
* Generic method to execute DELETE requests to myExperiment server. | |
* This is only to be called when a user is logged in. | |
* | |
* @param strURL The URL on myExperiment to direct DELETE request to. | |
* @return An object containing XML Document with server's response body and | |
* a response code. Response body XML document might be null if there | |
* was an error or the user wasn't authorised to perform a certain action. | |
* Response code will always be set. | |
* @throws Exception | |
*/ | |
/*public ServerResponse doMyExperimentDELETE(String strURL) throws Exception | |
{ | |
// open server connection using provided URL (with no modifications to it) | |
URL url = new URL(strURL); | |
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); | |
// "tune" the connection | |
conn.setRequestMethod("DELETE"); | |
conn.setRequestProperty("User-Agent", PLUGIN_USER_AGENT); | |
conn.setRequestProperty("Authorization", "Basic " + AUTH_STRING); | |
// check server's response | |
return (doMyExperimentReceiveServerResponse(conn, strURL, true)); | |
}*/ | |
/** | |
* A common method for retrieving BioCatalogue server's response for both | |
* GET and POST requests. | |
* | |
* @param conn Instance of the established URL connection to poll for server's response. | |
* @param strURL The URL on BioCatalogue with which the connection is established. | |
* @param bIsGetRequest Flag for identifying type of the request. True when the current | |
* connection executes GET request; false when it executes a POST / DELETE request. | |
* @return TODO | |
*/ | |
@SuppressWarnings("unchecked") | |
private ServerResponseStream doBioCatalogueReceiveServerResponse(HttpURLConnection conn, String strURL, boolean bIsGETRequest) throws Exception | |
{ | |
int iResponseCode = conn.getResponseCode(); | |
switch (iResponseCode) | |
{ | |
case HttpURLConnection.HTTP_OK: | |
// regular operation path - simply return the reference to the data input stream | |
return (new ServerResponseStream(iResponseCode, conn.getInputStream(), strURL)); | |
case HttpURLConnection.HTTP_BAD_REQUEST: | |
// this was a bad XML request - need full XML response to retrieve the error message from it; | |
// Java throws IOException if getInputStream() is used when non HTTP_OK response code was received - | |
// hence can use getErrorStream() straight away to fetch the error document | |
return (new ServerResponseStream(iResponseCode, conn.getErrorStream(), strURL)); | |
case HttpURLConnection.HTTP_UNAUTHORIZED: | |
// this content is not authorised for current user | |
return (new ServerResponseStream(iResponseCode, null, strURL)); | |
case HttpURLConnection.HTTP_NOT_FOUND: | |
// nothing was found at the provided URL | |
return (new ServerResponseStream(iResponseCode, conn.getErrorStream(), strURL)); | |
default: | |
// unexpected response code - raise an exception | |
throw new IOException("Received unexpected HTTP response code (" + iResponseCode + ") while " + | |
(bIsGETRequest ? "fetching data at " : "posting data to ") + strURL); | |
} | |
} | |
/** | |
* This method is here to make sure that *all* parsing of received input stream data | |
* from the API is parsed ("bound") into Java objects in a central place - so it's | |
* possible to measure performance of XmlBeans for various inputs. | |
* | |
* NB! There is a serious limitation in Java's generics. Generic methods cannot | |
* access any of the static context of the classes of type parameters, because | |
* it wasn't designed for this. The only purpose of type parameters is compile-time | |
* type-checking. | |
* This means that even though all classes that could potentially be supplied as a | |
* type-parameter would have certain static functionality, it's not possible to access | |
* that through using the type-parameter like it's done in normal polymorhic situations. | |
* Therefore, some switching based on the class of the type-parameter for this method is | |
* done... | |
* | |
* @param <T> | |
* @param classOfRequiredReturnedObject Class of the object that the caller expects to receive | |
* after parsing provided server's response. For example, | |
* a call to /tags.xml return the <pre>[tags]...[/tags]</pre> | |
* document. <code>TagsDocument</code> should be used to access | |
* its static factory and parse the input stream - the return | |
* value will have type <code>Tags</code> -- <code>Tags.class</code> | |
* is the required input value for this parameter in this situation then. | |
* @param serverResponse This object should contain the input stream obtained from the API in return | |
* to the call on some URL. | |
* @return InputStream data parsed into the Java object of the supplied type [T]. | |
* @throws Exception | |
*/ | |
@SuppressWarnings("unchecked") | |
private <T extends ResourceLink> T parseAPIResponseStream(Class<T> classOfRequiredReturnedObject, ServerResponseStream serverResponse) throws Exception | |
{ | |
T parsedObject = null; | |
InputStream xmlInputStream = serverResponse.getResponseStream(); | |
// choose a factory to parse the response and perform parsing | |
Calendar parsingStartedAt = Calendar.getInstance(); | |
if (classOfRequiredReturnedObject.equals(Annotations.class)) { | |
parsedObject = (T)AnnotationsDocument.Factory.parse(xmlInputStream).getAnnotations(); | |
} | |
else if (classOfRequiredReturnedObject.equals(Filters.class)) { | |
parsedObject = (T)FiltersDocument.Factory.parse(xmlInputStream).getFilters(); | |
} | |
else if (classOfRequiredReturnedObject.equals(RestMethods.class)) { | |
parsedObject = (T)RestMethodsDocument.Factory.parse(xmlInputStream).getRestMethods(); | |
} | |
else if (classOfRequiredReturnedObject.equals(RestMethod.class)) { | |
parsedObject = (T)RestMethodDocument.Factory.parse(xmlInputStream).getRestMethod(); | |
} | |
else if (classOfRequiredReturnedObject.equals(Search.class)) { | |
parsedObject = (T)SearchDocument.Factory.parse(xmlInputStream).getSearch(); | |
} | |
else if (classOfRequiredReturnedObject.equals(Services.class)) { | |
parsedObject = (T)ServicesDocument.Factory.parse(xmlInputStream).getServices(); | |
} | |
else if (classOfRequiredReturnedObject.equals(Service.class)) { | |
parsedObject = (T)ServiceDocument.Factory.parse(xmlInputStream).getService(); | |
} | |
else if (classOfRequiredReturnedObject.equals(ServiceProviders.class)) { | |
parsedObject = (T)ServiceProvidersDocument.Factory.parse(xmlInputStream).getServiceProviders(); | |
} | |
else if (classOfRequiredReturnedObject.equals(ServiceProvider.class)) { | |
parsedObject = (T)ServiceProviderDocument.Factory.parse(xmlInputStream).getServiceProvider(); | |
} | |
else if (classOfRequiredReturnedObject.equals(SoapOperations.class)) { | |
parsedObject = (T)SoapOperationsDocument.Factory.parse(xmlInputStream).getSoapOperations(); | |
} | |
else if (classOfRequiredReturnedObject.equals(SoapOperation.class)) { | |
parsedObject = (T)SoapOperationDocument.Factory.parse(xmlInputStream).getSoapOperation(); | |
} | |
else if (classOfRequiredReturnedObject.equals(SoapService.class)) { | |
parsedObject = (T)SoapServiceDocument.Factory.parse(xmlInputStream).getSoapService(); | |
} | |
else if (classOfRequiredReturnedObject.equals(SoapInput.class)) { | |
parsedObject = (T)SoapInputDocument.Factory.parse(xmlInputStream).getSoapInput(); | |
} | |
else if (classOfRequiredReturnedObject.equals(SoapOutput.class)) { | |
parsedObject = (T)SoapOutputDocument.Factory.parse(xmlInputStream).getSoapOutput(); | |
} | |
else if (classOfRequiredReturnedObject.equals(Tags.class)) { | |
parsedObject = (T)TagsDocument.Factory.parse(xmlInputStream).getTags(); | |
} | |
else if (classOfRequiredReturnedObject.equals(Tag.class)) { | |
parsedObject = (T)TagDocument.Factory.parse(xmlInputStream).getTag(); | |
} | |
else if (classOfRequiredReturnedObject.equals(Users.class)) { | |
parsedObject = (T)UsersDocument.Factory.parse(xmlInputStream).getUsers(); | |
} | |
else if (classOfRequiredReturnedObject.equals(User.class)) { | |
parsedObject = (T)UserDocument.Factory.parse(xmlInputStream).getUser(); | |
} | |
// log the operation if necessary | |
if (BioCataloguePluginConstants.PERFORM_API_XML_DATA_BINDING_TIME_LOGGING) { | |
logAPIOperation(parsingStartedAt, null, serverResponse); | |
} | |
return (parsedObject); | |
} | |
// ************ HELPERS ************ | |
public static DateFormat getDateFormatter() { | |
return(BioCatalogueClient.DATE_FORMATTER); | |
} | |
public static DateFormat getShortDateFormatter() { | |
return(BioCatalogueClient.SHORT_DATE_FORMATTER); | |
} | |
/** | |
* This is a helper to facilitate performance monitoring of the API usage. | |
* | |
* @param opearationStartedAt Instance of Calendar initialised with the date/time value of | |
* when the logged operation was started. | |
* @param requestType "GET" or "POST" to indicate that this was the actual URL connection with the BioCatalogue server | |
* to fetch some data; <code>null</code> to indicate an xml-binding operation using XmlBeans. | |
* @param serverResponse Will be used to extract the request URL. | |
*/ | |
private void logAPIOperation(Calendar opearationStartedAt, String requestType, ServerResponseStream serverResponse) | |
{ | |
// just in case check that the writer was initialised | |
if (pwAPILogWriter != null) { | |
pwAPILogWriter.println(API_LOGGING_TIMESTAMP_FORMATTER.format(opearationStartedAt.getTime()) + ", " + | |
(System.currentTimeMillis() - opearationStartedAt.getTimeInMillis()) + ", " + | |
(requestType == null ? "xml_parsing" : requestType) + ", " + | |
serverResponse.getRequestURL()); | |
} | |
} | |
} |