/* * Copyright 2001-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package samples.transport.tcp; import org.apache.axis.AxisEngine; import org.apache.axis.AxisFault; import org.apache.axis.Message; import org.apache.axis.MessageContext; import org.apache.axis.components.logger.LogFactory; import org.apache.axis.configuration.XMLStringProvider; import org.apache.axis.deployment.wsdd.WSDDConstants; import org.apache.axis.server.AxisServer; import org.apache.axis.utils.Options; import org.apache.commons.logging.Log; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.ServerSocket; import java.net.Socket; import java.net.URL; /** * Listen for incoming socket connections on the specified socket. Take * incoming messages and dispatch them. * * @author Rob Jellinghaus (robj@unrealities.com) * @author Doug Davis (dug@us.ibm.com) */ public class TCPListener implements Runnable { static Log log = LogFactory.getLog(TCPSender.class.getName()); // These have default values. private String transportName = "TCPTransport"; private static final String AXIS_ENGINE = "AxisEngine" ; private int port; private ServerSocket srvSocket; private AxisEngine engine = null ; // becomes true when we want to quit private boolean done = false; static final String wsdd = "<deployment xmlns=\"http://xml.apache.org/axis/wsdd/\" " + "xmlns:java=\"" + WSDDConstants.URI_WSDD_JAVA + "\">\n" + " <transport name=\"tcp\" pivot=\"java:samples.transport.tcp.TCPSender\"/>\n" + " <service name=\"" + WSDDConstants.URI_WSDD + "\" provider=\"java:MSG\">\n" + " <parameter name=\"allowedMethods\" value=\"AdminService\"/>\n" + " <parameter name=\"className\" value=\"org.apache.axis.utils.Admin\"/>\n" + " </service>\n" + "</deployment>"; public static void main (String args[]) { new TCPListener(args).run(); } public TCPListener (String[] args) { // look for -p, -d arguments try { Options options = new Options(args); port = new URL(options.getURL()).getPort(); } catch (MalformedURLException ex) { log.error("Hosed URL: "+ex); System.exit(1); } try { srvSocket = new ServerSocket(port); } catch (IOException ex) { log.error("Can't create server socket on port "+port); System.exit(1); } log.info("TCPListener is listening on port "+port+"."); } public void run () { if (srvSocket == null) { return; } Socket sock; while (!done) { try { sock = srvSocket.accept(); log.info("TCPListener received new connection: "+sock); new Thread(new SocketHandler(sock)).start(); } catch (IOException ex) { /** stop complaining about this! it seems to happen on quit, and is not worth mentioning. unless I am confused. -- RobJ */ log.debug("Got IOException on srvSocket.accept: "+ex); } } } public class SocketHandler implements Runnable { private Socket socket; public SocketHandler (Socket socket) { this.socket = socket; } public void run () { // get the input stream if ( engine == null ) { XMLStringProvider provider = new XMLStringProvider(wsdd); engine = new AxisServer(provider); engine.init(); } /* Place the Request message in the MessagContext object - notice */ /* that we just leave it as a 'ServletRequest' object and let the */ /* Message processing routine convert it - we don't do it since we */ /* don't know how it's going to be used - perhaps it might not */ /* even need to be parsed. */ /*******************************************************************/ MessageContext msgContext = new MessageContext(engine); InputStream inp; try { inp = socket.getInputStream(); } catch (IOException ex) { log.error("Couldn't get input stream from "+socket); return; } // ROBJ 911 // the plain ol' inputstream seems to hang in the SAX parse..... WHY????? // because there is no content length! //Message msg = new Message( nbbinp, "InputStream" ); Message msg = null; try { StringBuffer line = new StringBuffer(); int b = 0; while ((b = inp.read()) != '\r') { line.append((char)b); } // got to '\r', skip it and '\n' if (inp.read() != '\n') { log.error("Length line "+line+" was not terminated with \r\n"); return; } // TEST SUPPORT ONLY // If the line says "ping", then respond "\n". // If the line says "quit", then respond "\n" and exit. if (line.toString().equals("ping")) { socket.getOutputStream().write(new String("\n").getBytes()); return; } else if (line.toString().equals("quit")) { // peacefully die socket.getOutputStream().write(new String("\n").getBytes()); socket.close(); // The following appears to deadlock. It will get cleaned // up on exit anyway... // srvSocket.close(); log.error("AxisListener quitting."); System.exit(0); } // OK, assume it is content length int len = Integer.parseInt(line.toString()); // read that many bytes into ByteArrayInputStream... // experiment, doesn't work: // NonBlockingBufferedInputStream nbbinp = new NonBlockingBufferedInputStream(); // nbbinp.setContentLength(len); // nbbinp.setInputStream(inp); // msg = new Message(nbbinp, "InputStream"); byte[] mBytes = new byte[len]; inp.read(mBytes); msg = new Message(new ByteArrayInputStream(mBytes)); } catch (IOException ex) { log.error("Couldn't read from socket input stream: "+ex); return; } /* Set the request(incoming) message field in the context */ /**********************************************************/ msgContext.setRequestMessage( msg ); /* Set the Transport Specific Request/Response chains IDs */ /******************************************************/ msgContext.setTransportName(transportName); try { /* Invoke the Axis engine... */ /*****************************/ engine.invoke( msgContext ); } catch( Exception e ) { AxisFault fault = AxisFault.makeFault(e); msgContext.setResponseMessage( new Message(fault) ); } /* Send it back along the wire... */ /***********************************/ msg = msgContext.getResponseMessage(); String response = null; if (msg == null) { response="No data"; } else { try { response = (String) msg.getSOAPPartAsString(); } catch (AxisFault fault) { msg = new Message(fault); try { response = (String)msg.getSOAPPartAsString(); } catch (AxisFault fault2) { response = fault2.dumpToString(); } } } try { OutputStream buf = new BufferedOutputStream(socket.getOutputStream()); // this should probably specify UTF-8, but for now, for Java interop, // use default encoding buf.write(response.getBytes()); buf.close(); } catch (IOException ex) { log.error("Can't write response to socket "+port+", response is: "+response); } } } }