You are viewing a plain text version of this content. The canonical link for it is here.
Posted to soap-dev@ws.apache.org by sa...@locus.apache.org on 2000/08/08 08:32:06 UTC
cvs commit: xml-soap/java/src/org/apache/soap/server/http RPCRouterServlet.java
sanjiva 00/08/07 23:32:05
Added: java/src/org/apache/soap/server/http RPCRouterServlet.java
Log:
servlet version of RPC Router. A detailed note is being posted to
the soap-dev list .. see there for more.
Submitted by: Steven J. McDowall, "Noor Zaman" <no...@instill.com>
Reviewed by: Sanjiva Weerawarana
Revision Changes Path
1.1 xml-soap/java/src/org/apache/soap/server/http/RPCRouterServlet.java
Index: RPCRouterServlet.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "SOAP" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2000, International
* Business Machines, Inc., http://www.apache.org. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.soap.server.http;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import javax.servlet.* ;
import javax.servlet.http.* ;
import org.w3c.dom.* ;
import org.apache.soap.*;
import org.apache.soap.rpc.*;
import org.apache.soap.server.*;
import org.apache.soap.encoding.*;
import org.apache.soap.util.* ;
import org.apache.soap.util.xml.* ;
/**
* @author Sanjiva Weerawarana <sa...@watson.ibm.com>
* @author Mat
* @author Steven McDowall <sj...@aptest.com>
*/
public class RPCRouterServlet extends HttpServlet {
private final static String RPC_ROUTER_ID = "rpcRouter";
private final static String SERVICE_MANAGER_ID = "serviceManager";
private static final String SCRIPT_CLASS = "com.ibm.bsf.BSFManager";
private static final String SCRIPT_INVOKER =
"org.apache.soap.server.InvokeBSF";
public void init () throws ServletException {
ServletConfig config = getServletConfig ();
ServletContext context = config.getServletContext ();
// create the service manager if necessary. NOTE: This approach
// will not work if this servlet is put in a webapp that is
// marked distributed .. the servlet context is unique only
// per JVM. In that case we'll have to use an external database
// to store the global stuff.
synchronized (context) {
Object o = context.getAttribute (RPC_ROUTER_ID);
if (o == null) { // isn't this always true?? (is init() called once?)
RPCRouter rpcRouter = new RPCRouter ();
ServiceManager serviceManager = new ServiceManager ();
rpcRouter.setServiceManager (serviceManager);
context.setAttribute (RPC_ROUTER_ID, rpcRouter);
context.setAttribute (SERVICE_MANAGER_ID, serviceManager);
}
}
}
public void doPost (HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// locate the rpcrouter and service manager
ServletConfig config = getServletConfig ();
ServletContext context = config.getServletContext ();
HttpSession session = req.getSession ();
RPCRouter rpcRouter = (RPCRouter) context.getAttribute (RPC_ROUTER_ID);
ServiceManager serviceManager =
(ServiceManager) context.getAttribute (SERVICE_MANAGER_ID);
Response resp = null;
String targetID = null;
String contentType = req.getContentType ();
int contentLength = req.getContentLength ();
// set the outgoing content type and pick up the writer to write
// to *after* that
res.setContentType (Constants.HEADERVAL_CONTENT_TYPE_UTF8);
PrintWriter out = res.getWriter ();
Call call = null;
if ((contentType == null) ||
!contentType.equals (Constants.HEADERVAL_CONTENT_TYPE)) {
res.sendError (res.SC_BAD_REQUEST, "Content type must be: '" +
Constants.HEADERVAL_CONTENT_TYPE + "'.");
return;
} else if (contentLength < 0) {
res.sendError (res.SC_BAD_REQUEST, "Content length must be specified.");
return;
}
try {
System.err.println (">>(" + new Date() + ") Processing SOAP request...");
Reader requestReader = req.getReader ();
char[] payload = new char[contentLength];
int offset = 0;
while (offset < contentLength) {
offset += requestReader.read (payload, offset, contentLength - offset);
}
// Parse the incoming request stream.
org.apache.soap.util.xml.XMLParserLiaison xpl =
new XercesParserLiaison ();
Document callDoc = xpl.read("- SOAP HTTP RPC Call Envelope -",
new CharArrayReader (payload));
Element payloadEl = null;
if (callDoc == null) {
throw new SOAPException(Constants.FAULT_CODE_PROTOCOL,
"DOM parsing error: " + payload);
}
// extract the call
try {
payloadEl = callDoc.getDocumentElement ();
Envelope callEnv = Envelope.unmarshall (payloadEl);
call = rpcRouter.extractCallFromEnvelope (callEnv);
targetID = call.getTargetObjectURI ();
} catch (IllegalArgumentException e) {
String msg = e.getMessage ();
String faultCode =
(msg != null && msg.equals (Constants.ERR_MSG_VERSION_MISMATCH))
? Constants.FAULT_CODE_VERSION_MISMATCH
: Constants.FAULT_CODE_CLIENT;
throw new SOAPException (faultCode, msg, e);
}
// call on a valid method name?
if (!rpcRouter.validCall (call)) {
throw new SOAPException (Constants.FAULT_CODE_SERVER,
"Method '" + call.getMethodName () +
"' is not supported.");
}
// lifecycle stuff of target object: what's the class to instantiate?
DeploymentDescriptor dd = serviceManager.query (targetID);
int scope = dd.getScope ();
byte providerType = dd.getProviderType ();
String className;
Object targetObject = null;
if (providerType == DeploymentDescriptor.PROVIDER_JAVA) {
className = dd.getProviderClass ();
} else {
// for scripts, we need a new BSF manager basically
className = SCRIPT_CLASS;
}
// determine the scope and lock object to use to manage the lifecycle
// of the service providing object
Object scopeLock = null;
if (scope == DeploymentDescriptor.SCOPE_REQUEST) {
scopeLock = this; // no need to register .. create, use and dink
} else if (scope == DeploymentDescriptor.SCOPE_SESSION) {
scopeLock = session;
} else if (scope == DeploymentDescriptor.SCOPE_APPLICATION) {
scopeLock = context;
} else {
throw new SOAPException (Constants.FAULT_CODE_SERVER,
"Service uses deprecated object scope " +
"'page': inform provider of error");
}
// create the object if necessary
boolean freshObject = false;
// find the target object on which the requested method should
// be invoked
if (targetID.equals (ServerConstants.SERVICE_MANAGER_SERVICE_NAME)) {
targetObject = serviceManager;
} else {
// locate (or create) the target object and invoke the method
synchronized (scopeLock) {
if (scopeLock == session) {
targetObject = session.getAttribute (targetID);
} else if (scopeLock == context) {
targetObject = context.getAttribute (targetID);
} else {
targetObject = null;
}
if (targetObject == null) {
try {
Class c = Class.forName (className);
if (dd.getIsStatic ()) {
targetObject = c;
} else {
targetObject = c.newInstance ();
}
freshObject = true;
} catch (Exception e) {
String msg;
if (providerType == DeploymentDescriptor.PROVIDER_JAVA) {
msg = "Unable to resolve target object: " + e.getMessage ();
} else {
msg = "Unable to load BSF: script services not available " +
"without BSF: " + e.getMessage ();
}
throw new SOAPException (RPCConstants.FAULT_CODE_SERVER_BAD_TARGET_OBJECT_URI,
msg, e);
}
}
// remember the created instance if the scope is not REQUEST;
// in that case the object is to be thrown away after handling
// the request
if (scopeLock == session) {
session.setAttribute (targetID, targetObject);
} else if (scopeLock == context) {
context.setAttribute (targetID, targetObject);
}
}
}
// if script provider type and first time to it, then load and
// exec the script
if (providerType != DeploymentDescriptor.PROVIDER_JAVA &&
freshObject) {
// find the class that provides the BSF services (done
// this way via reflection to avoid a static dependency on BSF)
Class bc = Class.forName (SCRIPT_INVOKER);
// get the script string to exec
String script = dd.getScriptFilenameOrString ();
if (providerType == DeploymentDescriptor.PROVIDER_SCRIPT_FILE) {
String fileName = context.getRealPath (script);
script = IOUtils.getStringFromReader (new FileReader (fileName));
}
// exec it
Class[] sig = {DeploymentDescriptor.class,
Object.class,
String.class};
Method m = MethodUtils.getMethod (bc, "init", sig, true);
m.invoke (null, new Object[] {dd, targetObject, script});
}
// invoke the method on the target object
resp = rpcRouter.invoke (call, targetObject);
} catch (SOAPException e) {
Fault fault = new Fault ();
String faultCode = e.getFaultCode ();
String faultString = e.getMessage ();
if (faultCode == null ||
faultCode.startsWith (Constants.FAULT_CODE_SERVER)) {
res.setStatus (ServerConstants.SC_INTERNAL_SERVER_ERROR);
}
else if (faultCode.startsWith (Constants.FAULT_CODE_CLIENT)) {
res.setStatus (ServerConstants.SC_BAD_REQUEST);
}
fault.setFaultCode (faultCode);
fault.setFaultString (faultString);
fault.setFaultActorURI (req.getRequestURI ());
resp = new Response (null, null, fault, null, null, null);
} catch (Throwable t) {
// some unknown error occurred .. let's send the stacktrace out
// hoping it'll be useful to someone (can't do a SOAPFault though
// because if it was a SOAP problem it'd have been caught above)
t.printStackTrace ();
t.printStackTrace (out);
}
// Send it out.
if (resp != null) {
try {
// Build an envelope containing the response.
Envelope respEnvelope = resp.buildEnvelope ();
SOAPMappingRegistry smr = (call != null
? call.getSOAPMappingRegistry ()
: new SOAPMappingRegistry());
respEnvelope.marshall (out, smr);
} catch (Exception e) {
throw new ServletException ("Error building response envelope", e);
}
}
}
}
RE: cvs commit: xml-soap/java/src/org/apache/soap/server/http RPCRouterServlet.java
Posted by "Steven J. McDowall" <sj...@uswest.net>.
Does something need to be added to build.xml to make this stuff
compile?
I tried to ant the newest tree and the Servlet stuff didn't happen..
-Steve
-----Original Message-----
From: sanjiva@locus.apache.org [mailto:sanjiva@locus.apache.org]
Sent: Tuesday, August 08, 2000 1:32 AM
To: xml-soap-cvs@apache.org
Subject: cvs commit: xml-soap/java/src/org/apache/soap/server/http
RPCRouterServlet.java
sanjiva 00/08/07 23:32:05
Added: java/src/org/apache/soap/server/http RPCRouterServlet.java
Log:
servlet version of RPC Router. A detailed note is being posted to
the soap-dev list .. see there for more.
Submitted by: Steven J. McDowall, "Noor Zaman" <no...@instill.com>
Reviewed by: Sanjiva Weerawarana
Revision Changes Path
1.1
xml-soap/java/src/org/apache/soap/server/http/RPCRouterServlet.java
Index: RPCRouterServlet.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "SOAP" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2000, International
* Business Machines, Inc., http://www.apache.org. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.soap.server.http;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import javax.servlet.* ;
import javax.servlet.http.* ;
import org.w3c.dom.* ;
import org.apache.soap.*;
import org.apache.soap.rpc.*;
import org.apache.soap.server.*;
import org.apache.soap.encoding.*;
import org.apache.soap.util.* ;
import org.apache.soap.util.xml.* ;
/**
* @author Sanjiva Weerawarana <sa...@watson.ibm.com>
* @author Mat
* @author Steven McDowall <sj...@aptest.com>
*/
public class RPCRouterServlet extends HttpServlet {
private final static String RPC_ROUTER_ID = "rpcRouter";
private final static String SERVICE_MANAGER_ID = "serviceManager";
private static final String SCRIPT_CLASS = "com.ibm.bsf.BSFManager";
private static final String SCRIPT_INVOKER =
"org.apache.soap.server.InvokeBSF";
public void init () throws ServletException {
ServletConfig config = getServletConfig ();
ServletContext context = config.getServletContext ();
// create the service manager if necessary. NOTE: This approach
// will not work if this servlet is put in a webapp that is
// marked distributed .. the servlet context is unique only
// per JVM. In that case we'll have to use an external database
// to store the global stuff.
synchronized (context) {
Object o = context.getAttribute (RPC_ROUTER_ID);
if (o == null) { // isn't this always true?? (is init() called
once?)
RPCRouter rpcRouter = new RPCRouter ();
ServiceManager serviceManager = new ServiceManager ();
rpcRouter.setServiceManager (serviceManager);
context.setAttribute (RPC_ROUTER_ID, rpcRouter);
context.setAttribute (SERVICE_MANAGER_ID, serviceManager);
}
}
}
public void doPost (HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// locate the rpcrouter and service manager
ServletConfig config = getServletConfig ();
ServletContext context = config.getServletContext ();
HttpSession session = req.getSession ();
RPCRouter rpcRouter = (RPCRouter) context.getAttribute
(RPC_ROUTER_ID);
ServiceManager serviceManager =
(ServiceManager) context.getAttribute (SERVICE_MANAGER_ID);
Response resp = null;
String targetID = null;
String contentType = req.getContentType ();
int contentLength = req.getContentLength ();
// set the outgoing content type and pick up the writer to write
// to *after* that
res.setContentType (Constants.HEADERVAL_CONTENT_TYPE_UTF8);
PrintWriter out = res.getWriter ();
Call call = null;
if ((contentType == null) ||
!contentType.equals (Constants.HEADERVAL_CONTENT_TYPE)) {
res.sendError (res.SC_BAD_REQUEST, "Content type must be: '" +
Constants.HEADERVAL_CONTENT_TYPE + "'.");
return;
} else if (contentLength < 0) {
res.sendError (res.SC_BAD_REQUEST, "Content length must be
specified.");
return;
}
try {
System.err.println (">>(" + new Date() + ") Processing SOAP
request...");
Reader requestReader = req.getReader ();
char[] payload = new char[contentLength];
int offset = 0;
while (offset < contentLength) {
offset += requestReader.read (payload, offset, contentLength - offset);
}
// Parse the incoming request stream.
org.apache.soap.util.xml.XMLParserLiaison xpl =
new XercesParserLiaison ();
Document callDoc = xpl.read("- SOAP HTTP RPC Call Envelope -",
new CharArrayReader (payload));
Element payloadEl = null;
if (callDoc == null) {
throw new SOAPException(Constants.FAULT_CODE_PROTOCOL,
"DOM parsing error: " + payload);
}
// extract the call
try {
payloadEl = callDoc.getDocumentElement ();
Envelope callEnv = Envelope.unmarshall (payloadEl);
call = rpcRouter.extractCallFromEnvelope (callEnv);
targetID = call.getTargetObjectURI ();
} catch (IllegalArgumentException e) {
String msg = e.getMessage ();
String faultCode =
(msg != null && msg.equals (Constants.ERR_MSG_VERSION_MISMATCH))
? Constants.FAULT_CODE_VERSION_MISMATCH
: Constants.FAULT_CODE_CLIENT;
throw new SOAPException (faultCode, msg, e);
}
// call on a valid method name?
if (!rpcRouter.validCall (call)) {
throw new SOAPException (Constants.FAULT_CODE_SERVER,
"Method '" + call.getMethodName () +
"' is not supported.");
}
// lifecycle stuff of target object: what's the class to
instantiate?
DeploymentDescriptor dd = serviceManager.query (targetID);
int scope = dd.getScope ();
byte providerType = dd.getProviderType ();
String className;
Object targetObject = null;
if (providerType == DeploymentDescriptor.PROVIDER_JAVA) {
className = dd.getProviderClass ();
} else {
// for scripts, we need a new BSF manager basically
className = SCRIPT_CLASS;
}
// determine the scope and lock object to use to manage the
lifecycle
// of the service providing object
Object scopeLock = null;
if (scope == DeploymentDescriptor.SCOPE_REQUEST) {
scopeLock = this; // no need to register .. create, use and dink
} else if (scope == DeploymentDescriptor.SCOPE_SESSION) {
scopeLock = session;
} else if (scope == DeploymentDescriptor.SCOPE_APPLICATION) {
scopeLock = context;
} else {
throw new SOAPException (Constants.FAULT_CODE_SERVER,
"Service uses deprecated object scope " +
"'page': inform provider of error");
}
// create the object if necessary
boolean freshObject = false;
// find the target object on which the requested method should
// be invoked
if (targetID.equals (ServerConstants.SERVICE_MANAGER_SERVICE_NAME))
{
targetObject = serviceManager;
} else {
// locate (or create) the target object and invoke the method
synchronized (scopeLock) {
if (scopeLock == session) {
targetObject = session.getAttribute (targetID);
} else if (scopeLock == context) {
targetObject = context.getAttribute (targetID);
} else {
targetObject = null;
}
if (targetObject == null) {
try {
Class c = Class.forName (className);
if (dd.getIsStatic ()) {
targetObject = c;
} else {
targetObject = c.newInstance ();
}
freshObject = true;
} catch (Exception e) {
String msg;
if (providerType == DeploymentDescriptor.PROVIDER_JAVA) {
msg = "Unable to resolve target object: " + e.getMessage ();
} else {
msg = "Unable to load BSF: script services not available " +
"without BSF: " + e.getMessage ();
}
throw new SOAPException
(RPCConstants.FAULT_CODE_SERVER_BAD_TARGET_OBJECT_URI,
msg, e);
}
}
// remember the created instance if the scope is not REQUEST;
// in that case the object is to be thrown away after handling
// the request
if (scopeLock == session) {
session.setAttribute (targetID, targetObject);
} else if (scopeLock == context) {
context.setAttribute (targetID, targetObject);
}
}
}
// if script provider type and first time to it, then load and
// exec the script
if (providerType != DeploymentDescriptor.PROVIDER_JAVA &&
freshObject) {
// find the class that provides the BSF services (done
// this way via reflection to avoid a static dependency on BSF)
Class bc = Class.forName (SCRIPT_INVOKER);
// get the script string to exec
String script = dd.getScriptFilenameOrString ();
if (providerType == DeploymentDescriptor.PROVIDER_SCRIPT_FILE) {
String fileName = context.getRealPath (script);
script = IOUtils.getStringFromReader (new FileReader (fileName));
}
// exec it
Class[] sig = {DeploymentDescriptor.class,
Object.class,
String.class};
Method m = MethodUtils.getMethod (bc, "init", sig, true);
m.invoke (null, new Object[] {dd, targetObject, script});
}
// invoke the method on the target object
resp = rpcRouter.invoke (call, targetObject);
} catch (SOAPException e) {
Fault fault = new Fault ();
String faultCode = e.getFaultCode ();
String faultString = e.getMessage ();
if (faultCode == null ||
faultCode.startsWith (Constants.FAULT_CODE_SERVER)) {
res.setStatus (ServerConstants.SC_INTERNAL_SERVER_ERROR);
}
else if (faultCode.startsWith (Constants.FAULT_CODE_CLIENT)) {
res.setStatus (ServerConstants.SC_BAD_REQUEST);
}
fault.setFaultCode (faultCode);
fault.setFaultString (faultString);
fault.setFaultActorURI (req.getRequestURI ());
resp = new Response (null, null, fault, null, null, null);
} catch (Throwable t) {
// some unknown error occurred .. let's send the stacktrace out
// hoping it'll be useful to someone (can't do a SOAPFault though
// because if it was a SOAP problem it'd have been caught above)
t.printStackTrace ();
t.printStackTrace (out);
}
// Send it out.
if (resp != null) {
try {
// Build an envelope containing the response.
Envelope respEnvelope = resp.buildEnvelope ();
SOAPMappingRegistry smr = (call != null
? call.getSOAPMappingRegistry ()
: new SOAPMappingRegistry());
respEnvelope.marshall (out, smr);
} catch (Exception e) {
throw new ServletException ("Error building response envelope", e);
}
}
}
}
RE: cvs commit: xml-soap/java/src/org/apache/soap/server/http RPCRouterServlet.java
Posted by "Steven J. McDowall" <sj...@uswest.net>.
Does something need to be added to build.xml to make this stuff
compile?
I tried to ant the newest tree and the Servlet stuff didn't happen..
-Steve
-----Original Message-----
From: sanjiva@locus.apache.org [mailto:sanjiva@locus.apache.org]
Sent: Tuesday, August 08, 2000 1:32 AM
To: xml-soap-cvs@apache.org
Subject: cvs commit: xml-soap/java/src/org/apache/soap/server/http
RPCRouterServlet.java
sanjiva 00/08/07 23:32:05
Added: java/src/org/apache/soap/server/http RPCRouterServlet.java
Log:
servlet version of RPC Router. A detailed note is being posted to
the soap-dev list .. see there for more.
Submitted by: Steven J. McDowall, "Noor Zaman" <no...@instill.com>
Reviewed by: Sanjiva Weerawarana
Revision Changes Path
1.1
xml-soap/java/src/org/apache/soap/server/http/RPCRouterServlet.java
Index: RPCRouterServlet.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "SOAP" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2000, International
* Business Machines, Inc., http://www.apache.org. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.soap.server.http;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import javax.servlet.* ;
import javax.servlet.http.* ;
import org.w3c.dom.* ;
import org.apache.soap.*;
import org.apache.soap.rpc.*;
import org.apache.soap.server.*;
import org.apache.soap.encoding.*;
import org.apache.soap.util.* ;
import org.apache.soap.util.xml.* ;
/**
* @author Sanjiva Weerawarana <sa...@watson.ibm.com>
* @author Mat
* @author Steven McDowall <sj...@aptest.com>
*/
public class RPCRouterServlet extends HttpServlet {
private final static String RPC_ROUTER_ID = "rpcRouter";
private final static String SERVICE_MANAGER_ID = "serviceManager";
private static final String SCRIPT_CLASS = "com.ibm.bsf.BSFManager";
private static final String SCRIPT_INVOKER =
"org.apache.soap.server.InvokeBSF";
public void init () throws ServletException {
ServletConfig config = getServletConfig ();
ServletContext context = config.getServletContext ();
// create the service manager if necessary. NOTE: This approach
// will not work if this servlet is put in a webapp that is
// marked distributed .. the servlet context is unique only
// per JVM. In that case we'll have to use an external database
// to store the global stuff.
synchronized (context) {
Object o = context.getAttribute (RPC_ROUTER_ID);
if (o == null) { // isn't this always true?? (is init() called
once?)
RPCRouter rpcRouter = new RPCRouter ();
ServiceManager serviceManager = new ServiceManager ();
rpcRouter.setServiceManager (serviceManager);
context.setAttribute (RPC_ROUTER_ID, rpcRouter);
context.setAttribute (SERVICE_MANAGER_ID, serviceManager);
}
}
}
public void doPost (HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// locate the rpcrouter and service manager
ServletConfig config = getServletConfig ();
ServletContext context = config.getServletContext ();
HttpSession session = req.getSession ();
RPCRouter rpcRouter = (RPCRouter) context.getAttribute
(RPC_ROUTER_ID);
ServiceManager serviceManager =
(ServiceManager) context.getAttribute (SERVICE_MANAGER_ID);
Response resp = null;
String targetID = null;
String contentType = req.getContentType ();
int contentLength = req.getContentLength ();
// set the outgoing content type and pick up the writer to write
// to *after* that
res.setContentType (Constants.HEADERVAL_CONTENT_TYPE_UTF8);
PrintWriter out = res.getWriter ();
Call call = null;
if ((contentType == null) ||
!contentType.equals (Constants.HEADERVAL_CONTENT_TYPE)) {
res.sendError (res.SC_BAD_REQUEST, "Content type must be: '" +
Constants.HEADERVAL_CONTENT_TYPE + "'.");
return;
} else if (contentLength < 0) {
res.sendError (res.SC_BAD_REQUEST, "Content length must be
specified.");
return;
}
try {
System.err.println (">>(" + new Date() + ") Processing SOAP
request...");
Reader requestReader = req.getReader ();
char[] payload = new char[contentLength];
int offset = 0;
while (offset < contentLength) {
offset += requestReader.read (payload, offset, contentLength - offset);
}
// Parse the incoming request stream.
org.apache.soap.util.xml.XMLParserLiaison xpl =
new XercesParserLiaison ();
Document callDoc = xpl.read("- SOAP HTTP RPC Call Envelope -",
new CharArrayReader (payload));
Element payloadEl = null;
if (callDoc == null) {
throw new SOAPException(Constants.FAULT_CODE_PROTOCOL,
"DOM parsing error: " + payload);
}
// extract the call
try {
payloadEl = callDoc.getDocumentElement ();
Envelope callEnv = Envelope.unmarshall (payloadEl);
call = rpcRouter.extractCallFromEnvelope (callEnv);
targetID = call.getTargetObjectURI ();
} catch (IllegalArgumentException e) {
String msg = e.getMessage ();
String faultCode =
(msg != null && msg.equals (Constants.ERR_MSG_VERSION_MISMATCH))
? Constants.FAULT_CODE_VERSION_MISMATCH
: Constants.FAULT_CODE_CLIENT;
throw new SOAPException (faultCode, msg, e);
}
// call on a valid method name?
if (!rpcRouter.validCall (call)) {
throw new SOAPException (Constants.FAULT_CODE_SERVER,
"Method '" + call.getMethodName () +
"' is not supported.");
}
// lifecycle stuff of target object: what's the class to
instantiate?
DeploymentDescriptor dd = serviceManager.query (targetID);
int scope = dd.getScope ();
byte providerType = dd.getProviderType ();
String className;
Object targetObject = null;
if (providerType == DeploymentDescriptor.PROVIDER_JAVA) {
className = dd.getProviderClass ();
} else {
// for scripts, we need a new BSF manager basically
className = SCRIPT_CLASS;
}
// determine the scope and lock object to use to manage the
lifecycle
// of the service providing object
Object scopeLock = null;
if (scope == DeploymentDescriptor.SCOPE_REQUEST) {
scopeLock = this; // no need to register .. create, use and dink
} else if (scope == DeploymentDescriptor.SCOPE_SESSION) {
scopeLock = session;
} else if (scope == DeploymentDescriptor.SCOPE_APPLICATION) {
scopeLock = context;
} else {
throw new SOAPException (Constants.FAULT_CODE_SERVER,
"Service uses deprecated object scope " +
"'page': inform provider of error");
}
// create the object if necessary
boolean freshObject = false;
// find the target object on which the requested method should
// be invoked
if (targetID.equals (ServerConstants.SERVICE_MANAGER_SERVICE_NAME))
{
targetObject = serviceManager;
} else {
// locate (or create) the target object and invoke the method
synchronized (scopeLock) {
if (scopeLock == session) {
targetObject = session.getAttribute (targetID);
} else if (scopeLock == context) {
targetObject = context.getAttribute (targetID);
} else {
targetObject = null;
}
if (targetObject == null) {
try {
Class c = Class.forName (className);
if (dd.getIsStatic ()) {
targetObject = c;
} else {
targetObject = c.newInstance ();
}
freshObject = true;
} catch (Exception e) {
String msg;
if (providerType == DeploymentDescriptor.PROVIDER_JAVA) {
msg = "Unable to resolve target object: " + e.getMessage ();
} else {
msg = "Unable to load BSF: script services not available " +
"without BSF: " + e.getMessage ();
}
throw new SOAPException
(RPCConstants.FAULT_CODE_SERVER_BAD_TARGET_OBJECT_URI,
msg, e);
}
}
// remember the created instance if the scope is not REQUEST;
// in that case the object is to be thrown away after handling
// the request
if (scopeLock == session) {
session.setAttribute (targetID, targetObject);
} else if (scopeLock == context) {
context.setAttribute (targetID, targetObject);
}
}
}
// if script provider type and first time to it, then load and
// exec the script
if (providerType != DeploymentDescriptor.PROVIDER_JAVA &&
freshObject) {
// find the class that provides the BSF services (done
// this way via reflection to avoid a static dependency on BSF)
Class bc = Class.forName (SCRIPT_INVOKER);
// get the script string to exec
String script = dd.getScriptFilenameOrString ();
if (providerType == DeploymentDescriptor.PROVIDER_SCRIPT_FILE) {
String fileName = context.getRealPath (script);
script = IOUtils.getStringFromReader (new FileReader (fileName));
}
// exec it
Class[] sig = {DeploymentDescriptor.class,
Object.class,
String.class};
Method m = MethodUtils.getMethod (bc, "init", sig, true);
m.invoke (null, new Object[] {dd, targetObject, script});
}
// invoke the method on the target object
resp = rpcRouter.invoke (call, targetObject);
} catch (SOAPException e) {
Fault fault = new Fault ();
String faultCode = e.getFaultCode ();
String faultString = e.getMessage ();
if (faultCode == null ||
faultCode.startsWith (Constants.FAULT_CODE_SERVER)) {
res.setStatus (ServerConstants.SC_INTERNAL_SERVER_ERROR);
}
else if (faultCode.startsWith (Constants.FAULT_CODE_CLIENT)) {
res.setStatus (ServerConstants.SC_BAD_REQUEST);
}
fault.setFaultCode (faultCode);
fault.setFaultString (faultString);
fault.setFaultActorURI (req.getRequestURI ());
resp = new Response (null, null, fault, null, null, null);
} catch (Throwable t) {
// some unknown error occurred .. let's send the stacktrace out
// hoping it'll be useful to someone (can't do a SOAPFault though
// because if it was a SOAP problem it'd have been caught above)
t.printStackTrace ();
t.printStackTrace (out);
}
// Send it out.
if (resp != null) {
try {
// Build an envelope containing the response.
Envelope respEnvelope = resp.buildEnvelope ();
SOAPMappingRegistry smr = (call != null
? call.getSOAPMappingRegistry ()
: new SOAPMappingRegistry());
respEnvelope.marshall (out, smr);
} catch (Exception e) {
throw new ServletException ("Error building response envelope", e);
}
}
}
}