December 30, 2010

“No debug logs” on Apex Test Run in Force.com IDE for Winter’11

Winter’11(20.0.0) Force.com Plugin/IDE users stumbled upon “no debug logs” issue on running unit tests.  The problem is well stated below in this community thread

image

There are many similar community threads on force.com discussion boards around the same issue “No Debug logs” issue.

How to fix this ?

This issue poped because of a bug in winter’11(20.0.0) Force.com IDE. The Force.com IDE team released an IDE update(20.0.1) on November 15, 2010 that addresses this issue. More details in screen shot below and IDE release notes page here.

image 

So, to get rid of this issue, just update your Force.com IDE via this update site : http://www.adnsandbox.com/tools/ide/install/

December 25, 2010

Invoking “Apex WSDL” Web Services from Apex Code

Because of Tolerado, I came to know about “Apex Programming WSDL” given by Salesforce. Apex WSDL on a high level gives web service APIs for

  • running apex tests
  • executeAnonymous code
  • compiling classes and triggers.

How to download this WSDL ?

Apex programming WSDL can be downloaded from “Setup” area of your Salesforce org. Just land on “App Setup > Develop > API” page. Instructions to download are shown below.

Integrating with “Apex Programming WSDL” !

One can compile/consume this WSDL in various programming languages like Java/PHP/.NET/etc.  Post compilation, one can easily create mashup applications to behave like mini Cruise Control for Apex, those that can run nightly tests for your Salesforce Org etc. Only problem is those application needs to be hosted and maintained by one, not really on CLOUD unless one is developing one Smile

Compiling “Apex WSDL” to generate Apex code stubs (WSDL > Apex)

Fortunately, one can also generate Apex code stubs for a given WSDL i.e. force.com platform gives you an option to do “WSDL > Apex”  compilation.

Using this feature, we can bring the who bunch of web service exposed by “Apex WSDL” to Apex code directly.

So, lets hit the button showed in above screenshot i.e. “Generate from WSDL” and specify the downloaded “apex.wsdl” file, here, as shown below.

In next step, you will be asked to give a good name to the generated Apex class, by default it will come with something like “soapSforceCom200608Apex”. Detailed instructions shown below.

Next, you should see screen like following, giving you the link to the newly generated/compiled Apex class from “Apex WSDL”

Next, we will see how to invoke Apex WSDL web services from Apex code directly.

Invoke Apex WSDL web services from Apex Code

In this section I am assuming you have already generated “ApexStub” class by compiling Apex WSDL, as described above.

Step 1 – Know your web service end point !

As we are going to make web service calls from Apex code, we need to whitelist the web service endpoints first. To know your web service endpoint, there are two ways i.e.

1. Check location attribute of <soap:address location=”https://….”> in Apex WSDL file, it should have something like this. So for my org the web service endpoint to white list is “https://ap1-api.salesforce.com/services/Soap/s/20.0

<soap:address location="https://ap1-api.salesforce.com/services/Soap/s/20.0"/>

2. You can also check your endpoint directly in the ApexStub class. “ApexStub.Apex.endpoint_x” property points to the web service endpoint.

Step 2 – Whitelist the web service end point

To white list, goto “Setup > Administration Setup > Security Controls > Remote Site Settings” and create a “New Remote Site” using the domain details from endpoint captured in steps above. Make sure remote site url is as per your SFDC org, my org is on node “ap1”, yours can be different i.e. on NA1 etc. My security settings are shown below.

Step 3 – Coding time, make the web service call !

Out of all web service calls given by Apex WSDL, most interesting for me is runTests(). This allows one to run tests on either a single, bunch or all apex classes in sfdc org.

Run All Tests Sample

Here is the sample code that uses the “ApexStub” class generated above to run all tests in the org.

ApexStub.Apex ap = new ApexStub.Apex();
ap.SessionHeader = new ApexStub.SessionHeader_element ();
// This is important, give session id, to let the call work.
ap.SessionHeader.sessionId = UserInfo.getSessionId();
ApexStub.RunTestsRequest  rtr = new ApexStub.RunTestsRequest();
// Run All Tests
rtr.allTests = true;
rtr.Namespace = '';
// Execute the Tests
ApexStub.RunTestsResult testResults = ap.runTests(rtr);
System.debug("Failures >" + testResults.numFailures);
Running test on Single or bunch of classes
// You can also specify single class in this array
String[] classNames = new String [] {'TestFeature1', 'TestFeature2'};
// or specify package or org wide 
// namespace here
String namespace = ''; 
ApexStub.Apex ap = new ApexStub.Apex();
ap.SessionHeader = new ApexStub.SessionHeader_element ();
ap.SessionHeader.sessionId = UserInfo.getSessionId();

ApexStub.RunTestsRequest  rtr = new ApexStub.RunTestsRequest();
rtr.classes = classNames;
rtr.allTests = false;
rtr.Namespace = namespace;
ApexStub.RunTestsResult results = ap.runTests(rtr);

For more details on how to,

  • Create various RunTestsRequest, check this API Doc.
  • Parse RunTestsResult object, check this API Doc.

Making Apex WSDL calls from Apex – Limitations  !!

As we are making web service callouts from Apex, all the governor limits imposed on web service callouts are applicable here too. For ex.

  • Total request time for all callouts (HTTP requests or Web services calls) in a single unit of work is 120 secs
  • Maximum size of callout request or response (HTTP request or Web services call) is 3 MB

Out of these two only the first one limits us most from doing anything super creative from Apex. So you can’t run all/single/bunch tests, if they consume more than 120 secs to complete. This is pretty easily possible with an org with decent number of apex classes.

So one can’t go straight forward and do anything with Apex WSDL calls.

Creating a Junit like Test Suite using Apex WSDL.

Junit is a unit testing framework in Java. Many bits and pieces of Apex TestCase class are inspired from this framework itself.

A nice feature that’s given by Junit is ability to create TestSuites. A TestSuite is a Composite of Tests. It runs a collection of test cases. The beauty of test suites is you can create small suite of tests per feature or module of your org, this suite will have test classes for the feature/module only. So when you change something, its really not required to run all the tests, you can just run suite and see if everything for the feature is stable.

Apex Test Suites & ApexClass Sobject !

As of now, Apex doesn’t offers this feature. But we can run tests on single class as described above,  so why don’t we use this feature to create test suites in Apex. But for that we need access to Apex Classes available in the org.

Good news !!! Salesforce schema already has an Sobject called “ApexClass”, this sobject keeps information about all the classes in a SFDC org.  One can query this Sobject for details like ClassName, Namespace, Body and length etc.

So, to create Test Suite an rough idea could be to 

  • Create a “TestSuite” and “TestSuiteClass” custom Sobject. “TestSuiteClass” will keep apex class name and namespace, because we can’t lookup or master details to ApexClass object. Test Suite Class will master detail on “TestSuite”.
  • Create a Visualforce page/apex controller, that queries ApexClass sobject and presents a list of Apex classes to end user to select. These selected Apex classes then can be used to create a TestSuite/TestSuiteClass records.
  • Now having this TestSuite and ApexStub class we can execute it in many ways, a slight challenge will be to hack around the governor limits imposed. For ex. we can create another Visualforce/Apex page to run tests available in the TestSuite.
  • Also by using TestSuite and ApexStub class, we can also create applications that tells coverage etc. As RunTestsResult returned after running tests, have fine details about that too.
Test Suite as a Salesforce App - Your views

Let me know what do you feel about this TestSuite concept, if its really worth moving forward like this. If you have some ideas and good feeling about it, we can join our efforts to create an opensource project for this.

Getting Test Suite natively in Force.com Platform - Idea exchange !

I posting TestSuite as an idea on Salesforce Idea Exchange too, to get this feature natively in platform itself. Here is the link to that idea : https://sites.secure.force.com/success/ideaView?c=09a30000000D9xtAAC&id=08730000000KPkXAAW

Please promote it to make the platform better.

December 11, 2010

Tolerado for WSC now works with Google App Engine !

This was a long time TODO, to integrate Tolerado for WSC with Google App Engine also. I am glad to share that its no more a TODO, all code changes are done to Tolerado framework and latest jars are available for download.

How to setup Tolerado for GAE

Setup is really trivial, we just need to tell Tolerado the right Http Transport to pass to WSC Connector.

For fine details on how to setup Tolerado with Google App Engine, please check this guide. Though this setup is really trivial, you just need to make following “one line” call from any startup java code for ex. Servlet Context Listener or any other code that gets executed before creating Tolerado Stubs. I usually prefer static blocks to save explicit calls.

static {
  ToleradoStub.WSC_HTTP_TRANSPORT = GaeHttpTransport.class;
}

A detailed code snippet about using Context listener for the same is available here.

Config files vs Java Code

Many of us prefer configuration files instead of Java code based configuration. I really hate config files. Still if you want me to release a config file to control HTTP TRANSPORT for WSC, please let me know.

Feedback

Any other suggestions, issues please let me know.

References

November 20, 2010

Tolerado WSC now gives transparent batcher support for Salesforce Partner APIs !

One can’t persist more than 200 records in one web service call using Salesforce Partner calls like create()/update()/upsert(). You will stumble upon this error on such attempts

“EXCEEDED_ID_LIMIT: record limit reached. cannot submit more than 200 records into this call”

The solution to this is to use a batching mechanism as described in the Salesforce Cookbook here : http://wiki.developerforce.com/index.php/Batch_records.java. This batching recipe code sample is giving simple abstraction to batching for update/create calls and is really easy to port to your production app, because its not dramatically changing the code design.

Transparent Batching available in Tolerado for WSC !

I thought Tolerado for Salesforce WSC should also make best use of this delicious Batching recipe. So, the same Batch_records.java batching is ported to Tolerado PartnerStubs. Here are highlights of this port :

  • Batching available to all create()/update() and even upsert() calls.
  • Batching is made available transparently. Being transparent here means, client code using ToleradoPartnerStub will not change at all, “batching will come into play automatically if number of records are more then 200

Updated Tolerado Jars are available in download area

For those who want more fine technical details on batcher implementation, please check these classes:

Your views ?

Would love to hear your views/suggestions/feedback on this !

November 14, 2010

Tolerado for Salesforce WSC release 1.1 out !

A major release 1.1. is done for Tolerado for WSC  APIs today.

Here is a quick list of changes that contributed to this release, like

  • Added support to use all Tolerado stubs with only sessionId and serverUrl in hand. Previously username/password was a must. (Issue 1)
  • Fixed cache sharing issue between enterprise and partner sessions (Issue 2)
  • Added support to use either Product, Developer, Sandbox, Prerelease or Custom Org Type(Enviornment) with Tolerado. Now one can feed in either the Enviornment or the hostname to use for authorizing with Salesforce.
  • Added support to specify Salesforce API version to Tolerado stubs. That means more control if you still want to stuck with previous API version.
  • Tolerado Sobject, internal changes for more flexiblity in extending and changing behavior like caching.
    • Added new method List<XmlObject> getChildrens(String relationshipName)
    • Added final getType(), setType() methods, to get/set SObjectType.
    • Deprecated setAttribute(String attribName) to match with getters like getValue(String) getTextValue(String) etc, we are promoting setValue(String, Object), This method(setAttribute) might be removed in future releases.
  • Simplified design of Tolerado stubs, to facilitate easy extensions.
  • Removed getLoginDriver() from ToleradoSession API contract.
  • ToleradoMetaStub for metadata wsdl, has new recoverable calls like
    • AsyncResult checkStatus(final String asyncProcessId)
    • RetrieveResult checkRetrieveStatus(final String asyncProcessId)
    • AsyncResult deploy(final byte zipFile, final DeployOptions deployOptions)
    • DeployResult checkDeployStatus(final String asyncProcessId)
  • Added logout() call to both Tolerado Partner & Enterprise stubs.

Complete release notes available here.

Any feedback or issues with this new release ? please let me know !

Salesforce WSC added support for Session Timeout handling !

Retrying web service call failures/exceptions is important, because not every exception means its “end of world”, their is always some HOPE, for some exceptions like Session Timeout / Invalid Sessions Id. One can always renew the session (if credentials are available), and make those failing web service calls work again.

Want to know more about such recoveries, its explained in this previous post “Why WS-Client should RETRY Web Service Exceptions ?”.

SFDC WSC API & Session Renewal !

Salesforce WSC(Force.com Web Service Connector) recently in release 20 introduced the same concept of renewing session on timeout or invalidation. Unfortunately, I can’t find this anywhere in any official WSC documentation, I came to know about this new feature, when I was debugging some error and stumbled upon WSC ConnectorConfig class. This class has a new attribute called “sessionRenewer”, SessionRenewer is a Java interface, implementations of which can be used to renew session in case of Session-Timeout. These SessionRenewer implementations can be optionally set by calling the relevant setters in ConnectorConfig i.e. setSessionRenewer(SessionRenewer sessionRenewer);

My “FAILED” experiment with WSC SessionRenewer Sad smile !

I thought of giving this new feature a try and created following test class. I was not able to make this code work well with SessionRenewer. I think SessionRenewer just handles session timeouts, not a generic INVALID_SESSION_ID fault raised because of many other reasons. So, to know where I was going wrong, I raised the issue on SFDC WSC Google code project. If any one of you was able to successfully use SessionRenewer, please let me know.

public class WSCSessionTest {
 public static void main(String[] args) throws Exception {
  ConnectorConfig cfg = new ConnectorConfig();
  cfg.setUsername("sfdcusername");
  cfg.setPassword("sfdcpass");
  // set the SessionRenewer implementation
  cfg.setSessionRenewer(new WSCSessionRenewer());
  PartnerConnection binding = Connector.newConnection(cfg);
  // force logout, to see if session timeout,
  // because of "invalid session" comes
  binding.logout();
  // Try querying now
  QueryResult qr = binding.query("Select Id, Name from Contact limit 1");
  System.out.println(qr.getRecords()[0].getField("Name"));
 }

 public static class WSCSessionRenewer implements SessionRenewer {
  @Override
  public void renewSession(ConnectorConfig config)
    throws ConnectionException {
   System.err.println("Renewing Session for Config : " + config);
   config.setManualLogin(true);
   PartnerConnection binding = Connector.newConnection(config);
   LoginResult lr = binding.login(config.getUsername(), config.getPassword());
   
   // I am updating the config, back as I don't have reference to the original
   // PartnerConnection object.
   config.setSessionId(lr.getSessionId());
   // If using Partner or Enterprise WSDL 
   config.setServiceEndpoint(lr.getServerUrl());   
  }
 }
}

Tolerado (WSC or Apache Axis) users already have all this !

For those who don’t know what is Tolerado,

“Project "tolerado" is a Java based WS client framework for better and fault tolerant use of Web Service APIs given by Salesforce. Tolerado-WSC works on top of highly performance SFDC Web Service Connector API. In case your project is depending on Apache axis 1.4, you can use Tolerado for Axis

Tolerado framework, already gives all this session renewal and many other forms of error recovery transparently. So developers who ported their Java WS projects to Tolerado, don’t need to worry about retryable/recoverable web service error handling. They can just focus on grooming the integration and business logic with Tolerado.

To even more simplify developers life, I requested WSC team, to integrate Tolerado into the WSC library. I raised this issues http://code.google.com/p/sfdc-wsc/issues/detail?id=25 long back on WSC Issue list. I am still waiting to hear from WSC team, please let me know.

Conclusion

Its good to see this effort from WSC team, to add recovering abilities to the API. But renewing session on session timeout or invalidation is one thing, there are many other failures (explained in this post), that can be retried and recovered in same way. So, I expect more of such retryable/recoverable error handling coming to WSC in near future.

Also, SFDC WSC team : Please add API “release notes” page some where on WWW !

November 10, 2010

HTTP Compression with Apache Axis, a huge performance boost !

As mentioned in my previous post, I was researching/benchmarking on how HTTP Compression with Apache Axis improves performance. The results I got post HTTP compression, are surprisingly amazing i.e. “response time of web service calls is reduced to one third and one forth in many cases”.

Though HTTP Compression is a generic topic, not related to Salesforce, but for my benchmarking, I used Salesforce SOAP web services.

Good news : I got a highly noticeable response time difference with each Partner, Enterprise, Apex and Metadata web service calls.

How to make HTTP Compression work in Axis (Salesforce)

Prerequisite – setup Classpath with dependencies

Apart from WSDL2Java classes for your partner, metadata etc WSDL. You need following jars in classpath.

  • axis.jar (I used Axis v1.4)
  • commons-httpclient-3.1.jar 
  • common-codec-x.jar (If you are getting this error http://bit.ly/9dBisn)
  • Other jars that are usually included when working with Salesforce Webservice + Apache Axis 1.4.  Like jaxrpc.jar, commons-lang-x.x.jar, commons-discovery-x.x.jar, wsdl4j-1.x.x.jar. All these dependencies are available with your axis 1.4 binary download. Check the “axis-1_4.zip\lib” folder.

Step 1 - Extend Axis Service to @override createCall() method

As explained in this post by Simon. We need to extend the WSDL2Java generated extension class to “org.apache.axis.client.Service” as shown below. In case of Salesforce partner.wsdl, this class is SforceServiceLocator.

import javax.xml.rpc.Call;
import javax.xml.rpc.ServiceException;
import org.apache.axis.transport.http.HTTPConstants;
import com.sforce.soap.enterprise.SforceServiceLocator;

public class SforceService extends SforceServiceLocator {
   public Call createCall() throws ServiceException {
      Call call = super.createCall();
      call.setProperty(HTTPConstants.MC_ACCEPT_GZIP, Boolean.TRUE);
      call.setProperty(HTTPConstants.MC_GZIP_REQUEST, Boolean.TRUE);
      return call;
   }
}

If you are working with other Salesforce WSDLs, then you have extend these classes in the exact same way. 

  • Apex WSDL : com.sforce.soap._2006._08.apex.ApexServiceLocator
  • Enterprise WSDL : com.sforce.soap.enterprise.SforceServiceLocator
  • Metadata WSDL : com.sforce.soap._2006._04.metadata.MetadataServiceLocator

Note: We just need to change “extends SforceServiceLocator” in above code snippet to these classes, rest of the code will remain the same.

Once you are done with the change then you client code needs, to use this extension class for creating the stubs, as shown below

SoapBindingStub stub = (SoapBindingStub) new SforceService().getSoap();
// prepare the stub by either making a login call 
// OR
// by setting headers for SessionId/ServerURL etc
QueryResult qr = stub.query("Select Id, FirstName, LastName from Contact");

// Similarly you can create stubs for Apex, Metadata and Enterprise WSDL 
// as shown below
// Apex WSDL
ApexBindingStub apexBinding = (ApexBindingStub) new SforceService().getApex();
// Metadata WSDL
MetadataBindingStub apexBinding = (MetadataBindingStub) new SforceService().getMetadata();
// Enterprise WSDL (looks same as Partner, but SoapbindingStub here is 
// under package com.sforce.soap.enterprise.SoapBindingStub
SoapBindingStub stub = (SoapBindingStub) new SforceService().getSoap();

Step 2 - Tell Axis to use “CommonsHTTPSender” instead of “HTTPSender”

One way to do that is create a config file named “client-config.wsdd”, as explained by Simon. Here is the relevant text from his blog post :

“you have to configure axis to use the vastly superior CommonsHTTPSender class rather than the default HTTPSender class as its transport, this is done by changing the transport entry in the client-config.wsdd file from java:org.apache.axis.transport.http.HTTPSender to java:org.apache.axis.transport.http.CommonsHTTPSender and adding Commons HTTP to the class path.”

You can Google around how to create a client-config.wsdd file for this. I usually hate creating config files, so here is an alternate approach if you want to achieve the same using following Java code (Add this code inline to some class that’s called on application startup or prior making SOAP calls)

// You need to include this static block
// in some startup class or just set the AxisProperties
// some where else.
static {
   AxisProperties.setProperty(
     EngineConfigurationFactory.SYSTEM_PROPERTY_NAME,
     CompressedEngineConfigurationFactory.class.getName());
}

public static class CompressedEngineConfigurationFactory implements
  EngineConfigurationFactory {

  public static EngineConfigurationFactory newFactory(Object param) {
    return new CompressedEngineConfigurationFactory();
  }

  public EngineConfiguration getClientEngineConfig() {
    BasicClientConfig cfg = new BasicClientConfig();
    cfg.deployTransport("http", new SimpleTargetedChain(
      new CommonsHTTPSender()));
    return cfg;
  }

  public EngineConfiguration getServerEngineConfig() {
    return null;
  }
}

That’s it guys, try making calls now. You have HTTP Compression “ON”.

Step 3 - Feeling the response time difference

To really feel, “how SOAP compression is great”, try benchmarking Salesforce web service calls that return huge response. For ex. a SOQL query that returns 2000+ records, or a heavy metadata call.

When not to use HTTP Compression ?

Http compression(GZIP) is good for web service calls working on “TEXT” request/response. If your web service call is returning something binary like ZIP files. I would suggest, don’t use HTTP compression on that, because that is already compressed.

So ideally, one needs to decide “When to turn on HTTP compression ?”, based on Web service Response Type.

Do “SFDC WSC API” needs HTTP Compression ?

What is SFDC WSC API ?

SFDC WSC API i.e. The Force.com Web Service Connector (WSC) is a high performing web service client stack implemented using a streaming parser. WSC also makes it much easier to use the Force.com API (Web Services/SOAP or Asynchronous/BULK API).

Http Compression with WSC !

Good news here is that, HTTP Compression is “ON” by default with WSC. So one needs to do no tweaks to get it with WSC. I must say, great job done by WSC team, the API is very easy to use and gives many hidden cool stuff !

If required, you can easily turn HTTP Compression “OFF” by calling

com.sforce.ws.ConnectorConfig.setCompression(false);

 

What do you say ?

Let me know, how Axis compression works for you. Would be interested in getting your feedback on this..!

November 8, 2010

HTTP Compression with Apache Axis for Salesforce Web Services !

Though, I am speaking a lot about using WSC above Apache Axis, but today I found an interesting old post about Http compression with Apache Axis. This is interesting because, it can boost performance for those who are integrating with Salesforce web services using Java Apache Axis. Here are some benchmarks copied Salesforce WIKI :

“Your request to the server is gzipped compressed (the MC_GZIP_REQUEST property), and the request advertises (via the Accept-Encoding http header) that it'll accept a gzipped response (the MC_ACCEPPT_GZIP property). In the case of an sforce call like Query which can return very large responses you can see some big decreases in message sizes, a quick test here shows that an uncompressed response of 376426 bytes compresses down to a measly 33617 bytes (approx 9% the original size)”

These results look great !

I haven’t tested it, but will start soon. Here are the pointers, if you want to start and give some feedback.

Though it seems there are couple of problems, as mentioned in the WIKI article and force.com blog comments. Still, I am sure this should be doable and stable now, as all of those comments are of year 2005 and SFDC API v6, we are on SFDC API v20 now Smile

Anyone already had hands on experience with this compression ? if YES, please share. I will write a followup post soon, about how my experiment with compression goes.

November 2, 2010

Understanding–“No such column on entity 'Name'” Error !

One can get errors like

“No such column 'SmallPhotoUrl' on entity 'Name'.” OR “No such column CompanyName' on entity 'Name'.”

on a SOQL statements like

  • SELECT CreatedBy.CompanyName, FeedPost.Body, Id, CreatedBy.Name FROM AccountFeed
  • SELECT CreatedBy.SmallPhotoUrl, FeedPost.Body, Id, CreatedBy.Name FROM AccountFeed
  • SELECT Id, FeedPost.CreatedBy.SmallPhotoUrl, (SELECT Id, CreatedBy.Name, CreatedBy.SmallPhotoUrl, CommentBody FROM FeedComments) FROM NewsFeed

The column responsible for this error is bold highlighted in above SOQL statements. The error is so confusing, you must be wondering that : “I queried on User(CreatedBy) relation, then why the field is expected to be their on entity ‘Name’ ?

Why this error is thrown for entity “Name” ?

Its because “CreatedBy” and many other Salesforce relations become “Polymorphic” if pointing to more than one type of object as parent. This is what Salesforce "Relationship Queries" doc says:

“A polymorphic key is an Id that can refer to more than one type of object as a parent. For example, either a contact or a lead may be the parent of a task. In other words, the WhoId field of a task may contain the Id of either a contact or a lead. If an object can have more than one type of object as a parent, the polymorphic key points to a Name object instead of a single object type.”

So, one can’t expect a single Sobject type fields for polymorphic relations/keys. Rather, check what fields are available in entity “Name”. That is why one can’t find User sobject’s fields like SmallPhotoURL and CompanyName on CreatedBy polymorphic relationships.

Note: Not all CreatedBy relationships are polymorphic it totally varies from sobject to sobject.

How to know if a relationship is Polymorphic ?

To know whether a relation is polymorphic, you can do either of following

  • User describeSObjects call, as described in section “Understanding Polymorphic Keys and Relationships” of Salesforce "Relationship Queries" doc
  • Use Eclipse > Schema browser and expand into the “relationship column > Type Data > Reference To”, as shown below : image

October 30, 2010

How to logout and use multiple Salesforce Orgs with Chatter Desktop !

Chatter Desktop client gives no clear way to logout from a Salesforce Org. This can be because it uses OAuth  internally to authorize with Salesforce. So this post if for you, if you want to

  • Logout yourself or End your Chatter Desktop session.
  • Work with multiple Salesforce orgs with Chatter Desktop.

Logout/End your session on Chatter Desktop

Though this should be rare requirement, as we always keep us logged in to Yahoo/Gtalk Messengers, unless we are working on some temporary office or public machine.

This is pretty easy to do, here are the steps.

  1. Login to your Salesforce org via web browser Smile
  2. Goto Setup > Personal Information page.
  3. On this page, locate a related list / section titled “Remote Access”.
  4. If you have authorized Chatter Desktop Client,  something similar to following screenshot should appear. If you see multiple entries here, please select the one, where “Application” column is having “Chatter Desktop” entry in it (same is shown in big red circle)image
  5. Next, hit the “Revoke” link, in the first column titled “Action”.

imageThat’s it, you are now logged out from the Chatter client. This is not a true logout, we just revoked the oauth authorization. So it leaves so loop holes behind, i.e.

This logout(Revoke) will come to effect on if the Chatter desktop client is closed and restarted. If Desktop client was launched before you revoked the rights, it will keep on working normally.

But on trying to use Chatter desktop on next restart, one will get error screen like the one on left.

 

 

 

 

Work with multiple Salesforce orgs on Chatter Desktop !

Here are the steps to do this.

  1. Click on the Options button, located at the top. And in the popup menu, select “Settings”, to get to the screen shown in next step. image
  2. This screen maintains connections to all of your Salesforce Production/DE/Sandbox orgs.  By default you will see just the default/selected connection and an additional unselected connection to a Sandbox. image
  3. To add a new Org/Connection, enter server name and url in text fields, as highlighted in the screen shot. Server name, can be any good name, that is easy to remember. Server URL can “https://login.salesforce.com” or “https://test.salesforce.com” for Sandbox orgs. Lets say I want to add new production or DE org. So I will use  “https://login.salesforce.com” and will hit the “Add” button.image 
  4. Next, we will see the updated Connection list, as shown below. Make sure the radio before the new org name in the connection list is selected. Selection this radio ensures, that on next run, Chatter desktop will ask user again for authorizing with a new Salesforce Org.image
  5. That’s it, you are all set now. Please restart the Chatter desktop client to see start adding new org. Any time you wish to switch back to some other org, select any other existing connection or create a new one.

Ideas & Comments

I wish, Chatter desktop client makes it simple to add new orgs. For ex. a drop down, right their in the main interface that list all existing connections and ability to add a new one.

What do you say ?

Recommended relevant reading about Chatter !

Salesforce Chatter Desktop client now available for download !

image

I was excited to see this update of Chatter Facebook page. Without any delays, I logged-in to my Salesforce org, to download chatter desktop client.

To install Chatter Desktop, GoTo :(Setup » Desktop Integration » Chatter Desktop).

Expectations set with Chatter Desktop Client

Chatter desktop download page has some interesting facts about the client, like

  • Receive automatic alerts when your feed gets updated
  • Update your status without going into your browser
  • Drag & drop files from your desktop right into Chatter

All features look good for first version of a desktop client. Receive automatic alerts was of prime interest for me, my expectation was something like yahoo messenger / google talk / Tweek Deck will popup on updates in chatter feed.

 

Chatter desktop experience

Chatter desktop’s setup was a small Adobe AIR setup file, it quickly downloaded and installed. On run, I saw this authentication screen, one can login to production or sandbox orgs. Chatter desktop uses Oauth to authorize with Salesforce. So you will see these 4 screens before the Chatter feed.

imageimageimageimage

imageUser interface shown next, is pretty clean >>>

As said by Salesforce, one can easily update status, upload files via drag/drop and comment on existing posts. I liked all of that, it was pretty easy and fast.

Enhancements expected from Chatter Desktop Client

I must say, it’s a good first version of Chatter desktop client. But for sure there is a lot of scope for improvements. Like :

  • A way to locate SObjects, I am following or I can follow. So we can have another tab like “SObjects”, that offers clean layout to give next level of filtering based on Account, Opportunities and Custom Objects names.
  • As of now, Chatter desktop throws user on web browser for almost everything expect comments and file upload. We can have some brief details about User(self/other) Profile & Sobject right in the client itself.
  • Any redirection to web browser, shouldn’t require login. As of now Chatter desktop URLs are not taking care of that.
  • I can’t see notifications working. Would love to see Tweet Deck style notifications with Chatter Desktop client too.
  • There should be clean way to logout, as of now their no clean way to logout and login to other org in Chatter desktop. I will explain, how to do so in other blog post.
  • Ability to login to multiple Salesforce org/accounts. Again I am Tweek deck fan, so having ability to login to multiple Salesforce Orgs at the same time will  help for sure.

What do you say ?

Do you feel enhancements mentioned in this post makes sense. If YES, please comment, we will groom them to SFDC IdeaExchange.

Recommended relevant reading about Chatter !

October 27, 2010

Tolerado WSC APIs upgraded to support SFDC Winter’11 Web Service API changes !

Since SFDC winter’11 release, I was updating the Tolerado WSC APIs. This update to Tolerado APIs was important because Winter’11 brought too many cool enhancements to the Web service API.

List of changes done.

Following are the changes done to Tolerado WSC APIs

1. Upgraded to latest WSC-API

SFDC WSC got a new release(wsc-20.jar) few weeks back, Tolerado was upgraded to use that.

2. Upgrade to latest SFDC API v20.0 WSDLs

All WSDL2Java stuff for each partner, enterprise, metadata and apex WSDL, was regenerated to latest API version i.e. 20.0. This is important so that one can take benefit of cool new features of Web Services API like

  • Multiple Object Type Support: Ability to process records for multiple objecttypes, including custom objects, in one create() or update() call. For example, you can create a contact and an account in one call. Previously, you could only process records for one object type in a call.
  • Better Transactional Control : The New AllOrNoneHeader SOAP Header, allows the create(), delete(), undelete(), update(), and upsert() calls to roll back all changes unless all records are processed successfully. The default behavior is to allow partial success of a call.
  • Increased Number of Relationships Allowed in a SOQL Query : With Winter '11, you can include 25 relationships in a SOQL query in all API versions. Previously, there was a limit
    of 20 relationships.
  • Chatter Photos in User object:  The User object includes new fields if Chatter is enabled:
    • FullPhotoUrl—The URL for a user's profile photo.
    • SmallPhotoUrl—The URL for a thumbnail of a user's profile photo.
    • DigestFrequency—The frequency at which Salesforce.com sends the user’s Chatter personal email digest.
  • More details in Winter’11 release notes for other new and changed objects etc.

3. New Tolerado API’s for AllOrNoneHeader support

ToleradoEnterpriseStub & ToleradoPartnerStub classes are enhanced, to have a direct call to set new AllOrNone header. So one no more needs to get into native SOAP bindings to add this header. Also added Junit tests to make sure the AllOrNone SOAP header changes are working correctly.

Here is a code sample that shows how to turn on “AllOrNone” setting.

 public void testRollBackOnContacts() throws Exception {
         ToleradoPartnerStub stub = new ToleradoPartnerStub(credential);
         //
         // Create a new Contact
         //
         SObject c1 = new SObject();
         c1.setType("Contact");
         String firstName = "Abhinav";
         String lastName = "Gupta-";
         c1.setField("FirstName", firstName);
         c1.setField("LastName", lastName);

         //
         // Create a new Contact, created without last name intentionally to fail
         //
         SObject c2 = new SObject();
         c2.setType("Contact");
         c2.setField("FirstName", "Abhinav1");

         // Using AllOrNoneHeader = true, to make the rollback happen
         stub.setAllOrNoneHeader(true);

         SaveResult[] saveResults = stub.create(new SObject[] { c1, c2 });
         Assert.assertNotNull(saveResults);
         Assert.assertEquals(2, saveResults.length);
         Assert.assertEquals(false, saveResults[0].getSuccess());
         Assert.assertNull(saveResults[0].getId());
         Assert.assertEquals(false, saveResults[1].getSuccess());
         Assert.assertNull(saveResults[1].getId());
   }

One can see Junit tests for each enterprise and partner wsdl as detailed code samples.

4. Latest Tolerado-WSC available in downloads

All code changes are in SVN and latest version of all tolerado and salesforce wsdl jar files etc is available in download area.

What about Tolerado for Apache Axis ?

I have left “Tolerado for ApacheAxis” upgrade intentionally(+to save my time Winking smile) because, I personally feel we should move to SFDC-WSC APIs for all better performance. Still if anyone is blocking/depending on Tolerado for Apache Axis and wants Winter’11 coolness, please let me know. I will do that upgrade to Tolerado-Axis stubs too.

October 20, 2010

Force.com IDE for Eclipse 3.6 Helios, now available !

I was pleased to see that Force.com IDE plugin for Eclipse 3.6(Helios) is now available. You can find the download/installation instructions here. Though there is nothing different to the installation process, you just need to add the same Eclipse-Galileo update site to Eclipse-Helios.

image

I am happy about this release, as I no more need to maintain two versions of Eclipse i.e.

  • Eclipse 3.5 (Galileo) for Force.com projects.
  • Eclipse 3.6 (Helios) for J2EE projects.

Great job force.com tools team. I know its hard to match and release with latest Eclipse versions.

References

October 12, 2010

Debugging Sites Authorization Required Error !

Force.com sites redirects to “Authorization Required” page in case something goes wrong behind the scenes, for ex.
  • The Site’s public access settings or user profile doesn’t have access to a Page, Object, field etc used in the visualforce page / controller.
  • In case of Apex Exceptions like, LimitException.
  • Etc
“Unauthorized” page makes sense in case of missing access problem. But in case of Exceptions ideally the redirect should be the “Exception” page.
End user obviously can’t figure out anything by seeing the page. So how should developers debug this problem ?

Debugging the cause of Authorization required error.

Test  Fixture

To reproduce this problem, easily for all. I just created a super simple VF page. This VF page fails for Authorization required error, because it tried to do “DML” inside the Controller’s constructor. Details of both page and controller are available in code snippets below.
VF Page
<apex:page controller="MyPageController">
    <apex:outputLabel for="contactName" value="Created Contact :"></apex:outputLabel>
    <apex:outputField id="contactName" value="{!contact.Name}"/>                    
</apex:page>
Controller
public class MyPageController {
    public  Contact contact {get;set;}
  
    public MyPageController () {        
     // We are not allowed to do DML in constructor.
  // So this should reproduce the Autorization error on sites
  // pretty easily
        contact = new Contact(FirstName='Failing', LastName ='Contact'); 
        insert contact;
    }
           
}
On executing this page with sites, you will get “Authorization Required” error, as shown:
image
Next we will see approaches to debug the cause of this issue.

Debug Approach 1

The first approach to debug this problem would be to 
  • Enable debugging for “Sites User”, under Setup > Monitoring > Debug Logs.
  • Refresh the page failing for “Authorization” error.
  • Check what comes in debug logs.
The above approach will work most of the time and will let developers know, why “Authorization Required” page is shown. In our case, debug logs clearly say “DML currently not allowed”, as shown in screen shot below.
image
But sometimes on “Authorization” error no debug logs are generated, even if you have enabled debug logging for the user. In that case jump to Approach 2, described below.

Debug Approach 2

Login in your Salesforce org. Make sure you have turned on “Development Mode” under “Setup > Personal Information > Development Mode”.  Try running the same Visualforce page, without the sites domain i.e. execute the page just like any other visualforce page for ex.
"https://<Node>.visual.force.com/apex/<Sites Page Name>”
As development mode is on, one should see the error cause on the page itself. As shown in screen shot below
image
Still, if you can’t see any error on the visualforce page, jump to Approach 3 described  below:

Debug Approach 3

In this approach we will create another sites page, that calls the failing sites page via Apex API, i.e.
“Page.mypage.getContent().toString()”
Lets call that sites visualforce page “Error Finder”. Following is the visualforce + apex code for this new page.
Visualforce Page – ErrorFinder
<apex:page controller="ErrorFinderController"  action="{!fetchFailingPage}" showHeader="false" sidebar="false" >
    <apex:outputText id="failingPageResponse" escape="false" value="{!failingPageResponse}" />
</apex:page>
Apex Controller – ErrorFinderController
public class ErrorFinderController {
    public String failingPageResponse { get; set; }
    
    public void fetchFailingPage() {
       try {
           // Make a call to failing sites page here
           failingPageResponse = Page.mypage.getContent().toString();
       } catch (Exception e) {
           failingPageResponse = e.getTypeName() + ' : ' + e.getMessage() ;
       }       
    }   
}
On executing this page after connecting with sites, you will see why sites page “mypage” was showing Authorization required error. Here is the screenshot of the errorfinder sites page:
image
More over you can also try “Debug Approach 2” described above, i.e. looking into debug logs at “Setup > Monitoring > Debug Logs” for the sites user. You will get better details of error, if debug logs are available for the failing “mypage”.

More ideas/ways you know ?

Please share any thoughts or better ideas to know the cause of such sites page errors.


October 8, 2010

Apex Test data isolation from Org/User’s data.. !

The key to write a good apex test case is isolate test-data from actual org/user data. If your test case in anyway depends on org data, then it will fail for sure in deployments across different Salesforce orgs.

Unfortunately Apex tests run in SYSTEM mode (The permissions and record sharing of the current user are not taken into account), so their is no isolation from the org/user’s data.

How to Isolate test-data from org’s real data ?

  • All your apex code should declare classes as “with sharing”, unless you really want to access all of the org data. This is really important to ensure sharing rules work correct. In case you need to access all org data i.e. by pass sharing rules, then I suggest creating a new top level or nested class with “without sharing” keywords before class name. This without sharing class should be used to fire all such SOQLs, that need to by pass sharing.
  • Using System.runAs(User) one can create some isolation, this is explained in detail here . But, System.runAs() is effective only if :
    • All Sobjects used in Test case are having “Private” sharing access. But that is not possible and real scenario.
    • Test User profile has no profile overrides on sharing rules, like “Modify All Data” or “Modify/View All” permissions for Sobjects used in Test cases.

So, its pretty hard to ensure that test cases will go good all the times. They will certainly fail for bad combination of sharing rules, profile permissions and org data.

So, how to write stable Apex code + Apex Tests ?

The only good way I found is

“you non-test apex code(trigger/controller) should handle test execution smartly”

This means, one has to write the trigger/controller code to filter records more specifically for current user, (if possible) when running in test mode. One can do this by just doing things

  1. All test code should use System.runAs(<Mock User>) for creating quality test data. Note, here creating a mock user, who doesn’t already exists in system is important for isolation. As if you use some existing user, you might be able to see records owned by him/her. How to do so is explained in this post.
  2. Adding this criteria to all SOQL calls “WHERE OwnerId =:UserInfo.getUserId()” when Controller/Trigger is executed from Test Context. When this criteria is in place, only the test data will be visible to trigger/controller code.

Next, in code samples below, we will try to show how one can implement these above two points in Apex.

Code Sample

This the sample code fixture consists of:

  • A simple custom SObject named “TestObj__c” with “Private” Org wide sharing access. This Sobject is just having a Text field named “SomeTextField”.
  • An apex class named “MyClass”, it can be related to any thing i.e. trigger or a visualforce controller. This class
    • tries to query custom object TestObj__c for a criteria.
    • has configuration attributes to tell, if the class is executing in test context.
  • An apex test class that is written for MyClass. It
    • uses System.runAs etc to ensure tests run correctly in all orgs.
    • creates some TestObj__c records, for testing the MyClass’s query.

MyClass Code

Please note this class’s attributes like isRunningTest, this attribute is required until Salesforce winter’11 release is GA, as winter’11 will give System.isRunningTest() method, that can be used anywhere in test code to know if the code is running in test context. 

public with sharing class MyClass {
    public TestObj__c [] objs {get;set;}
   // Should be set to true, by Apex test cases only
   public boolean isRunningTest = false;    
    private Id contextUserId = Userinfo.getUserId();
       
    public void init() {
       String soql = 'select Id, SomeTextField__c from TestObj__c where SomeTextField__c like \'Gupta\'';
        objs = Database.query(prepareTestSOQL (soql));
    }    
    
    private String prepareTestSOQL (String soql) {
       // after winter'11 we can use System.isRunningTest here
       if (isRunningTest)
         return soql.replaceAll('where', 'where OwnerId =:contextUserId and ');
      else
         return soql;       
    }
}

TestMyClass Code

@isTest
private class TestMyClass{
    public static testMethod void testInit() {
       // Query Standard User or what ever profile best for Test Case
        Profile p = [SELECT Id FROM profile WHERE name='Standard User'];
        // Create a in-memory mock user for running tests in limited data access
        // context
        User mockUser = new User(alias = 'newUser', email='newuser@testorg.com',
        emailencodingkey='UTF-8', lastname='Testing', 
        languagelocalekey='en_US', localesidkey='en_US', profileid = p.Id,
        timezonesidkey='America/Los_Angeles', username='newuser@testorg.com');
      
        System.runAs(mockUser) {    
          // Create 2 test records
          TestObj__c c1 = new TestObj__c (SomeTextField__c='Gupta');
          TestObj__c c2 = new TestObj__c (SomeTextField__c='Gupta');
          insert new TestObj__c[]{c1, c2};
          
          MyClass mycls = new MyClass();
          mycls.isRunningTest = true;
          mycls.init();
        // Now this assertion, should never fail
        // as we are restricting the access in main
        // apex code using Owner Id
          System.assertEquals(2, mycls.objs.size());
        }        
    }
}

Do we have a better way to write Apex Tests ?

I know the above approach and code sample is messy and looks wierd, but this is what I can figure out to make sure that test cases run without crashing across the orgs and multiple deployments. I am sure its not possible to do such owner id replacements always, this can be because of many reasons like

  • Project is too big and has many complex SOQLs.
  • For some reasons we can’t add the ownerid filter in SOQL where clause.

So, if you have any better ideas and ways to crack this problem. Please share with me.

New Idea - Apex tests shouldn’t get access to any org’s data !

So is their a way, really to isolate test cases from Salesforce Org data ? I think no body needs to access org’s user data in apex test cases. Test cases should always run in isolation and their should be no way for them to access what’s the user data. This is because, a single force.com app can be installed in many salesforce orgs, if the test cases rely on org data then they will for sure fail any where because of too much or too less data.

I have posted new idea on Idea Exchange, so that this isolation can be given by salesforce to us in coming releases. If you feel, I am correct and this makes some sense. Then please promote this idea.

October 5, 2010

Winter’11 Setup/Logout in dropdown, inspired from Facebook ?

Winter’11 gave an interesting new location to popular links like “Setup” and “Logout”. They are no longer one click available, you have to click your login name in new interface header to see these links. In first appearance I thought its fine. But over the time when I was working in my winter’11 pre-release org and sandbox orgs. I found it little annoying to make 2 clicks to access “Setup” & “Logout”. 

Dropdown inspiration from Facebook !

We are habitual on one click logout, even the same stands true for links like “Settings” which can be related to “Setup” link of Salesforce. Most of the popular sites like twitter, gmail etc give one click access to logout and settings link. Only exception to this is FACEBOOK, which hides logout and settings link under a dropdown. Following pic tries to relate Salesforce dropdown to the Facebook one.

image

Why this dropdown is sensible on Facebook ?

This looks sensible with Facebook, as we rarely click on any “Settings” link, we are too busy to even read the complete news feed ;-) For me “logout” link is the same story, Chrome(browser) remembers me on Facebook forever. If I ever logout or need to re-login on facebook, I have to do “forget password” get recover my Facebook password :-D. So for Facebook perspective, having these links in a drop-down seems good UI decision and saves some real state too.

Why this dropdown is NOT sensible on Salesforce ?

In Salesforce, story is very very different from Facebook. Here is how :

  • We need to click “Setup” too often. This is specially true for developers and admins. So its not like Facebook, where many users doesn’t even understand how much they can do with Settings.
  • We need to “Logout” many times, I usually work on 5-6 different Salesforce orgs in a day, across many projects. Again, its not like Facebook, where you can remember your self forever in a browser.

Views & Ideas of Salesforce community on Winter’11 Dropdown.

Following are some tweets, that strengthen my feeling about issues with new winter’11 UI.

@TehNrd created a GreaseMonkey script to open the drop-down on hover, so saves the extra click. This can be a good idea for Salesforce to make it default behavior. For more details click here.

So its clear that people really loved the original “Setup” & “Logout” links, no body wants a drop-down. Their is even an idea posted on IdeaExchange, to “Bring the Setup link back out of the name dropdown”.  Please promote it, you know we want the links out of the drop-down !

October 4, 2010

Playing with Visualforce $Action Global Variable

Recently, I stumbled upon Visualforce $Action tag. My requirement was :

  • To open the standard “List” page of an Sobject from Visualforce page.
  • To open “New” Contact page from Visualforce page.

Seems too simple :)

I know $Action tag was the way, so I jumped to the “Visualforce docs for Global Variables”. But can’t find any good code sample at this page, only one sample that’s available is for opening new Account page ($Action.Account.New). So I started searching for some sample with Visualforce documentation, found a couple of good links like :

Still I was struggling to open “New” Contact page, based on what I understood from Account code sample in “Visualforce docs for Global Variables”.  I was trying following code snippet to open it in similar fashion.

<apex:outputLink value="{!URLFOR($Action.Contact.New)}">
    Create New Contact
</apex:outputLink>

This didn’t worked, so have to jump on force.com forums for any solution. Luckily I found this link/solution, it clearly states

“This is the syntax you want: {!URLFOR($Action.Contact.NewContact)}

If you're having problems figuring out the name of an action go to Setup -> Customize -> Contacts -> Buttons and Links and look in the "Name" column for the action you want.

I wish the above solution in green is available in original “Visualforce docs for Global Variables”. It was so confusing to have different Action names for even standard objects like Account and Contact.

We need more code samples on $Action

Even after the above solution, I found that every $Action has some dependencies on params etc. For ex.

  • You need to pass in ObjectType with “List” Action : URLFOR($Action.CustomSobject__c.List,  $ObjectType.CustomSobject__c)
  • You need to pass in Object Id to “View” Action : URLFOR($Action.CustomObject__c.View, 'a00900000016iUl')
  • Action to open new Contact is “$Action.Contact.NewContact”, whereas the same for Account is “$Action.Account.New”
  • Similarly, their can be many such examples and special cases.

Lets collect $Action code snippets.. !

Because of many such options with $Action, I thought of creating a centralized collection of all such $Action possibilities & code snippets. This can for sure help other Visualforce developers. For that I started creating some code samples at snipplr.com under tag “visualforce-action-var”.

If you have any more cool samples around $Action, please share on snipplr.com with tag: “visualforce-action-var”.

References

October 2, 2010

Editing Custom Labels in Force.com IDE !

Custom Labels are key to create multilingual Salesforce apps. Developers usually move their page/class to Custom Labels in two steps

  1. The first cut of the page/class is developed using hard coded English labels & messages. This helps in speeding up development time, as switching between IDE & “Custom Label” UI, for each label and message for sure slows development speed.
  2. In second cut, developers usually scan all the pages and classes for any hardcoded English labels/messages. Custom Label is created for each such hardcoded label/message and replacements are done with the Custom Label full api name.

Though this approach speeds the development time, still I feel creating custom labels from UI is time consuming. So to save time, I suggest use Force.com IDE(Eclipse) to directly update/create new labels, and replace the hard coded English text.

How to get Custom Labels in Force.com IDE ?

By default Custom Labels are not downloaded into Force.com project. How to get custom labels into your project depends, if

  • You are creating a new force.com project, or
  • You’re working on existing force.com project

Getting Labels in New Force.com Projects !

In new Force.com project wizard, after entering login/pass you will land up on following screen. Select second option “Selected metadata components:” and hit “Choose” button, this will open a dialog to select metadata components.

 image

In the next dialog, together with classes, pages, resources & triggers etc, make sure “CustomLabels” is selected as shown below. Selecting “CustomLabels” will download them to your force.com project.

image

After completing the above wizard, you will see new source folder named “labels” in your force.com project, as shown below (in red circle). Notice, their is new XML resource named “CustomLabels.labels” in  your force.com project. This is the one, we will use for editing/creating custom labels.

image 

Getting Labels in Existing Force.com Projects !

In case you already working on a force.com project, you can still get “Custom Labels” resource in your project. Here are the steps

  1. Go to Navigator or Project/Package Explorer and right click the force.com project to which you want to add Custom Labels.
  2. In the popup menu, select Force.com and in the next sub-popup menu select “Add/remove metadata components”, as shown below: image
  3. In the next dialog, hit “Add/Remove” button to open the Metadata Selection Dialog image 
  4. Again, as with new force.com project, ensure that “labels”>”CustomLabels” is selected. As shown below:image
  5. On completing this and next dialogs, you will be prompted for project refresh(as shown below). Hit “Yes” button image
  6. After completing the above wizard, you will see new source folder named “labels” in your force.com project, as shown below (in red circle). Notice, their is new XML resource named “CustomLabels.labels” in  your force.com project. This is the one, we will use for editing/creating custom labels.

    image 

Manipulating Labels from Force.com IDE !

To start open the resource “CustomLabels.labels” in Force.com IDE. You will see XML editor with all your custom labels. For demoing in this post, I previously created one custom label from UI, so my XML looks like this :

<?xml version="1.0" encoding="UTF-8"?>
<CustomLabels xmlns="http://soap.sforce.com/2006/04/metadata">
    <labels>
        <fullName>foo_screen_title</fullName>
        <categories>titles</categories>
        <language>en_US</language>
        <protected>true</protected>
        <shortDescription>foo screen title</shortDescription>
        <value>My FOO Screen Title</value>
    </labels>
</CustomLabels>

As you can see this XML structure is pretty simple, you will get a <labels> tag per Custom Label. The key attributes here are

  • Full Name : This is used in API like Visualforce($Label.foo_screen_title) and Apex(System.Label.foo_screen_title) for referring the custom label. You can change this value, by editing text inside the <fullName>…</fullName> tag.
  • Value  : This is the default value displayed for custom label. You can change this value, by editing text inside <value>…</value> tag

Edit custom labels via Force.com IDE

To edit you can change any value inside of the <labels> tag. Once you are done, save CustomLabels.labels file to replicate the changes in your org.

Note : Changing <fullName> of existing label, will create a new label for that name.

Create new custom labels via Force.com IDE

For ex. if I need a new custom label named “bar_screen_title” with value “My BAR Screen Title”, I can just copy the “foo_screen_title” <labels> XML tag from above example and create a new one with attributes required, as shown below :

<?xml version="1.0" encoding="UTF-8"?>
<CustomLabels xmlns="http://soap.sforce.com/2006/04/metadata">
    <labels>
        <fullName>foo_screen_title</fullName>
        <categories>titles</categories>
        <language>en_US</language>
        <protected>true</protected>
        <shortDescription>foo screen title</shortDescription>
        <value>My FOO Screen Title</value>
    </labels>
    <labels>
        <fullName>bar_screen_title</fullName>
        <categories>titles</categories>
        <language>en_US</language>
        <protected>true</protected>
        <shortDescription>bar screen title</shortDescription>
        <value>My BAR Screen Title</value>
    </labels>
</CustomLabels>

Just save this XML file to replicate the new labels in your Salesforce org.

Note

  • Refresh the CustomLabels.labels resource, before making any change and after saving this file. Salesforce re-organizes the xml some times, so its good to always work on latest from Salesforce.
  • If you haven’t created any Custom Labels, you will get no <labels> tag to use as template in “CustomLabels.labels” resource. So I recommend creating at least one via salesforce web interface.

Benefits of having Custom Labels in Force.com IDE !

  • You can text search the “CustomLabels.labels” xml with IDE. Searching for required labels and peeking into details is time consuming on web interface.
  • You can edit/create labels and copy the full api names quickly to your Visualforce and Apex code.
  • Easy to copy multiple labels quickly from one Org to other. You can just open the labels xml file for both org and do a cross org copy/paste of labels easily.
  • Its much faster the web interface to work on labels, specially changing and creating multiple labels at once.

 

Have more thoughts and tips/tricks on this topic, please comment !!

September 22, 2010

Deep Dive - Static Context in Visualforce Apex Controllers !

Apex static is always confusing for me, I am from Java background, so it took a while for me to really understand differences between Apex vs Java static. This post discusses apex controller static behavior, i.e. in relation to Visualforce only. Here by Apex Controller static, I mean static variables/blocks declared in controller associated with a Visualforce page.

The Apex STATIC context – Variables & Code initialization blocks !

(Intermediate/Advanced Apex developers can skip this section)

Apex gives static context in form of static variables and static blocks. Most of developers from Java background understand the static block, but those who are ramping up from PHP etc, please go thru this topic on static in Salesforce Docs :

Apex VF Controller Static – Common MYTHs !

Developers, specially from Java background assume, that static variables once initialized on first class load, can be shared/updated across multiple HTTP requests. This typically goes with Java classes. But this is not true at all with Apex, never expect to set some value in Apex static variable and expect it back in next request, even next Ajax request. On every new request, you will find static variables re-initialized to the value declared or updated in static blocks.

Then, what is STATIC in Apex Controller ? – Real Story !

In general as per Salesforce docs, this is definition of static.

Static variables are only static within the scope of the request. They are not static across the server, or across the entire organization.

This definition is a one liner, but it applies well on every Apex static context. The thumb rule to understand static in Apex controller is

Static Variables and Blocks are re-executed on each User HTTP Request or Visualforce Ajax Request

Please NOTE that, the static variables/block are re-executed for Ajax requests generated via Visualforce i.e. by actionFunction, actionPoller, commandLink or commandButton tags etc. You must be wondering Whyyy ? This is because HTTP is stateless protocol, Visualforce only maintains view state(as hidden input field) to re-store all non-transient instance level variables in Apex Controller. Static variables are never stored in view state, as said in Salesforce docs clearly :

Static variables aren't transmitted as part of the view state for a Visualforce page.

So to re-store all static stuff back, force.com platform recreates all static variables and executes all static block on each normal or ajax http request. So thats why one can’t share data across the requests via static variables, they are always recreated first on each request(VF Ajax request too)

Apex Static, and the mind set change

For programmers from other backgrounds like J2EE, PHP etc, its a mindset change because:

  • JVM(Java Virtual Machine) usually don’t reload classes. A Java class is loaded once in memory usually stays till container is UP. Same stands true with static variables in Java too, all information kept in static context is available through out the application across different user sessions etc.
  • J2EE & Frameworks like Struts, create a Session per user login like Salesforce. But that session is available to multiple requests via Cookies etc and acts as good mini container to store logged in user specific information.

But these both Java approaches are memory hogs and not scalable to multiple users, that’s why J2EE containers have complex session and other clustering mechanisms to scale for huge enterprise apps.

So, having static in this manner is important for success of multitenant nature of force.com platform. As force.com is multitenant, multiple customer orgs, with multiple users share the same hardware resources like CPU, RAM(Memory). If Apex static was like Java, then I can’t imagine how much memory would be required by force.com servers to match the current load. I am sure, they can’t scale !

So, are Static variables good for anything in Apex Controllers ?

As, static variables are not part of view state. One can consider static as “C” language CONST, use them to declare constants in Apex.

Next …

In my next post, I will discuss Apex static context in Triggers.  Would love to discuss your ideas/views on Apex Controller static context, please comment !!