Build Soap web service client using wsdl documents in Eclipse

自闭症网瘾萝莉.ら 提交于 2019-12-21 02:52:00

问题


I need to create web service client in Java using Eclipse the consumes the onvif wsdl.

I spent several hours without finding a how to do that, this the first time I am using soap, my experience was in REST.

I tried many tutorials like this to create web service client, but when I am trying to choose the wsdl file from my local disk, eclipse shows the an error Could not retrieve the WSDL file ..., the link structure I used for the file was file:/C:/ONVIF/media.wsdl.

I need to use any Java framework that support WS-Notification to implement my client.

Can you please tell me how to implement client web service that consumes the WSDL files.
Do I need web server to implement soap web service client?
If yes, why?


回答1:


Here is a complete code and guide on how to consume one of ONVIF's wsdl files (devicemgmt.wsdl) and how to use it to connect to a device:

package test;

import java.io.IOException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.ws.Binding;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Holder;
import javax.xml.ws.Service;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import org.onvif.ver10.device.wsdl.Device;
import org.onvif.ver10.schema.DateTime;
import org.onvif.ver10.schema.SystemDateTime;
import org.onvif.ver10.schema.Time;

import com.sun.org.apache.xml.internal.security.utils.Base64;

public class OnvifTest {

    private static TimeZone utc = TimeZone.getTimeZone("UTC");
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

    static {
        sdf.setTimeZone(utc);
    }

    private static long serverTime = 0;
    private static long clientTime = 0;


    private static final String ip = "...";
    private static final String user = "...";
    private static final String pass = "...";
    // Some cameras (e.g. Axis) require that you set the user/pass on the ONVIF section in it's web interface
    // If the camera is reset to factory defaults and was never accessed from the web, then
    // either no user/pass is needed or the default user/pass can be used

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws IOException {

        // The altered wsdl file
        URL url = new URL("file://"+System.getProperty("user.home")+"/onvif/devicemgmt.wsdl");
        // This file was downloaded from the onvif website and added a mock service in order to make it complete:
        //  <wsdl:service name="DeviceService">  
        //      <wsdl:port name="DevicePort" binding="tds:DeviceBinding">  
        //          <soap:address location="http://localhost/onvif/device_service"/>  
        //      </wsdl:port>  
        //  </wsdl:service>
        // The altered file was then used to generate java classes using $JAVA_HOME/bin/wsimport -Xnocompile -extension devicemgmt.wsdl 

        QName qname = new QName("http://www.onvif.org/ver10/device/wsdl", "DeviceService");
        Service service = Service.create(url, qname);
        Device device = service.getPort(Device.class);

        BindingProvider bindingProvider = (BindingProvider)device;

        // Add a security handler for the credentials
        final Binding binding = bindingProvider.getBinding();
        List<Handler> handlerList = binding.getHandlerChain();
        if (handlerList == null)
            handlerList = new ArrayList<Handler>();

        handlerList.add(new SecurityHandler());
        binding.setHandlerChain(handlerList);

        // Set the actual web services address instead of the mock service
        Map<String, Object> requestContext = bindingProvider.getRequestContext();
        requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://"+ip+"/onvif/device_service"); 

        // Read the time from the server
        SystemDateTime systemDateAndTime = device.getSystemDateAndTime();
        // Mark the local time (no need for an actual clock, the monotone counter will do just fine)
        clientTime = System.nanoTime()/1000000;

        // Generate the server time in msec since epoch
        DateTime utcDateTime = systemDateAndTime.getUTCDateTime();
        org.onvif.ver10.schema.Date date = utcDateTime.getDate();
        Time time = utcDateTime.getTime();
        Calendar c = new GregorianCalendar(utc);
        c.set(date.getYear(), date.getMonth()-1, date.getDay(), time.getHour(), time.getMinute(), time.getSecond());
        System.out.println(sdf.format(c.getTime()));
        serverTime = c.getTimeInMillis();

        // Now try and read something interesting
        Holder<String> manufacturer = new Holder<String>();
        Holder<String> model = new Holder<String>();
        Holder<String> firmwareVersion = new Holder<String>();
        Holder<String> serialNumber = new Holder<String>();
        Holder<String> hardwareId = new Holder<String>();
        device.getDeviceInformation(manufacturer, model, firmwareVersion, serialNumber, hardwareId);
        System.out.println(manufacturer.value);
        System.out.println(model.value);
        System.out.println(firmwareVersion.value);
        System.out.println(serialNumber.value);
        System.out.println(hardwareId.value);
    }

    // Calcualte the password digest from a concatenation of the nonce, the creation time and the password itself
    private static String calculatePasswordDigest(byte[] nonceBytes, String created, String password) {
        String encoded = null;
        try {
            MessageDigest md = MessageDigest.getInstance( "SHA1" );
            md.reset();
            md.update( nonceBytes );
            md.update( created.getBytes() );
            md.update( password.getBytes() );
            byte[] encodedPassword = md.digest();
            encoded = Base64.encode(encodedPassword);
        } catch (NoSuchAlgorithmException ex) {
        }

        return encoded;
    }

    // Calculate what time is it right now on the server
    private static String localToGmtTimestamp() {
        return sdf.format(new Date(System.nanoTime()/1000000 - clientTime + serverTime));
    }

    // This handler will add the authentication parameters
    private static final class SecurityHandler implements SOAPHandler<SOAPMessageContext> {

        @Override
        public boolean handleMessage(final SOAPMessageContext msgCtx) {

            // Indicator telling us which direction this message is going in
            final Boolean outInd = (Boolean) msgCtx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

            // Handler must only add security headers to outbound messages
            if (outInd.booleanValue() && clientTime!=0 && user!=null && pass!=null) {
                try {
                    // Create the timestamp
                    String timestamp = localToGmtTimestamp();

                    // Generate a random nonce
                    byte[] nonceBytes = new byte[16]; 
                    for (int i=0 ; i<16 ; ++i)
                        nonceBytes[i] = (byte)(Math.random()*256-128);

                    // Digest
                    String dig=calculatePasswordDigest(nonceBytes, timestamp, pass);

                    // Create the xml
                    SOAPEnvelope envelope = msgCtx.getMessage().getSOAPPart().getEnvelope();
                    SOAPHeader header = envelope.getHeader();
                    if (header == null)
                        header = envelope.addHeader();

                    SOAPElement security =
                    header.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

                    SOAPElement usernameToken =
                    security.addChildElement("UsernameToken", "wsse");

                    SOAPElement username =
                    usernameToken.addChildElement("Username", "wsse");
                    username.addTextNode(user);

                    SOAPElement password =
                    usernameToken.addChildElement("Password", "wsse");
                    password.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest");
                    password.addTextNode(dig);

                    SOAPElement nonce =
                    usernameToken.addChildElement("Nonce", "wsse");
                    nonce.setAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
                    nonce.addTextNode(Base64.encode(nonceBytes));

                    SOAPElement created = usernameToken.addChildElement("Created", "wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
                    created.addTextNode(timestamp);

                } catch (final Exception e) {
                    e.printStackTrace();
                    return false;
                }
            }
            return true;
        }

        // Other required methods on interface need no guts

        @Override
        public boolean handleFault(SOAPMessageContext context) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public void close(MessageContext context) {
            // TODO Auto-generated method stub

        }

        @Override
        public Set<QName> getHeaders() {
            // TODO Auto-generated method stub
            return null;
        }
    }

}



回答2:


I would recommend using wsimport command to generate the web service client to consume the web services.

The command can be executed from cmd prompt,


wsimport -d D:\WS-Client -extension -keep -XadditionalHeaders http://path-to-your-webserbice-wsdl-file/sampleWSDL?wsdl

After execution of the above command all the generated .class files and .java (source) files will be placed inside D:\WS-Client folder with proper package structure as mentioned in the wsdl file.

just ignore the .class files and copy entire package folder and include it in your consumer project to use it.

It will be like, you have the deployed web services in your source code. Just call the methods from the service classes and ohhla :)




回答3:


The WSDL you were provided is invalid. Most likely due to the extensive documentation tags that were used in it. You can verify this by trying to load it in SoapUI. Your best bet is to contact the vendor to find out if they have a cleaner version of the WSDL they can provide you.




回答4:


first you want to deploy your web service project on any server means tomcat or other. after that use the running server WSDL file URL for create the client.



来源:https://stackoverflow.com/questions/8798419/build-soap-web-service-client-using-wsdl-documents-in-eclipse

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!