Java Web服务:用户定义的元数据

时间:2014-03-05 12:19:41

标签: java web-services jboss jax-ws

我在Jboss 4.2.3上有一个SOAP Web服务实现。我想为服务添加版本号检查。每当客户端拨打电话时,我都会传递客户端版本号。我将在服务器上编写一个拦截器来检查客户端版本号。如果它是具有不同版本号的客户端,我将不会处理该请求。

我想知道的是,除了在Web服务方法签名中添加版本号之外,是否有其他方法可以从客户端传递版本号?

一般情况下,如果我想将一些自定义的META-DATA从客户端传递给服务器,我该怎么做?

3 个答案:

答案 0 :(得分:1)

  

一般来说,如果我想从客户端传递一些自定义的META-DATA    服务器,我该怎么做?


这可以通过Jax-WS中的 SOAP Message Handlers 双方(客户端和服务器)来实现。

客户端:

可以通过SOAP Headers添加自定义元数据,例如版本号,UUID,签名信息。

1 ..编写VersionNumberHandler,如下所示。

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 Handler-Chain.xml中的这个类。

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

3.在客户端(Stub)中添加处理程序链。

@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(){

}

这里,我们添加了一个新的头元素“versionnumber”和mustunderstand = true,这意味着服务器/中介必须处理这个元素,否则Jax-WS-Runtime会将SOAP Fault异常抛给客户端。现在我们需要在服务器端编写一个Validator(SOAP Handler)来验证客户端传递的这个版本号。

服务器端:

1 ..编写一个VersionNumberValidator,如下所示。

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 ..在Handler-Chain-server.xml中输入此类。

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

3 ..发布网络服务。

现在,每个客户端请求都将具有“版本号= v1.0”,在服务器端,您将验证此值是否正确。如果不正确,将抛出SOAPFaultException。

答案 1 :(得分:0)

您可以将其添加到http-headers,但这意味着您的客户端需要执行此操作,这也意味着他们可以更改它并为您提供错误的数字,从而导致服务器出现问题。它只与发送的消息一样可靠。

无论哪种方式,这都不是限制访问Web服务的正确方法,您应该使用http基本身份验证,或者如果版本存在差异,那么您应该创建多个版本端点,以便客户端访问所需的版本。

另外,JBoss 4.2.3已经很老了,甚至可能都无法运行。见[1]

小家鼠

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

答案 2 :(得分:0)

尝试将带外元数据添加到Web服务是个坏主意。如果数据结构不兼容,只需为每个版本选择一个新URL。如果它们兼容,请将版本号放在请求中。

通过这种方式,您仍然可以支持与所有不同库的互操作,而不需要您的客户端为每个工具包找到新的环节。