July 31, 2010

Using Apex:Variable in Visualforce to control rendering of HTML Markup

This post is for developers working on Visual-force. I came across an interesting way to control rendering of HTML markup, previously I was using “<apex:outputPanel .. />” for controlling the rendering of some HTML markup. This approach works well and has no such harm, but it introduces and additional “DIV” or “SPAN” depending on outputPanel’s layout attribute. Unless you use layout=”none” attribute.

So another alternate can be to use <apex:variable rendered=””/> for controlling the rendering of HTML markup. We mostly use apex:variable tag for declaring complex expressions or variables in visual force page. But the same can be used very easily to control the rendering too,

Apex Variable Code Snippet

For sake of sample code, I have created a small visualforce page that

  • Renders some HTML markup using both <apex:outputPanel /> and <apex:variable />
  • Hides some HTML markup using Apex variable.
  • Is connected to a simple controller with two Boolean variables to control visibility.

 

Here is the visualforce code

<apex:page controller="ApexVarController">
	<!--  
        This container div "mycontainer-div" will be used to track, the HTML differences between apex:outputPanel and apex:variable
     -->
	<div id="mycontainer-div">
	    <!-- apex:outputPanel tag to control the rendering for Markup -->
		<apex:outputPanel rendered="{!controllerBoolTrueVar}">
			<h1>This markup is rendered under control of &lt;apex:outputPanel
			/&gt; tag</h1> <br />
		</apex:outputPanel> 
		
		<!-- apex:variable tag to control the rendering for Markup --> 
		<apex:variable
			value="anything will go here" var="tempRenderingVar1"
			rendered="{!controllerBoolTrueVar}">
			<h1>This markup is rendered under control of &lt;apex:variable
			/&gt; tag</h1><br />
		</apex:variable> 
		
		<!-- apex:variable tag used to not render for a Markup --> 
		<apex:variable
			value="anything will go here" var="tempRenderingVar2"
			rendered="{!controllerBoolFalseVar}">
			<h1>This markup will not appear on the page</h1><br />
		</apex:variable>
	</div>
</apex:page>

The simple Controller attached to above visualforce page

public class ApexVarController {
    public boolean controllerBoolTrueVar { get; set; }
    public boolean controllerBoolFalseVar { get; set; }
    
    public ApexVarController (){
        controllerBoolTrueVar = true;
        controllerBoolFalseVar = false;
    }
}

Please share any queries or ideas about better ways to control rendering of html markup.

July 29, 2010

Tolerado SFDC WSC Helper APIs

I am researching on how to best use & integrate “WSC” with Tolerado. This research mainly focuses on

  • How to preserve and reuse a single sfdc login session across the all the WSDLs. This should again go in transparent fashion as with Tolerado for Apache Axis.
  • How to give an flexible+transparent interface to either login via Enterprise or Partner WSDL and then play with Metadata and Apex WSDL if required.
  • Keep possibility of Session caching open.

So during all that research, I came out with some Helper classes, that will anyway become part of Tolerado WSC framework, but I am releasing those as independent Java API classes. This will benefit others playing with WSC and who are not yet on Tolerado.

For this reason, I am sharing a helper Class/API for WSC in this post. This helper class is named “WSCSession” and it helps managing WSC session in a smart & easy way.

Class - WSCSession

Following are the highlights of WSCSession Class.

  • WSCSession allows you to flexibly login either via Partner or Enterprise WSDL. The best part is it doesn’t depends on either Partner or Enterprise WSDL2Java classes. So if you are working on Enterprise WSDL, you don’t need to include WSDL2Java classes for Partner WSDL in classpath. It internally works on dynamic class loading to ensure right WSC Connectors are used to create SFDC Sessions.
  • Gives easy API to obtain Service Endpoints for all Salesforce WSDLs like Partner, Enterprise, Metadata and Apex WSDL.  For ex.
    • public String getSessionId(); // returns reusable session id, that works across all wsdls
    • public String getMetadataServerUrl(); // Metadata Service Endpoint
    • public String getPartnerServerUrl(); // Partner Service Endpoint
    • public String getEnterpriseServerUrl(); // Enterprise Service Endpoint
    • public String getApexServerUrl(); // Apex Service Endpoint

Code Snippets - How WSCSession makes life easy with WSC ?

Now we will explore how to create a WSCSession instance and use it with all the WSDLs.

Creating WSCSession using Enterprise WSDL for login
// Note, we just specified Login WSDL is Enterprise
WSCSession session = new WSCSession(LoginWSDL.Enterprise, "user", "password");
Creating WSCSession using Partner WSDL for login
// Note, we just specified Login WSDL is Partner
WSCSession session = new WSCSession(LoginWSDL.Partner, "user", "password");

We can start playing with code samples below, once WSCSession is created in either of the above mentioned way i.e. by Enterprise or Partner WSDL.

Partner WSDL Sample – Creating Contact Record
static void doPartner(WSCSession session)
        throws ConnectionException {
    // Create new Partner Connection
    ConnectorConfig config = new ConnectorConfig();
    config.setManualLogin(true);
    // Parter Service Endpoint used from WSCSession
    config.setServiceEndpoint(session.getPartnerServerUrl());
    // SFDC Session Id pulled from WSCSession
    config.setSessionId(session.getSessionId());
    PartnerConnection partnerConn = Connector.newConnection(config);      

    // Create a new Contact
    SObject contact = new SObject();
    contact.setType("Contact");
    contact.setField("FirstName", "Abhinav");
    contact.setField("LastName", "Gupta");
    SaveResult[] create = partnerConn.create(new SObject[] { contact });
    for (SaveResult saveResult : create) {
        if (!saveResult.isSuccess()) {
            throw new RuntimeException(
                    "Failed to save contact via Partner WSDL");
        }
    }
    System.out.println("Partner-WSDL : Save successfully done");
}
Metadata WSDL Sample – Describe Metadata
static void doMeta(WSCSession session) throws ConnectionException {
    // Create Metadata Connection
    ConnectorConfig metadataConfig = new ConnectorConfig();
    // SFDC Session Id pulled from WSCSession
    metadataConfig.setSessionId(session.getSessionId());
    // Metadata Service Endpoint used from WSCSession
    metadataConfig.setServiceEndpoint(session.getMetadataServerUrl());
    MetadataConnection metadataConnection = com.sforce.soap.metadata.Connector
            .newConnection(metadataConfig);

    // Try describing the metadata
    DescribeMetadataResult describeMetadata = metadataConnection
            .describeMetadata(15.0);
    System.out
            .println("Metadata WSDL : OrgName from describeMetadata() call"
                    + describeMetadata.getOrganizationNamespace());
}
Apex WSDL Sample – Running All Tests
static void doApex(WSCSession session) throws ConnectionException {
    // Create Apex Connection
    ConnectorConfig apexConfig = new ConnectorConfig();
    // SFDC Session Id pulled from WSCSession
    apexConfig.setSessionId(session.getSessionId());
    String apexEndpoint = session.getApexServerUrl();
    // Metadata Service Endpoint used from WSCSession
    apexConfig.setServiceEndpoint(apexEndpoint);
    SoapConnection apexConnection = com.sforce.soap.apex.Connector
            .newConnection(apexConfig);

    // Run All Tests in the org
    RunTestsRequest runTestsRequest = new RunTestsRequest();
    runTestsRequest.setAllTests(true);
    runTestsRequest.setNamespace("");
    RunTestsResult runTests = apexConnection.runTests(runTestsRequest);
    System.out.println(" Apex-WSDL: NumTestsRun :  "
            + runTests.getNumTestsRun());
}
Enterprise WSDL Sample – Querying Contact Record
static void doEnterprise(WSCSession sessionFactory)
        throws ConnectionException {
    // Create Enterprise Connection		
    ConnectorConfig entCfg = new ConnectorConfig();
    entCfg.setManualLogin(true);                
    // Enterprise Service Endpoint used from WSCSession
    entCfg.setServiceEndpoint(sessionFactory.getEnterpriseServerUrl());
    // SFDC Session Id pulled from WSCSession
    entCfg.setSessionId(session.getSessionId());
    EnterpriseConnection entConn = com.sforce.soap.enterprise.Connector
            .newConnection(entCfg);		

    // Enterprise WSDL for query
    QueryResult queryResults = entConn
            .query("SELECT Id, FirstName, LastName FROM Contact LIMIT 1");
    if (queryResults.getSize() > 0) {
        Contact c = (Contact) queryResults.getRecords()[0];
        System.out.println("EnterPrise WSDL : Queried Contact Name: "
                + c.getFirstName() + " " + c.getLastName());
    }
}

Running the Code Samples - WSCSession and Sample Source

WSCSession class and sample code is checked in as part of Tolerado WSC project. For these WSC Helper Samples, their is a new Eclipse Java project(link to SVN code base) that you can directly checkout from SVN to start playing with directly in Eclipse. Just locate a properties file name “login.props” in the downloaded source and set your SFDC credentials in this file. All the sample code will automatically use the credentials in login.props file. The samples file is with name “WSCSessionSample”.

Please let me know any bugs or issues, if you faced.

July 27, 2010

Salesforce WSC Metadata WSDL Connector Config Issue – Solved !

I am working and doing RnD with Salesforce WSC library, to get Tolerado ported to it.  Most of the pieces worked well, but was stuck with Metadata WSDL issues from very starting. I got into following two major blockers

  1. Metadata WSDL Compilation Issue
  2. Metadata Connector Config Issue

Both these are explained in below

Metadata WSDL Compilation Issue

Thanks to Jeff for his post about fixing the metadata compilation issue and other assistance with WSC Code Samples. I get rid of this one by using the Jeff’s fix.

Metadata Connector Config Issue

When I tried running a sample metadata call by using Session Ids from Partner WSDL Login and created MetadataConnection it failed with error “INVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal Session", There is an issue posted on WSC Google Code Project too for the same.

Failing code shown below:

ConnectorConfig partnerConfig = new ConnectorConfig();
partnerConfig.setUsername("un");
partnerConfig.setPassword("pw");

PartnerConnection partnerConn = com.sforce.soap.partner.Connector.newConnection(partnerConfig);

ConnectorConfig metaConfig = new ConnectorConfig();
metaConfig.setSessionId(partnerConn.getSessionHeader().getSessionId());

MetadataConnection metaConn = Connector.newConnection(metaConfig);
DescribeMetadataResult describeMetadata = metaConn.describeMetadata(API_VERSION);
System.out.println(describeMetadata);

Solution

After some research and digging into WSC code, found that we need to set correct Metadata server URL to the ConnectorConfig. Obtaining Metadata URL was straightforward with Apache Axis as we need to do the Partner login manually. But with WSC we need to tell ConnectorConfig to STOP “Auto Login” and then do a manual login to get reference of LoginResult. So finally, following code is solution to this issue.

ConnectorConfig partnerConfig = new ConnectorConfig();
// IMPORTANT : This will not let PartnerConnection do the login
partnerConfig.setManualLogin(true);

PartnerConnection partnerConnection = com.sforce.soap.partner.Connector.newConnection(partnerConfig);
// We need LoginResult to get correct metadata server url
LoginResult lr = partnerConnection.login("USERNAME", "PASSWORD");

ConnectorConfig metadataConfig = new ConnectorConfig();
metadataConfig.setSessionId(lr.getSessionId());
// Set the metdata server url from LoginResult
metadataConfig.setServiceEndpoint(lr.getMetadataServerUrl());
MetadataConnection metadataConnection = com.sforce.soap.metadata.Connector.newConnection(metadataConfig);
DescribeMetadataResult describeMetadata = metadataConnection.describeMetadata(15.0);
System.out.println(describeMetadata);

July 26, 2010

Tolerado’s Release 1.1 – Added Plug and Play Support for Salesforce WSDLs!

Tolerado 1.1 release is available for download on Google code project now. The highlights of this release is

  • “Plug and Play Salesforce WSDLs” :- What that means is now you can plug any of the partner, enterprise, metadata and apex WSDLs on top of tolerado-core-x.x.jar.
  • Supports Enterprise WSDL : Now you can create cached and fault tolerant client implementations for your SFDC Enterprise WSDL also.

Previously “Tolerado 1.0” was just a single Jar file tolerado-x.x.jar, that enforces people to use WSDL2Java stuff for Apex and Metadata WSDLs also. Many of us don’t  need all these stubs while working with Salesforce APIs, for ex. one might be working with partner wsdl, then why get stuff related to metadata and apex wsdls.

The diagram below indicated how Tolerado jars can be best used for a web service project.

References

For more info on “Tolerado”, please follow these pointers

July 22, 2010

Tolerado SFDC-WSC integration started !

Tolerado API for Apache Axis 1.4 is code complete and is available at Google Code Project & Salesforce Code Share Project. Moving forward, as said I am working on developing Tolerado API for WSC. This is really important, as WSC is a high performance WS-Client running on top of Streaming Parser. And it seems new Java client projects for developing Salesforce mash-ups will move to WSC.

As of now, I am researching how Tolerado will fit with WSC stuff and experimenting with small test programs. My target is to show you something functional on top of “Tolerado + WSC” by 1st week of August.

References

For more info on “Tolerado”, please follow these pointers

July 14, 2010

How Tolerado improves the Salesforce Web Service Client code !

This post explains how Tolerado improves the Java client code for using Salesforce web services.

Why Client Code improvement is required ?

Developers are always too concerned about many things, like making the Web Service call work right for them and implementing the biz requirements. So handling exceptions and giving them proper treatment is mostly not a priority. Developers usually check the API docs/samples and production ready product usually evolves from the foundation laid by those sample codes.

So, Tolerado jumps in here to touch the areas often ignored in web service programming.

Code Samples

Here we will try touching areas of common programming issues and how Tolerado would fix them.

Sample 1 : Making Partner/Metadata/Apex Calls

When working Salesforce Axis client stubs, following are 2 very common scenarios/exceptions, where its possible to recover from errors but the code crashed :

  • Exception 1: Connection timeout or Unknownhost Error: This error might temporarily come in your internet connection because of some DNS/internet issues.
  • Exception 2: Service temporarily down: Again on getting this error, we are failing fast in above code samples.
  // Code sample that shows, the web service exception 
  // being caught and eaten
  
  QueryResult qr = null;
  try {
    // All your code to create the binding and set the correct headers 
    // .... 
    // ...
    binding = (SoapBindingStub) new SforceServiceLocator().getSoap();  
    // ...
    LoginResult loginResult = binding.login(userName, password);
    binding._setProperty(SoapBindingStub.ENDPOINT_ADDRESS_PROPERTY,
                                loginResult.getServerUrl());
    SessionHeader sh = new SessionHeader();
    sh.setSessionId(loginResult.getSessionId());
    binding.setHeader(new SforceServiceLocator().getServiceName()
                                .getNamespaceURI(), "SessionHeader", sh);
    qr = binding.query("select FirstName, LastName from Contact");
    // ... 
    // process the results within QueryResult 
    // ...
  }catch (Exception ex) {
    // No recovery, just log the message.
    System.out.println(
           "\nFailed to execute query successfully, error message was: \n" 
           + ex.getMessage());
  }

After using Tolerado stub, you will get something very similar. But many other stuff transparently. Check the code sample below.

    // NOTE: No try catch block, a RunTimeException ToleradoException is thrown if the failure // is not recoverable

    // All the hassle of doing login and setting headers encapsulated in this single call
    // ToleradoStub is a ready to use stub, with no changes required
    ToleradoPartnerStub pStub = new ToleradoPartnerStub(new Credential("userName@user.com", "password"));
    //Binding created transparently from the given salesforce user name
    //password.
    //You transparently got the
    //1. Fault recovery mechanism
    //2. Cached stub (if its second call via the same login)
    //3. QueryResult is same class as before, so no change on your rest of the
    // logic.
    QueryResult qr = pStub.query("select FirstName, LastName from Contact");
    // ... 
    // process the results within QueryResult 
    // ...
Sample 2 : Making Partner queryMore Calls

Using queryMore requires some setting of headers to stubs for batch size and using a string query locator handle correctly.

First we will show the normal code without Tolerado framework

  QueryResult qr = null;
  _QueryOptions qo = new _QueryOptions();
  qo.setBatchSize(250);
  binding.setHeader(new SforceServiceLocator().getServiceName().getNamespaceURI(), 
                     "QueryOptions", qo);
  try {
    qr = binding.query("Select name From lead");
    boolean done = false;
    if (qr.getSize() > 0){      
      while (!done) {
        for(sObject lead : qr.getRecords()) {
            System.out.println(lead.get_any()[0].getValue());
        }
        if (qr.isDone()) {
          done = true;
        } else {
          qr = binding.queryMore(qr.getQueryLocator());
        }
      }
    }
    else {
      System.out.println("No records found.");
    }
    System.out.println("\nQuery succesfully executed.");
  }
  catch (RemoteException ex) {
    // No recovery from remote errors
    System.out.println("\nFailed to execute query successfully, error message was: \n" + 
                       ex.getMessage());
  }

Now we will show the Tolerado simplified code sample

  
    // Cached, Recoverable Stub
    ToleradoPartnerStub pStub = new ToleradoPartnerStub(new Credential("username", "password"));
    // Wrapper class for making queryMore calls super easy
    // Just pass the SOQL and batch size here, it will take care of the rest
    ToleradoQuery q = new ToleradoQuery(pStub, "Select name From lead",
                                250);    
    // Do Java style iteration over the ToleradoQuery
    while (q.hasMoreRecords()) {
        // Correct query locator used internally 
        SObject[] records = q.getRecords();
        if (records == null || records.length == 0)  break;
        for(sObject lead : records) {
            System.out.println(lead.get_any()[0].getValue());
        }            
                log.debug("Fetched next " + records.length + " records !");
        }
    // No try catch block as run time exception is thrown, if the stub can't recover
    // the error. 
Sample 3: Working with SObject – Creating new Contact record

Developers need to deal with MessageElement and Sobjects while creating new Sobjects. As shown below

  SObject[] cons = new SObject[1];
  MessageElement[] contact = new MessageElement[5];
  contact[0] = new MessageElement(new QName("FirstName"),"Joe");
  contact[1] = new MessageElement(new QName("LastName"),"Blow");
  contact[2] = new MessageElement(new QName("Salutation"),"Mr.");
  contact[3] = new MessageElement(new QName("Phone"),"999.999.9999");
  contact[4] = new MessageElement(new QName("Title"),"Purchasing Director");
  cons[0] = new SObject();
  cons[0].setType("Contact");
  cons[0].set_any(contact);
  SaveResult[] sr = null;
  try {
    sr = binding.create(cons);
  } catch (Exception ex) {
    System.out.println("An unexpected error has occurred." + ex.getMessage());
    return;
  }

The Tolerado code, is much simpler and more readable

    ToleradoSobject sobj = new ToleradoSobject("Contact");
    sobj.setAttribute("FirstName", "Joe");
    sobj.setAttribute("LastName", "Blow");
    sobj.setAttribute("Salutation", "Mr.");
    sobj.setAttribute("Phone", "999.999.9999");
    sobj.setAttribute("Title", "Purchasing Director");
    // Get the updated Sobejct
    SObject updatedSObject = sobj.getUpdatedSObject();
    SaveResult[] saveResults = partnerStub.create(new SObject[] { updatedSObject });
What advantage you get is clearly visible

References

For more info on “Tolerado”, please follow these pointers

July 11, 2010

“Tolerado” - Salesforce Web Service client wrappers !

I am starting a new open source project called “Tolerado”. Tolerado will be a wrapper API over Salesforce Java Web service client (Apache Axis, WSC integration planned too). This project is started with motivation to make client java code more fault tolerant, recoverable and stable at production, so its named “Tolerado”. Tolerado will give wrapper API over Metadata, Partner and Apex WSDL APIs.

Core Motive

Motive is to create an API that wraps existing Salesforce web service client APIs and

  • Giving a RECOVERABLE framework for each web service method call. This recoverable framework will transparently RETRY all the recoverable web service/remote errors/exceptions rather failing fast.   Why recovering is important is explained here.
  • Giving an transparent caching mechanism for salesforce session id/urls, so that we save a login web service call.
  • Giving utility and wrapper API's for easing and making development effort less error prone with existing WS client stubs. For ex.
    • Easing the creation of new Sobjects via wrappers rather using “com.sforce.soap.partner.sobject.SObject” and notorious MessageElement.
    • Giving easy stubs, so that developers are not into hassle of setting right session headers, server urls etc for using either Metadata, Apex or Partner WSDL APIs.
  • Keeping the migration effort to minimal. So classes are designed to fit well with existing Axis generated classes for ex. QueryResult, RunTestsResult etc.

Tolerado Design/Components

Tolerado is having 3 main components, these match almost exactly to the motives mentioned above. Here is the list

  1. ToleradoStub(s) : These stubs are set of huge wrapper classes over all the web service calls exposed by partner, metadata and apex web service calls. (100 % Complete, code checked in with few samples) . It gives
    • Management of session headers and all other housekeeping required to keep the state correct in various partner, metadata and apex stubs.
    • Fault tolerant behavior to each web service method.
    • Transparent Salesforce SessionID + Server URL caching. So future web service calls can reuse the tokens. Those tokens are automatically renewed on expiry.
  2. ToleradoQuery : Its a partner query helper class. When querying with partner binding you can directly fetch only 500 records. To fetch more then 500 one needs to use queryMore() API, this API requires setting some headers and maintaining a cursor on client. This class simplifies and exposes and easy to use interface to queryMore() API, so it does all the ground work for making the call correctly. (100 % Complete, code checked in with few samples)
  3. ToleradoSObject : Wraps the com.sforce.soap.partner.sobject.SObject class, so that creating, updating and working with attributes can be pretty correct and easy. (I am in middle of development 30 % Complete, will check-in the code soon)

Source @ Google Code

Complete source code including the sample I am creating are available here. I am code complete. One can do an anonymous checkout from SVN, instructions available here.

References

For more info on “Tolerado”, please follow these pointers

TODOs ?

Guys, biggest TODO and help would be to test and start playing with the API, and report bugs. So here is the list

  • Add more documentation, add pages like FAQ and Videos for quickly productive with Tolerado
  • More more testing