/* * This file is part of rasdaman community. * * Rasdaman community 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 3 of the License, or * (at your option) any later version. * * Rasdaman community 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 rasdaman community. If not, see . * * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / rasdaman GmbH. * * For more information please see * or contact Peter Baumann via . */ /************************************************************* *
 *
 * PURPOSE:
 *
 *
 * COMMENTS:
 * - return type complex not yet supported.
 * 
*********************************************************** */ package rasj.clientcommhttp; import rasj.*; import org.odmg.*; import rasj.odmg.*; import rasj.global.*; import java.io.*; import java.net.*; import java.lang.*; import java.util.*; /** * This class handles a HTTP-request to the RasDaMan server. * The specified RasDaMan server is contacted, the specified command is sent to * the server, and the result of the query is retrieved and stored in a byte array. * The specification of the communication protocol is given below. *

* * @version $Revision: 1.35 $ * *

* Request structure

    * The rasj HTTP request to the rasdaman server uses the HTTP POST-Format with the following * parameters: *

    * * * * * * * * * * * * * * * * * * * * * * * * * * *
    Parameter:Description:Required for
    CommandInteger value specifying the desired action (e.g. OpenDB, BT, CT, CloseDB ...)all requests
    DatabaseString value specifying the databaseOpenDB, CloseDB
    ClientTypeInteger value defining the type of the client (at the moment always RasClient)all requests
    ClientIDInteger value specifying the ClientID (currently set to 1 for every client)all requests
    QueryStringString value containing the RasQL queryexecuteQuery
    EndianessInteger value containing the Client Endianessonly insert queries
    NumberOfQueryParametersInteger value specifying the number of query parametersonly insert queries
    QueryParametersByte Array containing the query parameters (MDDs) using the following format:
    * * * * * * *
    IntegerStringStringIntegerStringStringStringLongByte[]
    objectTypeobjectTypeNametypeStructuretypeLengthdomainstorageLayoutOIDdataSizebinary data
    *
    only insert queries
    *

    *

* * Result formats / internal representation:

    * The result of a HTTP request has one of the following forms:

    * MDD Collections:
    * * * * * * * * * * * * * *
    ByteByteStringLong(4Bytes)resultElement 1 ...
    StringStringStringLong(4Bytes)Byte[]
    Result type

    1=MDDCollection

    EndianessCollection typeNumber of resultsBaseType descriptionSpatial domainOIDSize of the Binary Data BlockBinary Data Block

    * * Skalar Collections:
    * * * * * * * * * * * *
    ByteByteStringLong(4Bytes)resultElement 1 ...
    StringLong(4Bytes)Byte[]
    Result type

    2=SkalarCollection

    EndianessCollection typeNumber of resultsElementType descriptionSize of the Binary Data BlockBinary Data Block

    * * Errors:
    * * * * * * * * * *
    ByteByteLong(4Bytes)Long(4Bytes)Long(4Bytes)String
    Result type

    0=Error

    EndianessError numberLine numberColumn numberToken

    * * Single Integer Value:
    * * *
    ByteInteger
    Result type

    3=Integer

    Value

    * * OID:
    * * *
    ByteStringStringDouble
    Result type

    4=OID

    systembasenamelocalOID

    * * Acknowledgement:
    * * *
    Byte
    Result type

    99=OK

    * *

* */ public class RasHttpRequest implements RasCommDefs, RasGlobalDefs { static final String rcsid = "@(#)Package rasj.clientcommhttp, class RasRequest: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/clientcommhttp/RasHttpRequest.java,v 1.35 2003/12/19 15:36:43 rasdev Exp $"; /** * The type of this client */ private String client = "RASCLIENT"; /** * The result type ( MDD Collection, Skalar Collection, Error, Integer ). This field is set * automatically when a query has been executed, so there's no setResultType method. */ private byte resultType = 0; /** * The result of the query **/ private Object result = null; /** * This method sends a query to the RasDaMan Server and retrieves the results. * * @param con server connection * @param parameters the parameters for the request as name/value pairs (for example "clientID=4354351&queryString=select img from test") */ public void execute( String serverURL, String parameters ) throws RasQueryExecutionFailedException, RasConnectionFailedException { Debug.enterVerbose( "RasHttpRequest.execute: start. serverURL=" + serverURL + ", parameters=" + parameters ); BenchmarkTimer httpTimer = new BenchmarkTimer("httpRequest"); BenchmarkTimer rcvTimer = new BenchmarkTimer("receive"); try { URL url = new URL( serverURL ); Debug.talkVerbose( "RasHttpRequest.execute: sending to " + url + " POST request=" + parameters ); httpTimer.startTimer(); BenchmarkTimer sendTimer = new BenchmarkTimer("send"); sendTimer.startTimer(); // Send the query HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestProperty("Content-type","application/octet-stream"); con.setRequestProperty("User-Agent","RasDaMan Java Client"); con.setRequestProperty("Version","1.0"); con.setRequestMethod("POST"); con.setDoInput(true); con.setDoOutput(true); con.setUseCaches(false); OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream(),"8859_1"); out.write(parameters,0,parameters.length()); out.flush(); out.close(); sendTimer.stopTimer(); sendTimer.print(); rcvTimer.startTimer(); // Read response BenchmarkTimer getInputTimer = new BenchmarkTimer("getInputStream"); getInputTimer.startTimer(); DataInputStream in = new DataInputStream(con.getInputStream()); // int BuffSize = con.getContentLength(); // not used -- PB 2003-jun-14 // Debug.talkVerbose("RasHttpRequest.execute: buffSize=" + BuffSize); getInputTimer.stopTimer(); getInputTimer.print(); /* variables for later use */ byte[] b1 = new byte[1]; byte[] b4 = new byte[4]; byte endianess = 0; String collType = null; int numberOfResults = 0; int dataSize = 0; byte[] binData = null; int readBytes = 0; int readBytesTmp = 0; DBag resultBag; RasGMArray res = null; in.read(b1); resultType = b1[0]; Debug.talkVerbose("RasHttpRequest.execute: resultType=" + resultType ); switch( resultType ) { case RESPONSE_OK: case RESPONSE_OK_NEGATIVE: //Nothing todo break; // +++++++++++++++++++++++++++++++++++++++++++++++++ case RESPONSE_MDDS: Debug.talkVerbose("RasHttpRequest.execute: result type is MDD." ); // read Endianess while(in.read(b1) == 0) ; endianess = b1[0]; // read Collection Type collType = RasUtils.readString(in); Debug.talkVerbose("RasHttpRequest.execute: colltype=" + collType); // read NumberOfResults while(in.available() < 4) ; in.read(b4); numberOfResults = RasUtils.ubytesToInt(b4,endianess); Debug.talkVerbose("RasHttpRequest.execute: number of results: " + numberOfResults); // Initialize return-set and parameters resultBag = new RasBag(); String mddBaseType = null; String domain = null; String oid = ""; RasOID roid = null; // do this for each result for(int x = 0; x < numberOfResults; x++) { Debug.talkVerbose("RasHttpRequest.execute: handling result #" + (x+1) ); //read mddBaseType mddBaseType = RasUtils.readString(in); // read spatialDomain domain = RasUtils.readString(in); // read OID oid = RasUtils.readString(in); //System.err.println("OID is " + oid); roid = new RasOID(oid); // read size of binData while(in.available() < 4) ; in.read(b4); dataSize = RasUtils.ubytesToInt(b4,endianess); Debug.talkVerbose("RasHttpRequest.execute: mddBaseType is " + mddBaseType + ", spatialDomain=" + domain + ", size of BinData=" + dataSize ); // read binData binData = new byte[dataSize]; readBytes = 0; readBytesTmp = 0; while( (readBytesTmp != -1) && (readBytes < dataSize) ) { readBytesTmp = in.read(binData,readBytes,dataSize-readBytes); readBytes += readBytesTmp; } Debug.talkVerbose("RasHttpRequest.execute: read " + readBytes + " bytes."); RasType rType = RasType.getAnyType(mddBaseType); //System.out.println(rType); RasBaseType rb = null; if(rType.getClass().getName().equals("rasj.RasMArrayType")) { RasMArrayType tmp = (RasMArrayType)rType; rb = tmp.getBaseType(); } else { Debug.talkCritical("RasHttpRequest.execute: exception: element of MDD Collection is no MArray" ); throw new RasClientInternalException("RasHttpRequest","execute()","element of MDD Collection is no MArray"); } if(rb.isBaseType()) { if(rb.isStructType()) { // It is a structType //System.err.println("It is a structType"); RasStructureType sType = (RasStructureType)rb; //System.out.println(sType); res = new RasGMArray(new RasMInterval(domain), 0); res.setTypeLength(rb.getSize()); res.setArraySize(dataSize); res.setArray(binData); //insert into result set resultBag.add(res); break; } else { // It is a primitiveType RasPrimitiveType pType = (RasPrimitiveType)rb; //System.err.println("It's a primitive type: " + pType); switch(pType.getTypeID()) { case RAS_BOOLEAN: case RAS_BYTE: case RAS_CHAR: //System.err.println("It's a byte array!"); res = new RasMArrayByte(new RasMInterval(domain)); break; case RAS_SHORT: //System.err.println("It's a short array!"); res = new RasMArrayShort(new RasMInterval(domain)); break; case RAS_USHORT: //System.err.println("It's a ushort array!"); byte[] tmData = new byte[dataSize*2]; for(int i=0;i * Future versions will support other types like, for example, "BROWSER", where the * results will be coded as standard HTTP-responses of certain mime types (for example * "image/gif"). * * @param clientType currently only "RASCLIENT" supported */ public void setClientType ( String clientType ) { client = clientType; } /** * main program for testing purposes */ /* BEGIN experimental *********************** public static void main( String[] args ) { String server = "localhost"; String port = "7001"; String base = "RASBASE"; String user = "rasguest"; String passwd = "rasguest"; String query = "select r from RAS_COLLECTIONNAMES as r"; int count = 1; System.out.println( "Query test started." ); for (int i=args.length-1; i>=0; i--) { if (args[i].equals("--server")) server = args[i+1]; if (args[i].equals("--port")) port = args[i+1]; if (args[i].equals("--database")) base = args[i+1]; if (args[i].equals("--user")) user = args[i+1]; if (args[i].equals("--passwd")) passwd = args[i+1]; if (args[i].equals("--query")) query = args[i+1]; if (args[i].equals("--count")) count = Integer.parseInt(args[i+1]); } try { RasImplementation myApp = new RasImplementation("http://"+server+":"+port); myApp.setUserIdentification(user, passwd); System.out.println( "opening database..." ); Database myDb = myApp.newDatabase(); myDb.open( base, Database.OPEN_READ_ONLY ); System.out.println( "starting transaction..." ); Transaction myTa = myApp.newTransaction(); myTa.begin(); String parameters = "Command=8&ClientID=1&QueryString=" + query; String serverUrl = "http://" + server + ":" + 7102; // port; for (int i = 0; i < count; i++) { System.out.println( "sending query #" + i + "..." ); execute( serverUrl, parameters ); } System.out.println( "closing transaction..." ); myTa.abort(); System.out.println( "closing database..." ); myDb.close(); System.out.println( "all done." ); } catch(Exception e) { System.err.println( e.getMessage() ); } System.out.println( "Query test done." ); } // main() END experimental ***********************/ }