Welcome to Lasius - a Java utility framework for SFDC.
Please be aware we will be phasing out much of the present functionality found in version 3.x.y. Subsequent versions (4.0.0 and beyond) will resemble the new next-gen subproject. A major refactoring has been written containing much of the connection like functionality now found in project Keraiai.
This project contains many useful features, but chief among them is automatic session management to your SFDC web services (custom, enterprise, metadata, partner, and tooling). By this we mean using credentials (user name, password, security token SFDC API version, and URL), we can provide:
- Automatic login.
- Automatic re-login should a session id become invalid.
- Concurrent threaded access to SFDC per session id.
- Multiplexed session ids for scaling up simultaneous concurrent calls to SFDC.
The most interesting thing to consider in the aforementioned statements is there is nothing special you must do other than have your SFDC WSDL and use wsimport to generate your client Java code. Once you've done this, in a matter of a few lines of code, you can leverage the above bullet points. The following sections will show you all that's involved.
Credentials are nothing more than a user name, password, security token, API version and URL (the SFDC URL to use when we login - ie https://test.salesforce.com or https://login.salesforce.com). There exists an interface aptly entitled Credentials and a few implementations:
- Default Credentials: simple holder of the aforementioned items such as user name, password, etc.
- Properties Credentials: uses a property manager, from the FlossWare java library, to load properties containing the aforementioned items such as user name, password, etc.
username = loneuser@some.company.com
password = somepassword
token = abcdefghijklmnopqrstuvwx
url = https://test.salesforce.com
apiVersion = 30.0
This snippet will load the aforementioned lone-user.properties file into a Credentials instance.
final Credentials credentials = new PropertiesCredentials(new FilePropertiesMgr("/tmp/myuser/creds/single/lone-user.properties"));
Security managers are used to login and logout of SFDC. All security managers provide an implementation of LoginResult which represents the login result one gets when logging into SFDC using either the enterprise, partner or tooling web services. Coincidentally, there are three security manager implementations in Lasius corresponding to them:
A security manager is used by session managers to login (if not already logged in) or log out (using the resetSession(). The result of a login is a session which contains a login result. Please see the next section for more information.
Once one logs into into SFDC (via a Security Manager), a session is created that holds the login result, and SFDC session id. Additionally, a session can provide the mechanism for locking and unlocking to help control simultaneous calls to SFDC web services (think of a semaphore). The call to lock() will actually block should their be 0 remaing locks available. Calling unlock() will allow any threads being blocked to proceed when attempting to lock().
It is highly unlikely you will ever use this class directly. It is actually used by proxy ports as described later below.
Session managers utilize credentials and security managers to:
- Manage sessions.
- Perform automatic logins when returning a session. If no session exists, the login will happen at that time.
- Reset sessions: disregards the current session and will perform a login. Please note this is only applicable if you attempt to reset a good "current" session.
There are currently two implementations of session managers:
- Single session manager: Deals with a single credential and a lone session.
- Multi session manager: Allows you to maintain N session managers using N credentials. Internally it uses N SingleSessionMgr's - one per credential.
When using wsimport against a WSDL, client Java code is generated containing a subclass of Service. This subclass will contain a "port" method that one uses to perform actual web service calls. For example, the following snippet represents the service generated code for an enterprise WSDL:
@WebServiceClient(name = "SforceService", targetNamespace = "urn:enterprise.soap.sforce.com", wsdlLocation = "file:/home/sfloess/Development/personal/solenopsis/Lasius/wsutils/wsdls/src/main/resources/wsdl/Lasius-enterprise.wsdl")
public class SforceService
extends Service
{
@WebEndpoint(name = "Soap")
public Soap getSoap() {
return super.getPort(new QName("urn:enterprise.soap.sforce.com", "Soap"), Soap.class);
}
}
Here is a snippet of wsimport generated java code for the tooling WSDL:
@WebServiceClient(name = "SforceServiceService", targetNamespace = "urn:tooling.soap.sforce.com", wsdlLocation = "file:/home/sfloess/Development/personal/solenopsis/Lasius/wsutils/wsdls/src/main/resources/wsdl/Lasius-tooling.wsdl")
public class SforceServiceService
extends Service
{
@WebEndpoint(name = "SforceService")
public SforceServicePortType getSforceService() {
return super.getPort(new QName("urn:tooling.soap.sforce.com", "SforceService"), SforceServicePortType.class);
}
}
The port is denoted via the annotated method for @WebEndpoint and above is:
- the method getSoap() for the enterprise WSDL.
- the method getSforceService() for the tooling WSDL.
When making SFDC web service calls, one must:
- set the session id (generated from login) into the SOAP header of the port.
- set the server URL from login as the end point. The URL denoted above for credentials is the login URL. Once you actually login, you are presented with a server URL in your login result - this is the one you want to use.
Lasius provides a number of convenient ways to deal with ports as described in the sections below.
Lasius makes use of the FlossWare Web Service package to simplify creating ports. Above we illustrated two different methods for returning the ports on the enterprise and tooling WSDLs. The FlossWare Service package will examine a Service subclass to find the ports for a Service based upon the @WebEndpoint annotation and use that to create ports uniformly and easily, encapsulating this to one method getPort(). This simplification makes port management for any SFDC web service trivial.
To illustrate, we'll define a web service for both the enterprise and tooling WSDLs above. Please note we are denoting WSDL locations in the classpath within a directory entitled "wsdl" as seen below:
final WebService<Soap> enterpriseWebService = new GenericWebService("wsdl/enterprise.wsdl", SforceService.class);
final WebService<SforceServicePortType> toolingWebService = new GenericWebService("wsdl/tooling.wsdl", SforceServiceService.class);
final Soap enterprisePort = enterpriseWebService.getPort();
final SforceServicePortType toolingPort = toolingWebService.getPort();
Even better:
final Soap enterprisePort = new GenericWebService<Soap>("wsdl/enterprise.wsdl", SforceService.class).getPort();
final SforceServicePortType toolingPort = new GenericWebService<SforceServicePortType>("wsdl/tooling.wsdl", SforceServiceService.class);
Lasius provides a number of utility classes for utilizing SFDC web service ports (please see above for the definition of "port" here as it is not related to sockets):
- Salesforce Web Service Util
- Custom Web Service Util
- Enterprise Web Service Util
- Metadata Web Service Util
- Partner Web Service Util
- Tooling Web Service Util
As a side note:
- A custom web service are web services written in Apex for SFDC.
- The Salesforce Web Service Util is a very generic utility class. It's useful but is mostly leveraged by the other utility classes listed in the bulleted section. While you can use this, it's unlikely you ever will.
Unproxied ports are those ports that are used without concern for:
- Sharing session ids across threads.
- Re-logins when session ids become invalid.
They are great when you need to communicate with SFDC simply and easily. Be aware when using any of the following web service utilities in an unproxied capacity, you will be automatically logged in and server URL set so your web service calls can proceed for you:
- Custom Web Service (Developer Designed) Util
- Enterprise Web Service Util
- Metadata Web Service Util
- Partner Web Service Util
- Tooling Web Service Util
Assume you want to utilize your company's enterprise.wsdl and you've stored it in your classpath within a "wsdl" directory:
final Credentials credentials = new DefaultCredentials("https://test.salesforce.com", "user1", "password", "abcdefghijklmnopqrstuvwx", "30.0");
final Soap enterprisePort = EnterpriseWebServiceUtil.createPort(credentials, "wsdl/enterprise.wsdl", SforceService.class);
Now when you use enterprisePort:
- You will automtically be logged in.
- The session id will be set on the port.
- The server URL from login will be set and your calls will hit the correct SFDC host.
Proxied ports are useful when you:
- Allow for concurrent threaded access to SFDC web services for a session id. Specifically one can call SFDC without regard to the number of simultaneous concurrent calls being made for a session id. Only the maximum number of calls (presently 10) will be allowed. Any more calls above 10 will block until currently executing calls return from SFDC.
- Multiplexing many SFDC users to scale up simultaneous concurrent calls. Specifically by using more than one user, you can leverage 10 times the actual number of users (credentials) simultaneous calls. As an example, using 5 SFDC users you can make 50 simultaneous concurrent calls to SFDC web services.
- Long running applications where session ids may become stale (the dreaded invalid session id SOAP Fault).
- Using more than one web service across session id(s).
Please note: simultaneous concurrent calls per session Id is based upon SFDC API releases and currently in Lasius is 10 calls per session id. Where appropriate should the number of calls for a session Id be greater than 10, we will either block (in the case of a SingleSessionMgr) or attempt to use another SessionMgr (when using a MultiSessionMgr). An issue is presently open to externalize this number per API version and is scheduled to be fixed as part of Lasius 2.1.
Assume you want to utilize your company's enterprise.wsdl, tooling.wsdl and metadata.wsdl. Also assume you've stored those WSDL's within a "wsdl" directory.
final Credentials credentials = new DefaultCredentials("https://test.salesforce.com", "user1", "password", "abcdefghijklmnopqrstuvwx", "30.0");
final SingleSessionMgr sessionMgr = new SingleSessionMgr(credenials, new EnterpriseSecurityMgr());
final Soap enterprisePort = EnterpriseWebServiceUtil.createEnterpriseProxyPort(sessionMgr, "wsdl/enterprise.wsdl", SforceService.class);
final SforceServicePortType.class toolingPort = ToolingWebServiceUtil.createToolingProxyPort(sessionMgr, "wsdl/tooling.wsdl", SforceServicePortType.class);
final MetadataPortType metadataPort = MetadataWebServiceUtil.createMetadataProxyPort(sessionMGr, "wsdl/metadata.wsdl", MetadataService.class);
Now you can:
- use all the ports in a threaded capacity - but for one SFDC user.
- never exceed 10 simultaneous calls as the session manager will block any call until any additional calls complete.
- automatically logged in.
- automatically re-login over time when your session id becomes stale (invalid session id).
final Credentials credentials1 = new DefaultCredentials("https://test.salesforce.com", "user1", "password", "abcdefghijklmnopqrstuvwx", "30.0");
final Credentials credentials2 = new DefaultCredentials("https://test.salesforce.com", "user2", "password", "abcdefghijklmnopqrstuvwx", "30.0");
final Credentials credentials3 = new DefaultCredentials("https://test.salesforce.com", "user3", "password", "abcdefghijklmnopqrstuvwx", "30.0");
final Credentials credentials4 = new DefaultCredentials("https://test.salesforce.com", "user4", "password", "abcdefghijklmnopqrstuvwx", "30.0");
final MultiSessionMgr sessionMgr = new MultiSessionMgr(new Credentials[] {credentials1, credentials2, credentials3, credentials4}, new EnterpriseSecurityMgr());
final Soap enterprisePort = EnterpriseWebServiceUtil.createEnterpriseProxyPort(sessionMgr, "wsdl/enterprise.wsdl", SforceService.class);
final SforceServicePortType.class toolingPort = ToolingWebServiceUtil.createToolingProxyPort(sessionMgr, "wsdl/tooling.wsdl", SforceServicePortType.class);
final MetadataPortType metadataPort = MetadataWebServiceUtil.createMetadataProxyPort(sessionMGr, "wsdl/metadata.wsdl", MetadataService.class);
Now you can:
- use all the ports in a threaded capacity - across four SFDC users.
- never exceed 40 simultaneous calls as the session manager will multiplex calls across all four SFDC users! When you exceed 40, the calls will be blocked until one of the internal session managers becomes free. Please note your upper bounds on number of concurrent calls is: 10 x the-number-of-credentials. Above we used four credentials therefore our total concurrent calls is: 10 x 4 = 40!
- automatically logged in.
- automatically re-login over time when a session id from one of the sessions becomes stale (invalid session id).
It's important to note this works equally well with your own custom SFDC web services - the level of effort is exactly the same!