简体   繁体   中英

Java web service : User defined meta-data

I have a SOAP web service implementation on Jboss 4.2.3. I want to add a version number check for the service. Whenever a client makes a call, I will pass the client version number. I will write an interceptor at the server that would check the client version number. If it is a client with a different version number, I would not process the request.

What I want to know is if there is a way to pass the version number from the client in some context parameter other than adding it in the web service method signature?

In general, if I want to pass some custom META-DATA from client to server, how do I do it ?

In general, if I want to pass some custom META-DATA from client to server, how do I do it ?


This can be achieved through SOAP Message Handlers both side (Client and Server ) in Jax-WS .

Client Side:

The custom-meta-data , like version number, UUID , Signature information can be added via SOAP Headers .

1..Write a VersionNumberHandler as shown below.

public class VersionNumberHandler implements SOAPHandler<SOAPMessageContext> {
private static final String LoggerName = "ClientSideLogger";
private Logger logger;
private final boolean log_p = true; // set to false to turn off

public VersionNumberHandler() {
    logger = Logger.getLogger(LoggerName);
}

public boolean handleMessage(SOAPMessageContext ctx) {
    if (log_p)
        logger.info("handleMessage");

    // Is this an outbound message, i.e., a request?
    Boolean request_p = (Boolean) ctx
            .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

    // Manipulate the SOAP only if it's a request
    if (request_p) {
        // Get the Version Number from some property file ,
        // to place in the message header.
        String versionNumber = "v1.0";

        try {
            SOAPMessage msg = ctx.getMessage();
            SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
            SOAPHeader hdr = env.getHeader();
            // Ensure that the SOAP message has a header.
            if (hdr == null)
                hdr = env.addHeader();

            QName qname = new QName("http://ticket.example.com/",
                    "versionnumber");
            SOAPHeaderElement helem = hdr.addHeaderElement(qname);

            // In SOAP 1.2, setting the actor is equivalent to
            // setting the role.
            helem.setActor(SOAPConstants.URI_SOAP_ACTOR_NEXT);
            helem.setMustUnderstand(true);
            helem.addTextNode(versionNumber);
            msg.saveChanges();

            // For tracking, write to standard output.
            msg.writeTo(System.out);
        } catch (SOAPException e) {
            System.err.println(e);
        } catch (IOException e) {
            System.err.println(e);
        }
    }
    return true; // continue down the chain
}

public boolean handleFault(SOAPMessageContext ctx) {
    if (log_p)
        logger.info("handleFault");
    try {
        ctx.getMessage().writeTo(System.out);
    } catch (SOAPException e) {
        System.err.println(e);
    } catch (IOException e) {
        System.err.println(e);
    }
    return true;
}

public Set<QName> getHeaders() {
    if (log_p)
        logger.info("getHeaders");
    return null;
}

public void close(MessageContext messageContext) {
    if (log_p)
        logger.info("close");
}

2..Mention this class in the Handler-Chain.xml.

<javaee:handler>
<javaee:handler-class>
com.example.client.handler.VersionNumberHandler
</javaee:handler-class>
</javaee:handler>

3..Add the handler-chain in the client (Stub) also.

@WebServiceClient(name = "TicketWSImplService", targetNamespace =    "http://ticket.example.com/", wsdlLocation = "http://localhost:8080/ticket?wsdl")
@HandlerChain(file = "handler-chain.xml")
public class TicketWSImplService extends Service {

@WebMethod
public void method(){

}

Here, we are adding a new header element "versionnumber" and mustunderstand=true, which means the server/intermediaries has to process this element, otherwise Jax-WS-Runtime will throw SOAP Fault exception to the client. Now we need to write a Validator(SOAP Handler) at the server side to validate this version number which is being passed by the clients.

Server Side:

1..Write a VersionNumberValidator as shown below.

public class VersionNumberValidator implements SOAPHandler<SOAPMessageContext> {
@SuppressWarnings("unused")
@Override
public boolean handleMessage(SOAPMessageContext ctx) {
    // Is this an inbound message, i.e., a request?
    Boolean response_p = (Boolean) ctx
            .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

    // Manipulate the SOAP only if it's incoming.
    if (!response_p) {
        try {
            SOAPMessage msg = ctx.getMessage();
            SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
            SOAPHeader hdr = env.getHeader();

            // Ensure that the SOAP message has a header.
            if (hdr == null) {
                generateSOAPFault(msg, "No message header.");
                return true;
            }

            Iterator mustUnderstandHeaders = msg.getSOAPHeader()
                    .examineMustUnderstandHeaderElements(
                            "http://schemas.xmlsoap.org/soap/actor/next");
            String value = null;
            while (mustUnderstandHeaders.hasNext()) {
                Node next = (Node) mustUnderstandHeaders.next();
                System.out.println("mustUnderstandHeaders name:"
                        + next.getValue());
                if (next.getNodeName().equalsIgnoreCase("versionnumber"))
                    value = next.getValue();
                if (value != null && !value.equalsIgnoreCase("v1.0")) {
                    generateSOAPFault(msg, "Version Number Mismatch");
                }
            }

            // For tracking, write to standard output.
            msg.writeTo(System.out);
        } catch (SOAPException e) {
            System.err.println(e);
        } catch (IOException e) {
            System.err.println(e);
        }
    }
    return true; // continue down the chain
}

@Override
public boolean handleFault(SOAPMessageContext ctx) {

    return true; // do continue down the chain
}

// For now, no-ops.
@Override
public Set<QName> getHeaders() {

    Set<QName> headers = new HashSet<QName>();
    QName qName = new QName("http://ticket.example.com/", "versionnumber");
    headers.add(qName);

    return headers;
}

@Override
public void close(MessageContext messageContext) {
}

private void generateSOAPFault(SOAPMessage msg, String reason) {
    try {
        SOAPBody body = msg.getSOAPBody();
        SOAPFault fault = body.addFault();
        QName fault_name = new QName(
                SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE, "UltimateReceiver");
        fault.setFaultCode(fault_name);
        fault.setFaultRole("http://ticket.example.com/versionNumber_validator");
        fault.addFaultReasonText(reason, Locale.US);
    } catch (SOAPException e) {
    }
}

2..Mention this class in the Handler-Chain-server.xml.

<javaee:handler>
<javaee:handler-class>
com.example.client.handler.VersionNumberValidator
</javaee:handler-class>
</javaee:handler>

3..Publish the webservices.

Now, the every client request will be having "version number =v1.0", At the server side , you will be validating this value is correct or not. If it is not correct, SOAPFaultException will be thrown.

You could add it to the http-headers but that would mean your client would need to do this which also means they can change it and give you wrong numbers causing issues on the server. It's only as reliable as the messages being sent in.

Either way, this isn't the right way to restrict access to your Web Service, you should use http basic authentication or if it's version differences then you should create multiple version endpoints giving clients access to the versions they need.

Also, JBoss 4.2.3 is so old it might not even work. See [1]

Mus

[1] https://community.jboss.org/message/534711

It's a bad idea to try to add out-of-band metadata to a web service. Just pick a new URL for each version if the data structures are incompatible. If they are compatible, put the version number inside the request.

This way you can still support interoperation with all different libraries and not require your clients to find a new hoop to jump through for each toolkit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM