SugarSoap In java

SugarCRM provides Web Services API via the NuSOAP PHP implementation of the SOAP protocol. The SugarSoap API are built using the NuSOAP library and included in the Sugar Community Edition, Sugar Professional Edition and Sugar Enterprise Edition.
This guide leads you through the steps of creating sugarsoap clients stubs In java using Xfire .Codehaus XFire is a next-generation java SOAP framework. We will use it to consume the SugarSoap webservice in Java clients.

1- Locate The SugarSoap WSDL file:

This guide suppose you already have a working sugarcrm installation. If you don’t have one, download and install the free Sugar Community Edition . Refer to section Installing and Upgrading Sugar to guide you through the installation procedure.
For example, In my Linux machine I unpacked the Sugar Community Edition 5.5.0 bundle into my apache server web apps directory ‘/srv/www/htdocs/SugarCE-Full-5.5.0’ . After completing the installation, I access my local sugarcrm application by browsing to URL : http://localhost/SugarCE-Full-5.5.0/. This URL could vary depending on your own choices of server, host and port. For the rest of this guide I’ll use the reference $sugar_base_url to refer to the base URL you use to access your sugarcrm installation (for me, $sugar_base_url =http://localhost/SugarCE-Full-5.5.0/ ).

The SugarSoap WSDL (Web Services Description Language) is located at:
$sugar_base_url/soap.php?wsdl

in my case it’s located at http://localhost/SugarCE-Full-5.5.0/soap.php?wsdl . Mark well this sugarsoap WSDL URL because we will need it for generating the sugarsoap clients stubs.

2- Getting XFire and other libraries:

To use Xfire we need the necessary library files. Go to xfire web site download page and download the file xfire-distribution-x.x.x.zip ( replace ‘x.x.x’ by the version number .the latest xfire version is xfire-distribution-1.2.6.zip at the time of writing this guide).
unzip it in a local folder. add the xfire-all-1.2.6.jar file from the distribution and its lib directory into your project classpath.
If you are using eclipse IDE, you can get the Xfire Eclipse plugin which is a nice and easy to use tool for generating Xfire clients stubs from WSDL files.

3.Generating SugarSoap Clients stubs with Xfire:

Ant is a useful and flexible tool to automate the building of your java project. Most java IDE generates a build.xml file for you , so why not use Ant to generate our sugarsoap clients stubs?

Edit your build .xml file and add the following ant target at the end of the file :

<target name="wsGen">

        <!-- Replace ${basedir} by your project base directory  and ${sugar_base_url} by your sugar URL (ex : http://localhost/SugarCE-Full-5.5.0-->

        <property name="dependencyfinder.home" value="${basedir}"/>
        <path id="dependencyfinder">
            <pathelement location="${basedir}/lib"/>
            <fileset dir="${basedir}/lib">
                <include name="**/*.jar"/>
            </fileset>
        </path>

        <taskdef name="wsgen">
                 classname="org.codehaus.xfire.gen.WsGenTask"
                 classpathref="dependencyfinder"/>

        <wsgen overwrite="true"
               package="com.sun.star.addon.sugarcrm.sugarsoap"
               outputDirectory="${basedir}/src"
               wsdl="${sugar_base_url}/soap.php?wsdl"
               />
    </target>

${basedir}/lib points to the directory where you copied all your xfire distribution jar files and xfire distribution lib folder jars.

From your command line change to your build.xml file directory and run command :

$ ant wsGen

this will generate the SugarSoap clients stubs under src directory in java package : com.sun.star.addon.sugarcrm.sugarsoap
package com.sun.star.addon.sugarcrm.sugarsoap holds the main sugarsoap java stubs classes mainly the class Sugarsoap

4.Writing a SugarSoap Java client:

Now it’s time to write a simple java client to test our sugarsoap service. Below is a java code snippet that demonstrates how to login to your sugarcrm web application :

import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.rpc.ServiceException;
import com.sun.star.addon.sugarcrm.sugarsoap.Sugarsoap;
import com.sun.star.addon.sugarcrm.sugarsoap.SugarsoapLocator;
import com.sun.star.addon.sugarcrm.sugarsoap.SugarsoapPortType;

public class SugarTest {

	Sugarsoap service = new SugarsoapLocator();
	SugarsoapPortType soap = null;
	public static void main(String[] arg) {

		try {
			soap = service.getsugarsoapPort(new URL("http://localhost/SugarCE-Full-5.5.0/"));
			String session = soap.login("your username", "your password",
					" sugarsoap test");
			if (session == null)
				System.err
						.println("there was an error connecting to sugarcrm service");
			else
				System.out
						.println("login to sugar service successfull. sessionId="
								+ session);

		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			_logger.error(e);
			return;

		} catch (ServiceException e) {
			// TODO Auto-generated catch block
			_logger.error(e);
			return;

		}

	}

	/**
	 * Logs the user into the Sugar application.
	 *
	 * @param username
	 * @param password
	 * @param application
	 * @return sugar session id
	 */
	String login(String username, String password, String application) {

		Set_entry_result loginRes = null;
		String session = null;

		try {

			_logger.info("connecting to " + this.sugarURL + " as " + username);
			User_auth user_auth = new User_auth(username,
					MD5.getHashString(password), "1");
			loginRes = this.soap.login(user_auth, application);

			if (loginRes == null) {
				// null result means something wrong went with authentication
				return null;
			}
			session = loginRes.getId();
			String userid = this.soap.get_user_id(session.getId());
			boolean error = (!loginRes.getError().getNumber().equals("0"));

			if (error) {

				if (userid == "-1") {
					String text = "Error connecting to "
							+ this.sugarURL
							+ ": Connection is available, but SOAP is not responsive due to PHP configuration.";
					_logger.error("Error initializing connection:" + text);

					return null;

				}

				_logger.error("sugar login error :"
						+ loginRes.getError().getNumber() + " "
						+ loginRes.getError().getName() + " "
						+ loginRes.getError().getDescription());
				return null;

			} else {
				// sugar login successful
				_logger.info("login to sugar application successful");

			}

		} catch (Exception e) {

			// Caught an unexpected exception!
			_logger.error(e.getMessage(), e);
			return null;

		}
		return session;
	}

}

this snippet simply create a service instance and use it to create a soap Object instance. soap Object is the entry class for all sugarsoap methods.
The login() method snippet describe how to connect to your sugarcrm instance and returns the sugar session id if login is successfull.Note that you need to encode your sugar password using the MD5 algorithm.

5.Conclusion:

Once you complete the previous steps in setting up sugarsoap java stubs clients with xfire, you can start exploring and using the power of the sugarcrm services by calling the various sugarsoap API methods .
xfire is not the only java webservice library to generate sugarsoap client. you can also use other java webservice tools like axis and CXF and others. in a comming post I’ll describe a simple method to generate sugarsoap client using eclipse IDE and axis2.
The supported calls in the official sugarsoap API are listed and described in this section of the Sugar Developer Guide: Web Services

Advertisements

22 comments on “SugarSoap In java

  1. useful tips says:

    At last, I found this post again. You have few useful tips for my school project. This time, I won’t forget to bookmark it. 🙂

  2. it’s good to see this information in your post, i was looking the same but there was not any proper resource, thanx now i have the link which i was looking for my research.

    UK Dissertation Writing

  3. juri says:

    hi, thanks for this.

    while running ant task I get

    An imported schema was announced to have the namespace http://schemas.xmlsoap.org/wsdl/, but has the namespace http://schemas.xmlsoap.org/soap/encoding/

    wsdl header is:

    both namespaces are there, how do I solve this, can you explain me?

    thanks

  4. juri says:

    sorry header is:

    definitions xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/” xmlns:tns=”http://www.sugarcrm.com/sugarcrm” xmlns:soap=”http://schemas.xmlsoap.org/wsdl/soap/” xmlns:wsdl=”http://schemas.xmlsoap.org/wsdl/” xmlns=”http://schemas.xmlsoap.org/wsdl/” targetNamespace=”http://www.sugarcrm.com/sugarcrm”

  5. juri says:

    and import declarations are these, is the second one correct?

    xsd:import namespace=”http://schemas.xmlsoap.org/soap/encoding/” schemaLocation=”http://schemas.xmlsoap.org/soap/encoding/”/

    xsd:import namespace=”http://schemas.xmlsoap.org/wsdl/” schemaLocation=”http://schemas.xmlsoap.org/soap/encoding/”/

  6. juri says:

    found the problem, its the shcemaLocation value in the second import

  7. juri says:

    Hi, can you have a look?

    If I call webservice this way:

    GetEntryListResultVersion2 result = port.get_entry_list(val.getId(), “Accounts”, “Accounts.name = Accounts.name”, “name”, 0, null, null, 100, 0);

    I get a list but the only property I see in the object is the id. (id column is set)

    If I try to set the LinkNameToFieldsArray to get all the columns I want to specify:

    //get all Accounts
    String array[] = {“name, industry”};
    selectFields = new SelectFields();
    selectFields.getAny().add(array);

    LinkNameToFieldsArray lnfa = new LinkNameToFieldsArray();
    lnfa.setName(“accounts”);
    lnfa.setValue(selectFields);

    GetEntryListResultVersion2 result = port.get_entry_list(val.getId(), “Accounts”, “Accounts.name = Accounts.name”, “name”, 0, null, lnfa, 100, 0);

    Exception in thread “main” org.codehaus.xfire.XFireRuntimeException: Could not invoke service.. Nested exception is org.codehaus.xfire.fault.XFireFault: Fault: java.lang.NullPointerException
    org.codehaus.xfire.fault.XFireFault: Fault: java.lang.NullPointerException
    at org.codehaus.xfire.fault.XFireFault.createFault(XFireFault.java:89)
    at org.codehaus.xfire.client.Invocation.invoke(Invocation.java:83)
    at org.codehaus.xfire.client.Invocation.invoke(Invocation.java:114)
    at org.codehaus.xfire.client.Client.invoke(Client.java:336)
    at org.codehaus.xfire.client.XFireProxy.handleRequest(XFireProxy.java:77)
    at org.codehaus.xfire.client.XFireProxy.invoke(XFireProxy.java:57)
    at $Proxy12.get_entry_list(Unknown Source)
    at com.starmountsystems.services.licenseManagement.sugar.SugarReader.main(SugarReader.java:62)
    Caused by: java.lang.NullPointerException
    at com.sun.xml.bind.v2.runtime.property.ArrayReferenceNodeProperty.serializeListBody(ArrayReferenceNodeProperty.java:73)
    at com.sun.xml.bind.v2.runtime.property.ArrayERProperty.serializeBody(ArrayERProperty.java:101)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:293)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:290)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:619)
    at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:114)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:293)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:619)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:93)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:127)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeBody(ElementBeanInfoImpl.java:244)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:251)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:33)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:461)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:292)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:148)
    at org.codehaus.xfire.jaxb2.JaxbType.writeObject(JaxbType.java:261)
    at org.codehaus.xfire.aegis.AegisBindingProvider.writeParameter(AegisBindingProvider.java:229)
    at org.codehaus.xfire.service.binding.AbstractBinding.writeParameter(AbstractBinding.java:273)
    at org.codehaus.xfire.service.binding.WrappedBinding.writeMessage(WrappedBinding.java:90)
    at org.codehaus.xfire.soap.SoapSerializer.writeMessage(SoapSerializer.java:80)
    at org.codehaus.xfire.transport.http.HttpChannel.writeWithoutAttachments(HttpChannel.java:56)
    at org.codehaus.xfire.transport.http.CommonsHttpMessageSender.getByteArrayRequestEntity(CommonsHttpMessageSender.java:422)
    at org.codehaus.xfire.transport.http.CommonsHttpMessageSender.send(CommonsHttpMessageSender.java:360)
    at org.codehaus.xfire.transport.http.HttpChannel.sendViaClient(HttpChannel.java:123)
    at org.codehaus.xfire.transport.http.HttpChannel.send(HttpChannel.java:48)
    at org.codehaus.xfire.handler.OutMessageSender.invoke(OutMessageSender.java:26)
    at org.codehaus.xfire.handler.HandlerPipeline.invoke(HandlerPipeline.java:131)
    at org.codehaus.xfire.client.Invocation.invoke(Invocation.java:79)
    … 6 more

    Do you know what is my problem here? thanks

  8. othmanelmoulat says:

    >GetEntryListResultVersion2 result = port.get_entry_list(val.getId(), >”Accounts”, “Accounts.name = Accounts.name”, “name”, 0, null, lnfa, 100, 0);

    you should pass Object selectFields not lnfa .so the call should be something like:

    GetEntryListResultVersion2 result = port.get_entry_list(val.getId(), “Accounts”, “Accounts.name = Accounts.name”, “name”, 0, null, selectFields, 100, 0);
    see the signatuture of method get_entry_list() here:
    http://developers.sugarcrm.com/docs/ENT/6.0/-docs-Developer_Guides-Sugar_Developer_Guide_6.0-Chapter%202%20Application%20Framework.html#9000507

  9. juri says:

    Hi, thanks

    I think you are wrong, parameters 6 & 7 are SelectFields (optional) and LinkNameToFieldsArray in that order.
    In fact I think I was wrong too. In particular the way I filled selectFields. Rather than adding an array I should add a string object as far as I can see.

    selectFields = new SelectFields();
    selectFields.getAny().add(“name”);
    selectFields.getAny().add(“industry”);

    LinkNameToFieldsArray lnfa = new LinkNameToFieldsArray();
    lnfa.setName(“My accounts”);
    lnfa.setValue(selectFields);

    GetEntryListResultVersion2 result = port.get_entry_list(val.getId(), “Accounts”, “Accounts.name = ‘Pullman Cart Company'”, “name”, 0, selectFields, lnfa, 100, 0);

    And now I get:

    Exception in thread “main” org.codehaus.xfire.XFireRuntimeException: Could not invoke service.. Nested exception is org.codehaus.xfire.fault.XFireFault: Could not marshall type.
    org.codehaus.xfire.fault.XFireFault: Could not marshall type.
    at org.codehaus.xfire.jaxb2.JaxbType.writeObject(JaxbType.java:266)
    at org.codehaus.xfire.aegis.AegisBindingProvider.writeParameter(AegisBindingProvider.java:229)
    at org.codehaus.xfire.service.binding.AbstractBinding.writeParameter(AbstractBinding.java:273)
    at org.codehaus.xfire.service.binding.WrappedBinding.writeMessage(WrappedBinding.java:90)
    at org.codehaus.xfire.soap.SoapSerializer.writeMessage(SoapSerializer.java:80)
    at org.codehaus.xfire.transport.http.HttpChannel.writeWithoutAttachments(HttpChannel.java:56)
    at org.codehaus.xfire.transport.http.CommonsHttpMessageSender.getByteArrayRequestEntity(CommonsHttpMessageSender.java:422)
    at org.codehaus.xfire.transport.http.CommonsHttpMessageSender.send(CommonsHttpMessageSender.java:360)
    at org.codehaus.xfire.transport.http.HttpChannel.sendViaClient(HttpChannel.java:123)
    at org.codehaus.xfire.transport.http.HttpChannel.send(HttpChannel.java:48)
    at org.codehaus.xfire.handler.OutMessageSender.invoke(OutMessageSender.java:26)
    at org.codehaus.xfire.handler.HandlerPipeline.invoke(HandlerPipeline.java:131)
    at org.codehaus.xfire.client.Invocation.invoke(Invocation.java:79)
    at org.codehaus.xfire.client.Invocation.invoke(Invocation.java:114)
    at org.codehaus.xfire.client.Client.invoke(Client.java:336)
    at org.codehaus.xfire.client.XFireProxy.handleRequest(XFireProxy.java:77)
    at org.codehaus.xfire.client.XFireProxy.invoke(XFireProxy.java:57)
    at $Proxy12.get_entry_list(Unknown Source)
    at com.starmountsystems.services.licenseManagement.sugar.SugarReader.main(SugarReader.java:64)
    Caused by: javax.xml.bind.MarshalException
    – with linked exception:
    [com.sun.istack.SAXException2: unable to marshal type “java.lang.String” as an element because it is missing an @XmlRootElement annotation]
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:295)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:148)
    at org.codehaus.xfire.jaxb2.JaxbType.writeObject(JaxbType.java:261)
    … 18 more
    Caused by: com.sun.istack.SAXException2: unable to marshal type “java.lang.String” as an element because it is missing an @XmlRootElement annotation
    at com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:225)
    at com.sun.xml.bind.v2.runtime.LeafBeanInfoImpl.serializeRoot(LeafBeanInfoImpl.java:101)
    at com.sun.xml.bind.v2.runtime.property.ArrayReferenceNodeProperty.serializeListBody(ArrayReferenceNodeProperty.java:78)
    at com.sun.xml.bind.v2.runtime.property.ArrayERProperty.serializeBody(ArrayERProperty.java:101)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:293)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:290)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:619)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:93)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:127)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeBody(ElementBeanInfoImpl.java:244)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:251)
    at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:33)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:461)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:292)
    … 20 more

    hahha!

  10. othmanelmoulat says:

    Hi,
    how did you generated the webservice client stub classes? did you used xfire from codhause? like described in this post?
    in fact when i generated my client sugasoap classes i didn’t got the GetEnteryListResultVersion2 and the SelectField class ect..probably those are not the right sugarsoap client classes to use . version2 classes should be avaoided.
    I’m maybe made a mistake for the wsdl to use to generate sugarsoap client classes. try using the following wsdl :
    http:///soap.php?wsdl (replace address between brackets with your actual sugarcrm adress)
    and you can use any java webservice lib you want like axis ,xfire or CXF to generate sugarsoap client classes from above wsdl.

    sorry for giving the wrong wsdl in article above!. I’ll update article with correct wsdl. as i said don’t use wsdl and soap for version2 as those won’t work correctly.

  11. othmanelmoulat says:

    juri,
    i have updated article with modifications. this new code should work well for you . i’m using it currently in my java sugarsoap project and it works well. use “/soap.php?wsdl” not “/service/v2/soap.php?wsdl” as in first article description.

    hope this helps.
    regards

  12. juri says:

    Hey,

    Yes Sir, just the way you said. But I am using a different sugar version (6.0.2) that’s why I get different stubs. The methods are slightly different. The wsdl I used is the one sugar exposes.

    I think my best choice right now is to use a prior version like 5.5 (the one you mention)

    Thanks a lot

  13. othmanelmoulat says:

    i didn’t tried generating sugarsoap clients for version 6.0.2 . the version i’m aware of is 5.5.0 . mybe using latest versions soap methods will not work for a user using your java class if he has an older version like 5.
    this is a problem for sugarcrm developers team. if they keep changing the wsdl methods then no client sugarsoap willl be stable and in each new sugarsoap version new code won’t work for users with older sugarcrm versions.
    i’m not sure if sugar developers team are frequently changing sugar service in each new version. doing that is a bad idea as it will cause backward compatibility problems for developers writing sugarsoap clients.

  14. juri says:

    hey man,
    Sorry, this is my last post in this matter.
    But I am now trying to use 5.5 and I get the same error. So I am using the singnature you are using.

    and I get the same error

    Caused by: javax.xml.bind.MarshalException
    – with linked exception:
    [com.sun.istack.SAXException2: unable to marshal type “java.lang.String” as an element because it is missing an @XmlRootElement annotation]
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:295)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:148)
    at org.codehaus.xfire.jaxb2.JaxbType.writeObject(JaxbType.java:261)
    … 18 more

    Do you set the arrayType in selectFields?

    SelectFields select_fields = new SelectFields();
    select_fields.getAny().add(“name”);
    selectFields.setArrayType(“java.lang.String”);

    In a word, how do you set selectFields? Or my problem is with XFire

    thanks man

  15. othmanelmoulat says:

    I have no Idea what’s the SelectField class is. you should generate sugarsaop client with version 5.5 not 6. if you generate client with v 5.5 you will not get this SelectField class.

  16. juri says:

    Just an update. I switched to axis 1.4 and sugar 5.5 and got all working good. I don’t know were I went wrong with xfire. but nevertheless, thanks a lot

  17. othmanelmoulat says:

    yes using axis is better. me too i use axis and it is working right. I’ll update the post to include axis generation method beside xfire.
    thanks

  18. Hi Othman,
    this is a good post over SugarCRM SOAP API. On my blog I have published several articles on this topic. I recently released on Maven a SOAP library for SugarCRM.

    Bye,
    Antonio.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s