Connecting to NAV Web Services from Java


Prerequisites

Please read this post to get an explanation on how to modify the service tier to use NTLM authentication and for a brief explanation of the scenario I will implement in Java.

BTW. Basic knowledge about Java is required to understand the following post:-)

Version and download

Java does not natively have support for the SPNEGO authentication protocol, but it does have support for NTLM authentication, so you will have to change the Web Services listener to use that.

I downloaded the Java developer toolkit from http://www.java.com/en/download/manual.jsp and installed it under c:\sun – and made sure that c:\sun\SDK\bin is added to the path.

wsimport – import WSDL

To make Java able to see and use webservices I use wsimport to create proxy classes in Java. In a directory, I have created two empty folders (generated and source) and use the following command:

C:\java>wsimport -d generated -s source http://localhost:7047/DynamicsNAV/WS/SystemService

this will create a series of .class files under

C:\java\generated\schemas\dynamics\microsoft\nav\system

and a set of source files under

C:\java\source\schemas\dynamics\microsoft\nav\system

note, that the folder structure is the namespace of the web service.

javac – compile the program

Assuming that I create a test program in c:\java\test.java, the following command will compile the program:

c:\java>c:\sun\sdk\jdk\bin\javac -cp .;generated test.java

this creates a c:\java\test.class, which we can run.

java – run the program

The statement used to run the java class is:

c:\java>c:\sun\sdk\jdk\bin\java -cp .;generated test

enough about setup – lets code…

Authentication

By default, java supports Windows Authentication and if the class is running in context of a windows user, these credentials are automatically used to authenticate towards NAV Web Services.

If you want to use different credentials (connect as a different user) you will need to create a class derived from Authenticator and implement getPasswordAuthentication like:

static class MyAuthenticator extends Authenticator {
  public PasswordAuthentication getPasswordAuthentication() {
    return (new PasswordAuthentication("domain\user", new char[] {‘p’,’a’,’s’,’s’,’w’,’o’,’r’,’d’}));
  }
}

and then as the very first statement in the class

Authenticator.setDefault(new MyAuthenticator());

test.java

First of all, I have a number of imports. Not sure that they all are needed and then a main function body:

import java.net.*;
import java.util.*;
import java.io.*;
import javax.xml.namespace.QName;
import schemas.dynamics.microsoft.nav.system.*;
import schemas.dynamics.microsoft.page.customer.*;

public class test {
    public static void main(String[] args) {

        // main program code

    }
}

The main code is:

try {
 
String baseURL = "http://localhost:7047/DynamicsNAV/WS/";

The following code allows you to connect to NAV Web Services system service in Java and output the companies available on the service tier:

  URL systemServiceURL = new URL(baseURL + "SystemService");
  QName systemServiceQName = new QName("urn:microsoft-dynamics-schemas/nav/system/", "SystemService");
  SystemService systemService = new SystemService(systemServiceURL, systemServiceQName);
  SystemServicePort systemPort = systemService.getSystemServicePort();
  List<String> companies = systemPort.companies();
  System.out.println("Companies:");
  for(String company : companies) {
    System.out.println(company);
  }
  String cur = companies.get(0);

Now I have the company I want to use in cur and the way I create a URL to the Customer page is by doing:

  URL customerPageURL = new URL(baseURL+URLEncoder.encode(cur,"UTF-8").replace("+","%20")+"/Page/Customer");
  QName customerPageQName = new QName("urn:microsoft-dynamics-schemas/page/customer", "Customer_Service");

  System.out.println("\nURL of Customer page:" + customerPageURL.toString());

and then I can create a Service Client to the Customer Page:

  CustomerService customerService = new CustomerService(customerPageURL, customerPageQName);
  CustomerPort customerPort = customerService.getCustomerPort();

and using this, I read customer 10000 and output the name:

  Customer cust = customerPort.read("10000");
  System.out.println("\nName of Customer 10000:" + cust.getName());

Last, but not least – lets create a filter and read all customers in GB that has Location Code set to RED or BLUE:

  CustomerFilter filter1 = new CustomerFilter();
  filter1.setField(CustomerFields.fromValue("Location_Code"));
  filter1.setCriteria("RED|BLUE");

  CustomerFilter filter2 = new CustomerFilter();
  filter2.setField(CustomerFields.fromValue("Country_Region_Code"));
  filter2.setCriteria("GB");

  List<CustomerFilter> filters = new ArrayList<CustomerFilter>();
  filters.add(filter1);
  filters.add(filter2);

  System.out.println("\nCustomers in GB served by RED or BLUE warehouse:");
  CustomerList customers = customerPort.readMultiple(filters, null, 0);
  for (Customer c : customers.getCustomer()) {
    System.out.println(c.getName());
  }

  System.out.println("\nTHE END");

} catch(MalformedURLException e) {
} catch(UnsupportedEncodingException e) {
}

All of the above will output the following in a prompt (on my machine running NAV 2009SP1 W1)

image

I hope this is helpful.

Good luck

Freddy Kristiansen
PM Architect
Microsoft Dynamics NAV

Comments (16)

  1. OMG! says:

    I'm glad I stumbled upon this post…..I'll give this a shot on our system and see if I can get it to work, I think this is the thing that I was missing – you are a life saver and I'll name my first child after you if this works!

  2. Chris Lemper says:

    Hi,

    I was able to get his to work but using Apache CXF.  However, I cannot seem the get the Dynamics NAV server to honor my "Keep-Alive" client setting.  Do you know if it is possible to enable keep alive for the web services so that the client does not need to create and destroy HTTP connections?

    Thanks!

  3. Andrea says:

    Hi, Couldn't get pass the 401 – Authentication problem even if I'm on the same machine as the web service. I modified the CustomSettings.config as stipulated in the previous article.  Server returned HTTP response code: 401 for URL: http://localhost:7047/D… Any ideas?

    Thanks

  4. Hi, Is this possible on an Android 2.2 application??

    I've tried this tutorial, but not worked form me.

  5. Jai says:

    You did a great help! I have sucessfully integrated Navision with my Java application using Apache axis. However, I just have a query that whether the generated classes would differ from one instance of Navision to another. Since I have got to use the same code to connect with multiple installations of navision.

    Jai

  6. Arturs says:

    Freddy, will this work in Eclipse for Android ?

  7. Miguel says:

    Hi there! I tried your example but it's always the same error.: Error:

    com.sun.xml.internal.ws.wsdl.parser.InaccessibleWSDLException: 2 counts of InaccessibleWSDLException. java.io.IOException: Got Server returned HTTP response code: 401 for URL: http://localhost:7053/MicrosoftDynamicsNavWS/WS/SystemService while opening stream from http://localhost:7053/MicrosoftDynamicsNavWS/WS/SystemService java.io.IOException: Got Server returned HTTP response code: 401 for URL: http://localhost:7053/MicrosoftDynamicsNavWS/WS/SystemService?wsdl while opening stream from http://localhost:7053/MicrosoftDynamicsNavWS/WS/SystemService?wsdl

    Please, how can i fix it? Thank you.

  8. Abram says:

    When I run the wsimport I am getting a 401 Unauthorized error.  The error suggests creating authorization file, which I have done and still no luck.  I can browse to the WSDL file, but cannot get wsimport to work.  One thing to note is that I am running the wsimport from a remote Linux computer with JDK 1.7.0_5.

    Any thoughts?

  9. Rakesh Ranjan says:

    Hi I am trying to connect navision Web services using android,but unfortunate i am unable to do this , can any one help me out of this , Same code in java is working great in JAVA but when i tried to move the code to android and run the application, Error occoured Stop Unexpected.

    package com.example.testwebservices;

    code is as follow :

    import java.net.URL;

    //import javax.xml.namespace.QName;

    import android.os.Bundle;

    import android.app.Activity;

    //import android.view.Menu;

    import java.net.*;

    //import java.util.*;

    //import java.io.*;

    import javax.xml.namespace.QName;

    import schemas.dynamics.microsoft.codeunit.navisionws.NavisionWS;

    import schemas.dynamics.microsoft.codeunit.navisionws.NavisionWSPort;

    //import schemas.dynamics.microsoft.nav.system.*;

    //import schemas.dynamics.microsoft.codeunit.Navisionws.*;

    public class MainActivity extends Activity {

       @Override

       public void onCreate(Bundle savedInstanceState) {

           super.onCreate(savedInstanceState);

           setContentView(R.layout.activity_main);

           try{

            /*

            String baseURL = "http://localhost:7047/DynamicsNAV/WS/Codeunit/NavisionWS&quot;;

            URL systemServiceURL = new URL(baseURL);

            QName systemServiceQName = new QName("urn:microsoft-dynamics-schemas/nav/system/NavisionWS");

            NavisionWS ns = new NavisionWS(systemServiceURL,systemServiceQName);

            NavisionWSPort NsPort = ns.getNavisionWSPort();

            String Res = NsPort.getCompanyName();

            System.out.print(Res);

            */

            String baseURL = "10.2.2.0/…/";

            //The following code allows you to connect to NAV Web Services system service in Java and output the companies available on the service tier:

      URL systemServiceURL = new URL(baseURL + "Codeunit/NavisionWS");

    QName systemServiceQName = new QName("urn:microsoft-dynamics-schemas/codeunit/NavisionWS", "NavisionWS");

    NavisionWS ns = new NavisionWS(systemServiceURL,systemServiceQName);

            NavisionWSPort NsPort = ns.getNavisionWSPort();

            String Res = NsPort.getCompanyName();

            System.out.print(Res);

           } catch (MalformedURLException e)

    {}

    }

    }

    /*

    public class CallNavWSActivity extends Activity {

    /** Called when the activity is first created. */

    /*@Override

    public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    try {

    String baseURL = "10.0.2.2/…/";

    URL systemServiceURL = new URL(baseURL + "NavisionWS");

    //URL systemServiceURL = new URL()

    QName systemServiceQName = new QName("urn:microsoft-dynamics-schemas/codeunit/NavisionWS","NavisionWS");

    NavisionWS ns = new NavisionWS(systemServiceURL, systemServiceQName);

    NavisionWSPort port = ns.getNavisionWSPort();

    String res = port.getCompanyName();

    System.out.print(res);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    }*/

  10. Ravi Thakkar says:

    Hello Freddy,

    First of all, Thank you very much for sharing this article.

    It helped us a lot.

    By the guidance of it, I was able to read and delete the records from Android.

    But, unfortunately, I could not do it for Insert and Update the records.

    For Update and Insert, we need to transfer a complete Object as a parameter from Android to NAV.

    I am unable to get the format of soap object to be inserted as a parameter while using the Update and Insert function.

    Could you please suggest?

    I would be thankful to you.

    Again I appreciate your articles.

    Regards,

    Ravi Thakkar

  11. Elisa says:

    Hi all, where can I fine jar to use

    "import schemas.dynamics.microsoft.nav.system."?

    Thanks a lot

    Regards

  12. Mark says:

    You're the man!  I was able to use it to modify the code I had such that it worked.

    BTW, here's a slightly shorter example if you want to connect to a known company:  

    try {

               CustomerService service = new CustomerService(new URL("http://<server&gt;:<port>/<Nav Server Name>/WS/<percent encoded company name>/Page/Customer"));

               CustomerPort port = service.getCustomerPort();

               Customer cust = port.read("<some customer number>");

               System.out.println(cust.getName());

           } catch (MalformedURLException ex) {

               Logger.getLogger(NavCustExample.class.getName()).log(Level.SEVERE, null, ex);

           }

  13. David says:

    Hello ,

    Same problem as Andrea. Can anyone help please ?

    Couldn't get pass the 401 – Authentication problem even if I'm on the same machine as the web service. I modified the CustomSettings.config as stipulated in the previous article.  Server returned HTTP response code: 401 for URL: http://localhost:7047/D

    Thanks.

  14. Authenticacion problem says:

    Anybody knows how works authentication on Nav?, In this example, I can't change the user, java use same  windows user, no matter what put in Java, always take on windows.

  15. Scott says:

    Can you provide an example for using a Codeunit instead of a Page web service? I am trying to use the Item Jnl.-Post Line Codeunit

  16. Richard says:

    Hello,

    Same problem as Andrea. Can anyone help please ?

    Couldn't get pass the 401 – Authentication problem even if I'm on the same machine as the web service. I modified the CustomSettings.config as stipulated in the previous article.  Server returned HTTP response code: 401 for URL: http://localhost:7047/D

    Thanks.