/******************************************************************************* * Copyright (c) 2009 MATERNA Information & Communications. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html. For further * project-related information visit http://www.ws4d.org. The most recent * version of the JMEDS framework can be obtained from * http://sourceforge.net/projects/ws4d-javame. ******************************************************************************/ package org.ws4d.java.communication.protocol.soap.server; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.ws4d.java.DPWSFramework; import org.ws4d.java.communication.ProtocolData; import org.ws4d.java.communication.connection.ip.IPAddress; import org.ws4d.java.communication.connection.udp.Datagram; import org.ws4d.java.communication.connection.udp.DatagramInputStream; import org.ws4d.java.communication.connection.udp.UDPDatagramHandler; import org.ws4d.java.communication.connection.udp.UDPServer; import org.ws4d.java.communication.monitor.MonitorStreamFactory; import org.ws4d.java.communication.monitor.MonitoredInputStream; import org.ws4d.java.communication.monitor.MonitoredMessageReceiver; import org.ws4d.java.communication.monitor.MonitoredOutputStream; import org.ws4d.java.communication.monitor.MonitoringContext; import org.ws4d.java.communication.protocol.soap.SOAPoverUDPClient; import org.ws4d.java.communication.protocol.soap.generator.DefaultMessageDiscarder; import org.ws4d.java.communication.protocol.soap.generator.MessageReceiver; import org.ws4d.java.communication.protocol.soap.generator.SOAPMessageGeneratorFactory; import org.ws4d.java.message.Message; import org.ws4d.java.types.ByteArrayBuffer; import org.ws4d.java.util.Log; import org.ws4d.java.util.Math; /** * SOAP-over-UDP server. * <p> * This server uses the {@link UDPServer} to listen for incoming UDP datagram * packets which contains SOAP messages. * </p> * <p> * The incoming datagram will be handled by the internal * {@link UDPDatagramHandler} if a {@link MessageReceiver} is set. Uses the * {@link #setReceiver(MessageReceiver)} method to set the correct receiver. * </p> */ public class SOAPoverUDPServer { /** * The local UDP host address that this server should listen to. */ private IPAddress ipAddress = null; /** * The local UDP port that this server should listen to. */ private int port = -1; private String ifaceName; private final SOAPoverUDPDatagramHandler handler; /** * Indicates whether this server is running or not. */ private boolean running = false; /** * Create a SOAP-over-UDP Server with given address and port for a specified * interface. * * @param address the address * @param port the port * @param ifaceName the name of the interface * @param handler the handler which will receive incoming UDP datagrams. * @throws IOException */ public SOAPoverUDPServer(IPAddress ipAddress, int port, String ifaceName, SOAPoverUDPDatagramHandler handler) throws IOException { this.ipAddress = ipAddress; this.port = port; this.ifaceName = ifaceName; this.handler = handler; start(); } /** * Starts the SOAP-over-UDP server. * * @throws IOException */ public synchronized void start() throws IOException { if (running) return; UDPServer.open(ipAddress, port, ifaceName, handler); running = true; } /** * Stops the SOAP-over-UDP server. * * @throws IOException */ public synchronized void stop() throws IOException { if (!running) return; UDPServer.close(ipAddress, port, ifaceName); running = false; } /** * Returns <code>true</code> if the SOAP-over-UDP server is running, * <code>false</code> otherwise. * * @return <code>true</code> if the SOAP-over-UDP server is running, * <code>false</code> otherwise. */ public synchronized boolean isRunning() { return running; } /** * Sends a UDP datagram packet with the UDP datagram socket used for this * SOAP-over-UDP server. * * @param dstAddress the destination address of the datagram packet. * @param dstPort the destination port of the datagram packet. * @param data the content of the datagram packet. * @param len the length of the datagram packet. * @throws IOException */ public void send(IPAddress dstAddress, int dstPort, byte[] data, int len) throws IOException { UDPServer.send(ipAddress, port, ifaceName, dstAddress, dstPort, data, len); } /** * Returns the handler configured on this UDP server instance. * * @return this UDP server's handler */ public SOAPoverUDPDatagramHandler getHandler() { return handler; } /** * Internal SOAP-over-UDP datagram handler. */ public static abstract class SOAPoverUDPDatagramHandler implements UDPDatagramHandler, MessageReceiver { /** * */ public SOAPoverUDPDatagramHandler() { super(); } /* * (non-Javadoc) * @see * org.ws4d.java.communication.connection.udp.UDPDatagramHandler#handle * (org.ws4d.java.communication.connection.udp.Datagram, * org.ws4d.java.communication.DPWSProtocolData) */ public void handle(Datagram datagram, ProtocolData protocolData) throws IOException { InputStream in; MonitorStreamFactory monFac = DPWSFramework.getMonitorStreamFactory(); if (monFac != null) { in = new MonitoredInputStream(new DatagramInputStream(datagram), protocolData); } else { in = new DatagramInputStream(datagram); } final MessageReceiver r; if (monFac != null) { MonitoringContext context = monFac.getNewMonitoringContextIn(protocolData); r = new MonitoredMessageReceiver(this, context); } else { r = this; } SOAPMessageGeneratorFactory.getInstance().getSOAP2MessageGeneratorForCurrentThread().deliverMessage(in, r, protocolData, getDiscarder()); in.close(); } protected abstract DefaultMessageDiscarder getDiscarder(); protected final void respond(Message message, IPAddress destAddr, int destPort, ProtocolData pd) { MonitorStreamFactory monFac = DPWSFramework.getMonitorStreamFactory(); MonitoringContext context = null; try { ByteArrayBuffer buffer = SOAPMessageGeneratorFactory.getInstance().getMessage2SOAPGeneratorForCurrentThread().generateSOAPMessage(message, pd); UDPServer.send(this, destAddr, destPort, buffer.getBuffer(), buffer.getContentLength()); int repeatCount = SOAPoverUDPClient.MULTICAST_UNICAST_UDP_REPEAT; if (repeatCount <= 0) { return; } int delay = Math.nextInt(SOAPoverUDPClient.UDP_MIN_DELAY, SOAPoverUDPClient.UDP_MAX_DELAY); while (true) { try { Thread.sleep(delay); } catch (InterruptedException e) { // ignore } if (monFac != null) { OutputStream o = new ByteArrayOutputStream(buffer.getContentLength()); o = new MonitoredOutputStream(o, pd); context = monFac.getNewMonitoringContextOut(pd); o.write(buffer.getBuffer(), 0, buffer.getContentLength()); o.flush(); o.close(); } UDPServer.send(this, destAddr, destPort, buffer.getBuffer(), buffer.getContentLength()); if (monFac != null) { monFac.send(pd, context, message); } if (--repeatCount == 0) break; delay *= 2; if (delay > SOAPoverUDPClient.UDP_UPPER_DELAY) { delay = SOAPoverUDPClient.UDP_UPPER_DELAY; } } } catch (IOException e) { Log.error("Unable to send SOAP-over-UDP response: " + e); Log.printStackTrace(e); if (monFac != null) { monFac.sendFault(pd, context, e); } } } } }