Update of /cvsroot/monetdb/java/src/nl/cwi/monetdb/xquery/xrpc/api
In directory 
sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv10861/src/nl/cwi/monetdb/xquery/xrpc/api

Added Files:
        XRPCException.java XRPCHTTPConnection.java XRPCMessage.java 
        XRPCReceiverException.java XRPCSenderException.java 
Log Message:
Moved the XRPC Wrapper to the new "java" module



--- NEW FILE: XRPCException.java ---
/**
 * The contents of this file are subject to the MonetDB Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html

 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and
 * limitations under the License.

 * The Original Code is the MonetDB Database System.

 * The Initial Developer of the Original Code is CWI.
 * Portions created by CWI are Copyright (C) 1997-2007 CWI.
 * All Rights Reserved.
**/

package nl.cwi.monetdb.xquery.xrpc.api;

/**
 * @author Ying Zhang <[EMAIL PROTECTED]>
 * @version 0.1
 */

public class XRPCException extends Exception {
    public XRPCException(String reason) {
        super(reason);
    }
}

--- NEW FILE: XRPCSenderException.java ---
/**
 * The contents of this file are subject to the MonetDB Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html

 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and
 * limitations under the License.

 * The Original Code is the MonetDB Database System.

 * The Initial Developer of the Original Code is CWI.
 * Portions created by CWI are Copyright (C) 1997-2007 CWI.
 * All Rights Reserved.
**/

package nl.cwi.monetdb.xquery.xrpc.api;

/**
 * @author Ying Zhang <[EMAIL PROTECTED]>
 * @version 0.1
 */

public class XRPCSenderException extends XRPCException {
    public XRPCSenderException(String reason) {
        super(reason);
    }
}

--- NEW FILE: XRPCHTTPConnection.java ---
/**
 * The contents of this file are subject to the MonetDB Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html

 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and
 * limitations under the License.

 * The Original Code is the MonetDB Database System.

 * The Initial Developer of the Original Code is CWI.
 * Portions created by CWI are Copyright (C) 1997-2007 CWI.
 * All Rights Reserved.
**/

package nl.cwi.monetdb.xquery.xrpc.api;

import java.io.*;
import java.net.*;

/**
 * @author Ying Zhang <[EMAIL PROTECTED]>
 * @version 0.1
 */

public class XRPCHTTPConnection {
    public static final String HTTP_OK_HEADER =
        "HTTP/1.1 200 OK\r\n" +
        "Content-type: text/xml; charset=\"utf-8\"\r\n\r\n";
    public static final String HTTP_ERR_404_HEADER =
        "HTTP/1.1 404 Bad Request\r\n" +
        "Content-type: text/xml; charset=\"utf-8\"\r\n\r\n";
    public static final String HTTP_ERR_500_HEADER =
        "HTTP/1.1 500 Internal Server Error\r\n" +
        "Content-type: text/xml; charset=\"utf-8\"\r\n\r\n";

    /* Sends XRPC request messages and SOAP Fault messages.
     *
     * It is up to the caller to catch the possible exception and print
     * proper error message.  It is also up to the caller to close the
     * socket and the associated streams. */
    public static void send(BufferedWriter socketWriter,
                            String httpHeader,
                            String xrpcMessage)
        throws Exception
    {
        socketWriter.write(httpHeader);
        socketWriter.write(xrpcMessage);
        socketWriter.flush();
    }

    /* Receives XRPC request messages.
     *
     * Returns: the received XRPC message
     *
     * It is up to the caller to catch the possible exception and print
     * proper error message.  It is also up to the caller to close the
     * socket and the associated streams. */
    public static String receive(BufferedReader socketReader,
                                 String reqURI)
        throws XRPCException
    {
        int contentLength = 0;
        String ln = null;
        boolean foundPostHeader = false;
        boolean foundClHeader = false;
        boolean foundHostHeader = false;
        
        /* read the HTTP header */
        try{
            while( ((ln = socketReader.readLine()) != null) &&
                   (ln.length() > 0) ){
                if(ln.startsWith("POST")){
                    if( !ln.startsWith(reqURI, 5) ){
                        throw new XRPCSenderException(
                                "Unsupported Request: \"" + ln + "\"");
                    }
                    foundPostHeader = true;
                } else if(ln.startsWith("Content-Length:")) {
                    contentLength = Integer.parseInt(ln.substring(16));
                    foundClHeader = true;
                } else if(ln.startsWith("Host:")) {
                    /* TODO: save the value of Host for later use??? */
                    foundHostHeader = true;
                }
            }
        } catch(NumberFormatException nfe) {
            throw new XRPCSenderException("Invalid value of " +
                    "\"Content-Length\": \"" +
                    ln.substring(16) + "\": " + nfe.getMessage());
        } catch (IOException ioe) {
            throw new XRPCSenderException(
                    "Could not read HTTP request header.");
        }

        if(!foundPostHeader){
            throw new XRPCSenderException("HTTP header does not contain " +
                    "a \"POST\" method definition.");
        } else if (!foundClHeader){
            throw new XRPCSenderException("HTTP header does not contain " +
                    "the mandatory \"Content-Length\" field.");
        } else if (!foundHostHeader){
            throw new XRPCSenderException("HTTP header does not contain " +
                    "the mandatory \"Host\" field.");
        }

        /* read the XRPC request message */
        StringBuffer reqMsg = new StringBuffer(contentLength + 10);
        ln = null;
        try{
            while( (reqMsg.length() < contentLength) &&
                   ((ln = socketReader.readLine()) != null) ){
                reqMsg.append(ln).append('\n');
            }
        } catch (IOException e) {
            throw new XRPCReceiverException(
                    "Failed to receive request.");
        }

        if(reqMsg.length() != contentLength){
            throw new XRPCReceiverException(
                    "Failed to receive all request: " +
                    contentLength + "bytes expected, " +
                    reqMsg.length() + " bytes received.");
        }

        return reqMsg.toString();
    }

    /* Send an XRPC request, returns the XRPC response message or the
     * SOAP Fault message */
    public static StringBuffer sendReceive(String server,
                                           String request)
        throws Exception
    {
        URL url = new URL(server);
        HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
        httpConn.setDoInput(true);
        httpConn.setDoOutput(true);
        httpConn.setUseCaches(false);
        httpConn.setRequestMethod("POST");
        httpConn.setRequestProperty("Content-Type",
                                    "application/x-www-form-urlencoded");
        httpConn.setRequestProperty("Content-Length", request.length()+"");
        httpConn.connect();

        /* Send POST output. */
        DataOutputStream printout = new
            DataOutputStream(httpConn.getOutputStream());
        printout.writeBytes(request);
        printout.flush ();

        /* Get response data. */
        InputStreamReader isReader;
        StringBuffer response = new StringBuffer(16384);
        if(httpConn.getResponseCode() != HttpURLConnection.HTTP_OK){
            /* Read the SOAP Fault message. */
            isReader = new InputStreamReader(httpConn.getErrorStream());
        } else {
            /* Read the response message, which can also be a SOAP Fault
             * message. */
            isReader = new InputStreamReader(httpConn.getInputStream());
        }
        int c;
        while( (c = isReader.read()) >= 0) response.append((char)c);
        isReader.close();
        printout.close();
        return response;
    }
}

--- NEW FILE: XRPCReceiverException.java ---
/**
 * The contents of this file are subject to the MonetDB Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html

 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and
 * limitations under the License.

 * The Original Code is the MonetDB Database System.

 * The Initial Developer of the Original Code is CWI.
 * Portions created by CWI are Copyright (C) 1997-2007 CWI.
 * All Rights Reserved.
**/

package nl.cwi.monetdb.xquery.xrpc.api;

/**
 * @author Ying Zhang <[EMAIL PROTECTED]>
 * @version 0.1
 */

public class XRPCReceiverException extends XRPCException {
    public XRPCReceiverException(String reason) {
        super(reason);
    }
}

--- NEW FILE: XRPCMessage.java ---
/**
 * The contents of this file are subject to the MonetDB Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html

 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and
 * limitations under the License.

 * The Original Code is the MonetDB Database System.

 * The Initial Developer of the Original Code is CWI.
 * Portions created by CWI are Copyright (C) 1997-2007 CWI.
 * All Rights Reserved.
**/

package nl.cwi.monetdb.xquery.xrpc.api;

import java.io.*;
import java.util.*;
import javax.xml.namespace.*;
import javax.xml.xpath.*;
import org.w3c.dom.*;
import org.xml.sax.*;

/**
 * @author Ying Zhang <[EMAIL PROTECTED]>
 * @version 0.1
 */

public class XRPCMessage {
    public static final String XRPC_MSG_TYPE_REQ  = "request";
    public static final String XRPC_MSG_TYPE_RESP = "response";

    /**
     * Namespace definitions used in an XRPC message
     **/
        public static final String SOAP_NS  = 
"http://www.w3.org/2003/05/soap-envelope";;
        public static final String XDT_NS   = 
"http://www.w3.org/2005/xpath-datatypes";;
        public static final String XS_NS    = 
"http://www.w3.org/2001/XMLSchema";;
        public static final String XSI_NS   = 
"http://www.w3.org/2001/XMLSchema-instance";;
        public static final String XRPC_NS  = "http://monetdb.cwi.nl/XQuery";;
        public static final String XRPC_LOC = 
"http://monetdb.cwi.nl/XQuery/XRPC.xsd";;

    /**
     * Start and End of the messages
     **/
    public static final String XML_DECL =
        "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
    public static final String XRPC_MSG_START =
        "<env:Envelope" + 
        " xmlns:env=\"" + SOAP_NS + "\"" +
        " xmlns:xrpc=\"" + XRPC_NS + "\"" +
        " xmlns:xs=\"" + XS_NS + "\"" +
        " xmlns:xsi=\"" + XSI_NS + "\"" +
        " xsi:schemaLocation=\"" + XRPC_NS + " " + XRPC_LOC + "\">" +
        "<env:Body>";
    public static final String XRPC_REQUEST_END =
        "</xrpc:request></env:Body></env:Envelope>\n";
    public static final String XRPC_RESPONSE_END =
        "</xrpc:response></env:Body></env:Envelope>\n";
    public static final String SOAP_FAULT_START =
        XML_DECL +
        "<env:Envelope xmlns:env=\""+SOAP_NS+"\">" +
        "<env:Body><env:Fault>";
    public static final String SOAP_FAULT_END =
        "</env:Fault></env:Body></env:Envelope>\n";

    /***********************************************/
    /*  Private Functions for Generating Messages  */
    /***********************************************/
    private static String xrpc_req(String module,
                                   String location,
                                   String method,
                                   int arity,
                                   int iterc,
                                   String updCall,
                                   String body)
    {
        StringBuffer header = new StringBuffer(512);
        header.append("<xrpc:request xrpc:module=\"");
        header.append(module);
        header.append("\" xrpc:location=\"");
        header.append(location);
        header.append("\" xrpc:method=\"");
        header.append(method);
        header.append("\" xrpc:arity=\"");
        header.append(arity);

        if (iterc > 0){
            header.append("\" xrpc:iter-count=\"");
            header.append(iterc);
        }
        if (updCall != null){
            header.append("\" xrpc:updCall=\"");
            header.append(updCall);
        }

        header.append("\">");

        return XML_DECL + XRPC_MSG_START + header + body +
               XRPC_REQUEST_END;
    }

    /***********************************************/
    /*     Public Message Generating Functions     */
    /***********************************************/
    public static String XRPC_REQUEST(String module,
                                      String location,
                                      String method,
                                      int arity,
                                      int iterc,
                                      boolean updCall,
                                      String body)
    {
        return xrpc_req(module, location, method, arity, iterc,
                        updCall?"true":"false", body);
    }

    public static String XRPC_REQUEST(String module,
                                      String location,
                                      String method,
                                      int arity,
                                      int iterc,
                                      String body)
    {
        return xrpc_req(module, location, method, arity, iterc,
                        null, body);
    }

    public static String XRPC_REQUEST(String module,
                                      String location,
                                      String method,
                                      int arity,
                                      boolean updCall,
                                      String body)
    {
        return xrpc_req(module, location, method, arity, 0,
                        updCall?"true":"false", body);
    }

    public static String XRPC_REQUEST(String module,
                                      String location,
                                      String method,
                                      int arity,
                                      String body)
    {
        return xrpc_req(module, location, method, arity, 0,
                        null, body);
    }

    public static String XRPC_RESPONSE(String module,
                                       String method,
                                       String body)
    {
        return XML_DECL + XRPC_MSG_START +
               "<xrpc:response xrpc:module=\"" + module + "\"" +
                             " xrpc:method=\"" + method + "\">" +
               body + XRPC_RESPONSE_END;
    }

    public static String SOAP_FAULT(String faultCode,
                                    String faultReason)
    {
        return SOAP_FAULT_START +
            "<env:Code>" +
            "<env:Value>" + faultCode + "</env:Value>" +
            "</env:Code>" +
            "<env:Reason>" +
            "<env:Text xml:lang=\"en\">" + faultReason +
            "</env:Text>" +
            "</env:Reason>" +
            SOAP_FAULT_END;
    }

    /* a body consists of one or more calls */
    public static String XRPC_CALL(String params)
    {
        if (params == null || params.length() == 0){
            return "<xrpc:call/>";
        }
        return "<xrpc:call>" + params + "</xrpc:call>";
    }

    /* each parameter is an XQuery sequence */
    public static String XRPC_SEQ(String seq)
    {
        if (seq == null || seq.length() == 0){
            return "<xrpc:sequence/>";
        }
        return "<xrpc:sequence>" + seq + "</xrpc:sequence>";
    }

    /* Sequence values are either atomics of an "xs:"<type> or XML nodes
     * (e.g. elements, documents, attribute, comment, text,
     * processing-instruction, etc)
     */
    public static String XRPC_ATOM(String type, String value)
    {
        /* FIXME: do we need to escape the string value "value"?
         *        See the XRPC web client. */
        return "<xrpc:atomic-value xsi:type=\"xs:" + type + "\">" +
            value + "</xrpc:atomic-value>";
    }

    public static String XRPC_ELEMENT(String value)
    {
        return "<xrpc:element>" + value + "</xrpc:element>";
    }

    public static String XRPC_DOCUMENT(String value)
    {
        return "<xrpc:document>" + value + "</xrpc:document>";
    }

    public static String XRPC_TEXT(String value)
    {
        return "<xrpc:text>" + value + "</xrpc:text>";
    }

    public static String XRPC_COMMENT(String value)
    {
        return "<xrpc:comment>" + value + "</xrpc:comment>";
    }

    public static String XRPC_PI(String value)
    {
        return "<xrpc:processing-instruction>" + value +
               "</xrpc:processing-instruction>";
    }

    public static String XRPC_ATTRIBUTE(String attrName, String attrVal)
    {
        return "<xrpc:attribute " + attrName+"=\""+attrVal+"\" />";
    }

    /***********************************************/
    /*     Public Message Parsing Functions        */
    /***********************************************/

    /**
     * Find the prefix definition of the given namespace URI in an XRPC
     * message, by searching in the SOAP Envelope tag and the XRPC
     * request/response tag.
     *
     * Returns: the prefix, or throws XRPCException
     **/
    public static String getNamespacePrefix(String msgType,
                                            String msg,
                                            String namespaceURI)
        throws XRPCException
    {
        int start = -1, end = -1;

        /* Find the start and end of the tag "Envelope" */
        start = msg.indexOf("Envelope");
        if(start < 0){
            throw new XRPCSenderException(
                    "XRPC " + msgType + " message not well-formed:" +
                    "could not find the \"Envelope\" tag.");
        }
        end = msg.indexOf(">", (start + 8));
        if(end < 0){
            throw new XRPCSenderException(
                    "XRPC " + msgType + " message nog well-formed: " +
                    "could not find the end of the \"Envelope\" tag.");
        }

        /* Find the end of the tag msgType */
        end = msg.indexOf(msgType, end);
        if(end < 0){
            throw new XRPCSenderException(
                    "XRPC " + msgType + " message not well-formed:" +
                    "could not find the \"" + msgType + "\" tag.");
        }
        end = msg.indexOf(">", (end + 7));
        if(end < 0){
            throw new XRPCSenderException(
                    "XRPC " + msgType + " message nog well-formed: " +
                    "could not find the end of the \"" +
                    msgType + "\" tag.");
        }

        /* Cut off the namespace declarations from the "Envelope" tag
         * until the end of the msgType tag and remove all white space
         * characters. */
        String str = msg.substring(start+9, end).replaceAll("[ \t\r\n]", "");
        start = 0;
        end = str.length();
        int nsLen = namespaceURI.length();
        do{
            start = str.indexOf(namespaceURI, start);
            if(str.charAt(start + nsLen) == '"'){
                /* search backward */
                end = str.lastIndexOf("=", start);
                start = str.lastIndexOf("\"", end) + 1;
                if(str.indexOf("xmlns",start) != start){
                    throw new XRPCSenderException(
                            "XRPC " + msgType + " message not " +
                            "well-formed: \"xmlns\" expected in a " +
                            "namespace declaration.");
                }
                /* Skip "xmlns:" */
                return str.substring(start + 6, end);
            }
            start += nsLen;
        } while(start < end);

        throw new XRPCSenderException(
                "XRPC " + msgType + " message nog well-formed: " +
                "declaration of the namespace \"" + namespaceURI +
                "\" not found.");
    }

    /**
     * Given a prefix and an XRPC message, find the Namespace URI it
     * represents.
     *
     * Returns: the Namespace URI, or throws XRPCException
     **/
    public static String getNamespaceURI(String msg,
                                         String prefix)
        throws XRPCException
    {
        String searchStr = "xmlns:" + prefix;

        int i = msg.indexOf(searchStr);
        if(i < 0){
            throw new XRPCException("Prefix definition not found: \"" +
                    prefix + "\"");
        }

        /* Skip whitespaces between "xmlns:"prefix and '=' */
        i += searchStr.length();
        while(Character.isWhitespace(msg.charAt(i))) i++;
        if(msg.charAt(i) != '=') {
            throw new XRPCException("Expected '=', found '" +
                    msg.charAt(i) + "'");
        }

        /* Skip whitespaces between '=' and '\"'*/
        i++;
        while(Character.isWhitespace(msg.charAt(i))) i++;
        if(msg.charAt(i) != '\"') {
            throw new XRPCException("Expected '\"', found '" +
                    msg.charAt(i) + "'");
        }

        i++; /* start of the namespace URI */
        int j = msg.indexOf("\"", i);
        if(j < 0) {
            throw new XRPCException("Could not find the end '\"' of " +
                    "the namespace URI string");
        }

        return msg.substring(i, j);
    }

    /* Retrieves the values of the parameters of a called XQuery
     * function into a String array.
     *
     * NOTE: the parameter values MUST be single-item sequences
     *       containing ONLY atomic values.
     */
    public static String[] getSingleItemParamValues(String request,
                                                    String soapPrefix,
                                                    String xrpcPrefix,
                                                    XPath xPath,
                                                    int arity)
        throws XRPCException
    {

        String[] values = new String[arity];
        int j = 1;

        /* TODO: may be we can use NodeSet to replace multiple calls to
         *       'evaluate'. */
        try {
            for(int i = 0; i < arity; i++, j++){
                values[i] = xPath.evaluate(
                        "/" + soapPrefix + ":Envelope/" +
                              soapPrefix + ":Body/" +
                              xrpcPrefix + ":request/" +
                              xrpcPrefix + ":call/" +
                              xrpcPrefix + ":sequence[" + j + "]/" +
                              xrpcPrefix + ":atomic-value/text()",
                        new InputSource(new StringReader(request)));
            }
        } catch (Exception e){
            throw new XRPCSenderException(
                    "Failed to execute XPath query:" +
                    e.getClass().getName() +
                    ". Only found " + j + " of " + arity +
                    "parameter value(s).");
        }
        return values;
    }

    /* Evaluate 'xPathExpr' on 'xmlStr' using 'xPath' into a NodeSet,
     * which should contain only *one* node, then return all
     * attributes of the resulting node in a NamedNodeMap.
     *
     * Return a NamedNodeMap
     */
    public static NamedNodeMap getNodeAttributes(XPath xPath,
                                                 String xmlStr,
                                                 String xPathExpr)
        throws Exception
    {
        InputSource inputSource = new InputSource(new StringReader(xmlStr));
        NodeList nodeList = (NodeList) xPath.evaluate(xPathExpr,
                inputSource, XPathConstants.NODESET);
        if(nodeList.getLength() != 1){
            throw new XRPCException("Exactly 1 node is expected, got " +
                                    nodeList.getLength());
        }

        return nodeList.item(0).getAttributes();
    }

    /* Evaluate 'xPathExpr' on 'xmlStr' using 'xPath' into a NodeSet,
     * then retrieve the value of the attribute 'attrName' of each node
     * in the NodeSet.  With this function, one can, e.g., retrieve the
     * values of the ID attribute of all 'person' nodes.
     *
     * Return a String[] with the values of the attribute 'attrName'
     */
    public static String[] getNodeListAttribute(XPath xPath,
                                                String xmlStr,
                                                String xPathExpr,
                                                String attrName)
        throws Exception
    {
        InputSource inputSource = new InputSource(new StringReader(xmlStr));
        NodeList nodeList = (NodeList) xPath.evaluate(xPathExpr,
                inputSource, XPathConstants.NODESET);

        String[] attrValues= new String[nodeList.getLength()];
        for(int i = 0; i < nodeList.getLength(); i++){
            Node n = nodeList.item(i);
            NamedNodeMap nodeMap = n.getAttributes();
            Node attrNode = nodeMap.getNamedItem(attrName);
            attrValues[i] = attrNode.getNodeValue();
        }

        return attrValues;
    }
}


-------------------------------------------------------------------------
SF.Net email is sponsored by: The Future of Linux Business White Paper
from Novell.  From the desktop to the data center, Linux is going
mainstream.  Let it simplify your IT future.
http://altfarm.mediaplex.com/ad/ck/8857-50307-18918-4
_______________________________________________
Monetdb-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/monetdb-checkins

Reply via email to