Vieme, že vypublikovať webservice cez JAX-WS je jednoduché. Stačí zobrať 1 ks obslužnej triedy a vypublikovať ju v main()
:
package sk.upjs.ics.novotnyr.jaxws;
import javax.jws.WebMethod;
import javax.jws.WebService;
@WebService
public class HelloService {
@WebMethod
public String sayHello() {
return "Hello";
}
public static void main(String[] args) {
Endpoint endpoint = Endpoint.publish("http://localhost:10000/ws/hello", new HelloService());
}
}
Ako logovať správy na strane servera?
Máme dve možnosti: buď programovo alebo šperkovaním cez anotácie.
V oboch prípadoch budeme potrebovať vlastnú implementáciu SOAPHandlera
, teda triedy, ktorú vieme zavesiť na reťaz objektov spracujúcich správu.
Handler môže vyzerať napr. takto:
package sk.upjs.ics.novotnyr.jaxws.log;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class SOAPLoggingHandler implements SOAPHandler<SOAPMessageContext> {
private static final String DEFAULT_CHARSET = "UTF-8";
private String messageCharset = DEFAULT_CHARSET;
public static Logger LOGGER_OUTBOUND = Logger.getLogger(SOAPLoggingHandler.class.getName() + ".outbound");
public static Logger LOGGER_INBOUND = Logger.getLogger(SOAPLoggingHandler.class.getName() + ".inbound");
public static Logger LOGGER = Logger.getLogger(SOAPLoggingHandler.class.getName());
public Set<QName> getHeaders() {
return null;
}
public boolean handleMessage(SOAPMessageContext smc) {
logToSystemOut(smc);
return true;
}
public boolean handleFault(SOAPMessageContext smc) {
logToSystemOut(smc);
return true;
}
public void close(MessageContext messageContext) {
// nothing to clean up
}
private void logToSystemOut(SOAPMessageContext soapMessageCtx) {
try {
SOAPMessage message = soapMessageCtx.getMessage();
Boolean outboundProperty = (Boolean) soapMessageCtx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
LOGGER_OUTBOUND.info(toString(message));
} else {
LOGGER_INBOUND.info(toString(message));
}
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "I/O exception while logging the message.", e);
} catch (SOAPException e) {
LOGGER.log(Level.SEVERE, "SOAP exception while logging the message.", e);
}
}
private String toString(SOAPMessage message) throws IOException, SOAPException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
message.writeTo(byteOut);
return byteOut.toString(messageCharset);
}
public void setMessageCharset(String messageCharset) {
this.messageCharset = messageCharset;
}
public String getMessageCharset() {
return messageCharset;
}
}
Programové nastavenie logovania
Použitie je nasledovné: vytvoríme endpoint cez Endpoint#create()
, získanú inštanciu nakonfigurujeme a následne endpoint vypublikujeme:
Endpoint endpoint = Endpoint.create(new HelloService());
@SuppressWarnings("rawtypes")
List<Handler> handlerChain = endpoint.getBinding().getHandlerChain();
handlerChain.add(new SOAPLoggingHandler());
endpoint.getBinding().setHandlerChain(handlerChain);
endpoint.publish("http://localhost:10000/ws/hello");
Pozor na viacero zádrheľov!
Endpoint musíte vytvoriť, nakonfigurovať a vypublikovať!
Ak sa pokúsite nakonfigurovať inštanciu, ktorú vráti publish()
(áno, publish()
), nebudete úspešní. Publikovaný endpoint zjavne nemožno konfigurovať.
getHandlerChain()
vracia kópiu zoznamu!
Ak sa pokúsite pridať nový handler štýlom
endpoint.getBinding().getHandlerChain().add(new SOAPLoggingHandler());
nebude to fungovať. Metóda getHandlerChain()
totiž vracia kópiu zoznamu handlerov a ak doň pridáte nový prvok, endpoint zmenu neuvidí. Musíte to urobiť naookolo. Toto správanie explicitne popisuje dokumentácia, ale kto ju číta? ;-)
Nastavenie v XML
Ak máte HelloService
v balíčku sk.upjs.ics.novotnyr.jaxws
, môžete ho anotovať pomocou @HandlerChain
, kde uvediete názov súboru s popisom handlerov, ktoré sa priradia k tomuto endpointu.
@HandlerChain(file = "handlers.xml")
public class HelloService {
...
}
Do adresára s balíčkom sk.upjs.ics.novotnyr.jaxws
vložte handlers.xml
. Naozaj, tento súbor sa musí nachádzať pri spustení v rovnakom adresári ako HelloService.class
.
Obsah toť:
<?xml version="1.0" encoding="UTF-8"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
<handler-chain>
<handler>
<handler-name>log</handler-name>
<handler-class>sk.upjs.ics.novotnyr.jaxws.log.SOAPLoggingHandler</handler-class>
</handler>
</handler-chain>
</handler-chains>
Následne nemusíte konfigurovať endpoint v kóde, stačí ho publish()
núť a je to.