/** * '$RCSfile$' * Copyright: 2000 Regents of the University of California and the * National Center for Ecological Analysis and Synthesis * * '$Author: Serhan AKIN $' * '$Date: 2009-07-15 10:54:27 +0300 $' * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package edu.ucsb.nceas.metacat.client.rest; import java.io.BufferedReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.StringReader; import java.io.Writer; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.Vector; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import edu.ucsb.nceas.metacat.client.DocumentNotFoundException; import edu.ucsb.nceas.metacat.client.InsufficientKarmaException; import edu.ucsb.nceas.metacat.client.MetacatAuthException; import edu.ucsb.nceas.metacat.client.MetacatException; import edu.ucsb.nceas.metacat.client.MetacatInaccessibleException; import edu.ucsb.nceas.utilities.IOUtil; import edu.ucsb.nceas.utilities.XMLUtilities; public class MetacatRestClient implements MetacatRest { /** The session identifier for the session */ private String sessionId; /** The URL string for the metacat REST API*/ private String contextRootUrl; /** * Constructor to create a new instance. */ public MetacatRestClient(String contextRootUrl){ setContextRootUrl(contextRootUrl); } /** * Method used to log in to a metacat server through REST API. Implementations will need * to cache a cookie value to make the session persistent. Each time a * call is made to one of the other methods (e.g., read), the cookie will * need to be passed back to the metacat server along with the request. * * @param username the username of the user, like an LDAP DN * @param password the password for that user for authentication * @return the response string from metacat in XML format * @throws MetacatAuthException when the username/password could * not be authenticated */ public String login(String username, String password) throws MetacatAuthException, MetacatInaccessibleException { String urlParams = FUNCTION_KEYWORD+"="+FUNCTION_NAME_LOGIN; String postData = "username="+username+"&password="+password; String response = null; try { response = sendData(RESOURCE_SESSION, POST, urlParams, postData, "application/x-www-form-urlencoded", null, null); } catch (Exception e) { throw new MetacatInaccessibleException(e.getMessage()); } if (response.indexOf("") == -1) { setSessionId(""); throw new MetacatAuthException(response); } else { int start = response.indexOf("") + 11; int end = response.indexOf(""); if ((start != -1) && (end != -1)) { setSessionId(response.substring(start,end)); } } return response; } /** * Method used to log out a metacat server. The Metacat server will end * the session when this call is invoked. * * @return the response string from metacat in XML format * @throws MetacatInaccessibleException when the metacat server can not be * reached or does not respond */ public String logout()throws MetacatInaccessibleException,MetacatException { String urlParams = FUNCTION_KEYWORD+"="+FUNCTION_NAME_LOGOUT ; String postData = "sessionid="+sessionId; String response; try { response = sendData(RESOURCE_SESSION, POST, urlParams, postData,"application/x-www-form-urlencoded", null, null); } catch (Exception e) { throw new MetacatInaccessibleException(e.getMessage()); } return response; } /** * Read a public XML document , accessed by docid, and returned as a Reader. * * @param docid the identifier of the document to be read * @param outputFile name of the file to be written to local (optional) * @return a Reader for accessing the document * @throws InsufficientKarmaException when the user has insufficent rights * for the operation * @throws MetacatInaccessibleException when the metacat server can not be * reached or does not respond * @throws MetacatException when the metacat server generates another error */ public Reader getObject(String docid, String outFile) throws InsufficientKarmaException, MetacatInaccessibleException, DocumentNotFoundException, MetacatException{ String resource = RESOURCE_OBJECTS+"/"+docid; try { String response = sendData(resource, GET, null, null, null, null, outFile); if (response != null ) { if (response != null && response.indexOf("") != -1) { if (response.indexOf("does not have permission") != -1) { throw new InsufficientKarmaException(response); } else if(response.indexOf("does not exist") != -1) { throw new DocumentNotFoundException(response); } else { throw new MetacatException(response); } } else { return new StringReader(response); } } else throw new MetacatException(response); } catch(IOException ioe){ throw new MetacatInaccessibleException(ioe.getMessage()); } } /** * Read XML document from server session, accessed by docid, and returned as a Reader. * * @param docid the identifier of the document to be read * @param outputFile name of the file to be written to local (optional) * @return a Reader for accessing the document * @throws InsufficientKarmaException when the user has insufficent rights * for the operation * @throws MetacatInaccessibleException when the metacat server can not be * reached or does not respond * @throws MetacatException when the metacat server generates another error */ public Reader authenticatedGetObject(String docid, String outFile) throws InsufficientKarmaException, MetacatInaccessibleException, DocumentNotFoundException, MetacatException{ String resource = RESOURCE_OBJECTS+"/"+docid; try { String response = sendData(resource, GET, "sessionid="+sessionId, null, null, null, outFile); if (response != null ) { if (response != null && response.indexOf("") != -1) { if (response.indexOf("does not have permission") != -1) { throw new InsufficientKarmaException(response); } else if(response.indexOf("does not exist") != -1) { throw new DocumentNotFoundException(response); } else { throw new MetacatException(response); } } else { return new StringReader(response); } } else throw new MetacatException(response); } catch(IOException ioe){ throw new MetacatInaccessibleException(ioe.getMessage()); } } /** * Query the metacat document store with the given Ecogrid-compatible * query document and return the Ecogrid result set as a Reader. * * @param xmlQuery a Reader for accessing the XML version of the query * @return a Reader for accessing the result set */ public Reader query(Reader xmlQuery) throws MetacatInaccessibleException,IOException { String response = null; try{ response = sendData(RESOURCE_OBJECTS, POST, null, null, "text/xml", xmlQuery, null); } catch (Exception e) { e.printStackTrace(); throw new MetacatInaccessibleException(e.getMessage()); } if (response != null) return new StringReader(response); return null; } /** * Query (as an authenticated user) the metacat document store with the given Ecogrid-compatible * query document and return the Ecogrid result set as a Reader. * * @param xmlQuery a Reader for accessing the XML version of the query * @return a Reader for accessing the result set */ public Reader authenticatedQuery(Reader xmlQuery) throws MetacatInaccessibleException,IOException { String response = null; try{ response = sendData(RESOURCE_OBJECTS, POST, "sessionid="+sessionId, null, "text/xml", xmlQuery, null); } catch (Exception e) { e.printStackTrace(); throw new MetacatInaccessibleException(e.getMessage()); } if (response != null) return new StringReader(response); return null; } /** * Create an XML document in the repository. * * @param docid the docid to insert the document * @param xmlDocument a Reader for accessing the XML document to be inserted * @param isInsert whether the operation is update or insert * * * @return the metacat response message * @throws InsufficientKarmaException when the user has insufficent rights * for the operation * @throws MetacatInaccessibleException when the metacat server can not be * reached or does not respond * @throws MetacatException when the metacat server generates another error * @throws IOException when there is an error reading the xml document */ public String create(String docid, Reader xmlDocument) throws InsufficientKarmaException, MetacatException, IOException, MetacatInaccessibleException { return putObject(docid, xmlDocument, true); } /** * Update an XML document in the repository, replacing an existing document. * * @param docid the docid to insert the document * @param xmlDocument a Reader for accessing the XML document to be inserted * @param isInsert whether the operation is update or insert * * * @return the metacat response message * @throws InsufficientKarmaException when the user has insufficent rights * for the operation * @throws MetacatInaccessibleException when the metacat server can not be * reached or does not respond * @throws MetacatException when the metacat server generates another error * @throws IOException when there is an error reading the xml document */ public String update(String docid, Reader xmlDocument) throws InsufficientKarmaException, MetacatException, IOException, MetacatInaccessibleException { return putObject(docid, xmlDocument, false); } /** * Delete an XML document in the repository. * * @param docid the docid to delete * @return the metacat response message * @throws InsufficientKarmaException when the user has insufficent rights * for the operation * @throws MetacatInaccessibleException when the metacat server can not be * reached or does not respond * @throws MetacatException when the metacat server generates another error */ public String deleteObject(String docid) throws InsufficientKarmaException, MetacatException,MetacatInaccessibleException { String resource = RESOURCE_OBJECTS+"/"+docid; String urlParams = "sessionid="+sessionId+"&"; String response = null; try{ response = sendData(resource, DELETE, urlParams, null, null, null, null); } catch (Exception e) { e.printStackTrace(); throw new MetacatInaccessibleException(e.getMessage()); } // Check for an error condition if (response.indexOf("") != -1) { if (response.indexOf("does not have permission") != -1) { throw new InsufficientKarmaException(response); } else { throw new MetacatException(response); } } return response; } /** * Return the highest document id for a given scope. This is used by * clients to make it easier to determine the next free identifier in a * sequence for a given scope. * @param scope String the scope to use for looking up the latest id * @throws MetacatException when an error occurs */ public String getNextObject(String scope) throws MetacatException { String lastIdentifier = ""; String resource = RESOURCE_IDENTIFIER; String urlParams = FUNCTION_KEYWORD+"="+FUNCTION_NAME_GETNEXTOBJ; if (scope != null) urlParams += "&scope="+scope; String response = null; try { response = sendData(resource, GET, urlParams, null, null, null, null); // Check for an error condition if (response.indexOf("") != -1) { throw new MetacatException(response); } else { Reader responseReader = new StringReader(response); Node root = XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader); Node docidNode = XMLUtilities.getNodeWithXPath(root, "/lastDocid/docid"); lastIdentifier = docidNode.getFirstChild().getNodeValue(); } } catch (Exception e) { throw new MetacatException(e.getMessage()); } return lastIdentifier; } /** * The method will return the latest revision in metacat server * for a given document id. If some error happens, this method will throw * an exception. * @param identifierId String the given docid you want to use. the docid it self * can have or haven't revision number * @throws MetacatException */ public int getNextRevision(String identifierId) throws MetacatException { int rev = 0; String resource = RESOURCE_IDENTIFIER+"/"+identifierId; String urlParams = FUNCTION_KEYWORD+"="+FUNCTION_NAME_GETNEXTREV; String response = null; try { response = sendData(resource, GET, urlParams, null, null, null, null); // Check for an error condition if (response.indexOf("") != -1 ) { throw new MetacatException(response); } Reader responseReader = new StringReader(response); Node root = XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader); Node docidNode = XMLUtilities.getNodeWithXPath(root, "/next-revision"); rev = Integer.parseInt(docidNode.getFirstChild().getNodeValue()); } catch (Exception e) { e.printStackTrace(); throw new MetacatException(e.getMessage()); } return rev; } /** * return a list of all docids that match a given scope. if scope is null * return all docids registered in the system * @param scope String the scope to use to limit the docid query * @throws MetacatException when an error occurs */ public Vector getAllDocids(String scope) throws MetacatException { Vector resultVec = new Vector(); String resource = RESOURCE_IDENTIFIER; String urlParams = FUNCTION_KEYWORD+"="+FUNCTION_NAME_GETALLDOCS; if (scope != null) urlParams += "&scope="+scope; String response = null; try { response = sendData(resource, GET, urlParams, null, null, null, null); // Check for an error condition if (response.indexOf("") != -1) { throw new MetacatException(response); } else { Reader responseReader = new StringReader(response); Node root = XMLUtilities.getXMLReaderAsDOMTreeRootNode(responseReader); NodeList nlist = root.getChildNodes(); for(int i=0; i") != -1) { throw new MetacatException(response); } else { Reader responseReader = new StringReader(response); StringBuffer sb = new StringBuffer(); char[] c = new char[1024]; int numread = responseReader.read(c, 0, 1024); while(numread != -1) { sb.append(new String(c, 0, numread)); numread = responseReader.read(c, 0, 1024); } String responseStr = sb.toString(); if(responseStr.indexOf("true") != -1) { return true; } return false; } } catch (Exception e) { throw new MetacatException(e.getMessage()); } } /** * Adds identifierId * @param identifierId String the given docid you want to use. * @throws MetacatException when an error occurs */ public String addLSID(String identifierId) throws MetacatException { String resource = RESOURCE_IDENTIFIER+"/"+identifierId; String response = null; try { response = sendData(resource, PUT, null, null, null, null, null); } catch (Exception e) { throw new MetacatException(e.getMessage()); } return response; } public void setContextRootUrl(String contextRootUrl) { if (!contextRootUrl.endsWith("/")) contextRootUrl += "/"; this.contextRootUrl = contextRootUrl; } public String getSessionId() { return sessionId; } public void setSessionId(String sessionId) { this.sessionId = sessionId; } /** * Put (Insert/Update) an XML document into the repository. * * @param docid the docid to insert the document * @param xmlDocument a Reader for accessing the XML document to be inserted * @param isInsert whether the operation is update or insert * * @return the metacat response message * @throws InsufficientKarmaException when the user has insufficent rights * for the operation * @throws MetacatInaccessibleException when the metacat server can not be * reached or does not respond * @throws MetacatException when the metacat server generates another error * @throws IOException when there is an error reading the xml document */ private String putObject(String docid, Reader xmlDocument, boolean isInsert) throws InsufficientKarmaException, MetacatException, IOException, MetacatInaccessibleException { String resource = RESOURCE_OBJECTS+"/"+docid; String urlParams = "sessionid="+sessionId+"&"; if (isInsert) urlParams += FUNCTION_KEYWORD+"="+FUNCTION_NAME_INSERT; else urlParams += FUNCTION_KEYWORD+"="+FUNCTION_NAME_UPDATE; String response = null; try{ response = sendData(resource, PUT, urlParams, null, "text/xml", xmlDocument, null); } catch (Exception e) { e.printStackTrace(); throw new MetacatInaccessibleException(e.getMessage()); } // Check for an error condition if (response.indexOf("") != -1) { if (response.indexOf("does not have permission") != -1) { throw new InsufficientKarmaException(response); } else { throw new MetacatException(response); } } return response; } /** * Send request to metacat REST API. * @param resource Resource name to be accessed * @param method HTTP verb, shoudl be one of GET,POST,DELETE,PUT * @param urlParameters QueryString to be added to the end of server url * @param postData QueryString to be printed to output stream * @param contentType Content Type of the data to be posted. eg: "text/xml" or "application/x-www-form-urlencoded" * @param postFileReader Reader of file to be posted * @param outputFile File name to be saved returning from API */ private String sendData(String resource, String method, String urlParamaters, String postData, String contentType, Reader postFileReader, String outputFile) throws IOException { HttpURLConnection connection = null ; String restURL = contextRootUrl+resource; if (urlParamaters != null) { if (restURL.indexOf("?") == -1) restURL += "?"; restURL += urlParamaters; } URL u = new URL(restURL); URLConnection uc = u.openConnection(); connection= (HttpURLConnection) uc; if (contentType!=null) connection.setRequestProperty("Content-Type",contentType); connection.setDoOutput(true); connection.setDoInput(true); connection.setRequestMethod(method); if (!method.equals(GET)) { if (postFileReader != null) { postData = IOUtil.getAsString(postFileReader, true); } if (postData != null){ OutputStream out = connection.getOutputStream(); Writer wout = new OutputStreamWriter(out); wout.write(postData); wout.flush(); wout.close(); } } return readStream(connection.getInputStream(),outputFile); } /** * * Reads Input stream and return readed data, optionaly write the data to specified file * */ private String readStream(InputStream is, String writeFile) throws IOException{ BufferedReader in = new BufferedReader( new InputStreamReader( is)); String inputLine; StringBuffer b = new StringBuffer(); FileWriter writer = null; if (writeFile!=null) writer = new FileWriter(writeFile); while ((inputLine = in.readLine()) != null) { //System.out.println(inputLine+"\n"); b.append(inputLine+"\n"); if (writeFile!=null) writer.write(inputLine); } if (writeFile!=null) { writer.flush(); writer.close(); } in.close(); return b.toString(); } }