Oh my god. It's full of code!

Posts tagged “apex

Dynamic Apex Invocation/Callbacks

So I’ve been working on that DeepClone class and it occurred to me that whatever invokes that class might like to know when the process is done (so maybe it can do something with those created records). Seeing as the DeepClone is by it’s very nature asynchronous that presents a problem, since the caller cannot sit and wait for process to complete. You know what other language has to deal with async issues a lot? Javascript. In Javascript we often solve this problem with a ‘callback’ function (I know callbacks are old and busted, promises are the new hotness but bare with me here), where in you call your asynchronous function and tell it what to call when it’s done. Most often that is done by passing in the actual function code instead of just the name, but both are viable. Here is an example of what both might look like.

var someData = 'data to give to async function';

//first type of invocation passes in an actual function as the callback. 
asyncThing(someData,function(result){
	console.log('I passed in a function directly!' + result);
});

//second type of invocation passes in the name of a function to call instead
asyncThing(someData,'onCompleteHandler');

function onCompleteHandler(result)
{
	console.log('I passed in the name of a function to call and that happened' + result);
}

function asyncThing(data,callback)
{
	//async code here, maybe a callout or something.
	var data = 'probably  a status code or the fetched data would go here';
	
	//if our callback is a function, then just straight up invoke it
	if(typeof callback == 'function')
	{
		callback(data);
	}
	//if our callback is a string, then dynamically invoke it
	else if(typeof callback == 'string')
	{
		window[callback](data);
	}
}

So yeah, javascript is cool, it has callbacks. What does this have to do with Apex? Apex is strongly typed, you can’t just go around passing around functions as arguments, and you sure as hell can’t do dynamic invocation… or can you? Behold, by abusing the tooling api, I give you a basic implementation of a dynamic Apex callback!

public HttpResponse invokeCallback(string callback, string dataString)
{
	HttpResponse res = new HttpResponse();
	try
	{
		string functionCall = callback+'(\''+dataString,',')+'\');';
		HttpRequest req = new HttpRequest();
		req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
		req.setHeader('Content-Type', 'application/json');
		string instanceURL = System.URL.getSalesforceBaseUrl().getHost().remove('-api' ).toLowerCase();
		String toolingendpoint = 'https://'+instanceURL+'/services/data/v28.0/tooling/executeAnonymous/?anonymousBody='+encodingUtil.urlEncode(functionCall,'utf-8');
		req.setEndpoint(toolingendpoint);
		req.setMethod('GET');
		
		Http h = new Http();
		res = h.send(req);
	}
	catch(exception e)
	{
		system.debug('\n\n\n\n--------------------- Error attempting callback!');
		system.debug(e);
		system.debug(res);
	}
	return res;
} 

What’s going on here? The Tooling API allows us to execute anonymous code. Normally the Tooling API is for external tools/languages to access Salesforce meta-data and perform operations. However, by accessing it via REST and passing in both the name of a class and method, and properly encoding any data you’d like to pass (strings only, no complex object types) you can provide a dynamic callback specified at runtime. We simply create a get request against the Tooling API REST endpoint, and invoke the execute anonymous method. Into that we pass the desired callback function name. So now when DeepClone for example is instantiated the caller can set a class level property of class and method it would like called when DeepClone is done doing it’s thing. It can pass back all the Id’s of the records created so then any additional work can be performed. Of course the class provided has to be public, and the method called must be static. Additionally you have to add your own org id to the allowed remote sites under security->remote site settings. Anyway, I thought this was a pretty nice way of letting your @future methods and your queueable methods to pass information back to a class so you aren’t totally left in the dark about what the results were. Enjoy!


Deep Clone (Round 2)

So a day or two ago I posted my first draft of a deep clone, which would allow easy cloning of an entire data hierarchy. It was a semi proof of concept thing with some limitations (it could only handle somewhat smaller data sets, and didn’t let you configure all or nothing inserts, or specify if you wanted to copy standard objects as well as custom or not). I was doing some thinking and I remembered hearing about the queueable interface, which allows for asynchronous processing and bigger governor limits. I started thinking about chaining queueable jobs together to allow for copying much larger data sets. Each invocation would get it’s own governor limits and could theoretically go on as long as it took since you can chain jobs infinitely. I had attempted to use queueable to solve this before but i made the mistake of trying to kick off multiple jobs per invocation (one for each related object type). This obviously didn’t work due to limits imposed on queueable. Once I thought of a way to only need one invocation per call (basically just rolling all the records that need to get cloned into one object and iterate over it) I figured I might have a shot at making this work. I took what I had written before, added a few options, and I think I’ve done it. An asynchronous deep clone that operates in distinct batches with all or nothing handling, and cleanup in case of error. This is some hot off the presses code, so there is likely some lingering bugs, but I was too excited not to share this. Feast your eyes!

public class deepClone implements Queueable {

    //global describe to hold object describe data for query building and relationship iteration
    public map<String, Schema.SObjectType> globalDescribeMap = Schema.getGlobalDescribe();
    
    //holds the data to be cloned. Keyed by object type. Contains cloneData which contains the object to clone, and some data needed for queries
    public map<string,cloneData> thisInvocationCloneMap = new map<string,cloneData>();
    
    //should the clone process be all or nothing?
    public boolean allOrNothing = false;
    
    //each iteration adds the records it creates to this property so in the event of an error we can roll it all back
    public list<id> allCreatedObjects = new list<id>();
    
    //only clone custom objects. Helps to avoid trying to clone system objects like chatter posts and such.
    public boolean onlyCloneCustomObjects = true;
    
    public static id clone(id sObjectId, boolean onlyCustomObjects, boolean allOrNothing)
    {
        
        deepClone startClone= new deepClone();
        startClone.onlyCloneCustomObjects  = onlyCustomObjects;
        startClone.allOrNothing = allOrNothing;
        
        sObject thisObject = sObjectId.getSobjectType().newSobject(sObjectId);
        cloneData thisClone = new cloneData(new list<sObject>{thisObject}, new map<id,id>());
        map<string,cloneData> cloneStartMap = new map<string,cloneData>();
        
        cloneStartMap.put(sObjectId.getSobjectType().getDescribe().getName(),thisClone);
        
        startClone.thisInvocationCloneMap = cloneStartMap;
        return System.enqueueJob(startClone);      
    }
    
    public void execute(QueueableContext context) {
        deepCloneBatched();
    }
        
    /**
    * @description Clones an object and the entire related data hierarchy. Currently only clones custom objects, but enabling standard objects is easy. It is disabled because it increases risk of hitting governor limits
    * @param sObject objectToClone the root object be be cloned. All descended custom objects will be cloned as well
    * @return list<sobject> all of the objects that were created during the clone.
    **/
    public list<id> deepCloneBatched()
    {
        map<string,cloneData> nextInvocationCloneMap = new map<string,cloneData>();
        
        //iterate over every object type in the public map
        for(string relatedObjectType : thisInvocationCloneMap.keySet())
        { 
            list<sobject> objectsToClone = thisInvocationCloneMap.get(relatedObjectType).objectsToClone;
            map<id,id> previousSourceToCloneMap = thisInvocationCloneMap.get(relatedObjectType).previousSourceToCloneMap;
            
            system.debug('\n\n\n--------------------  Cloning record ' + objectsToClone.size() + ' records');
            list<id> objectIds = new list<id>();
            list<sobject> clones = new list<sobject>();
            list<sObject> newClones = new list<sObject>();
            map<id,id> sourceToCloneMap = new map<id,id>();
            list<database.saveresult> cloneInsertResult;
                       
            //if this function has been called recursively, then the previous batch of cloned records
            //have not been inserted yet, so now they must be before we can continue. Also, in that case
            //because these are already clones, we do not need to clone them again, so we can skip that part
            if(objectsToClone[0].Id == null)
            {
                //if they don't have an id that means these records are already clones. So just insert them with no need to clone beforehand.
                cloneInsertResult = database.insert(objectsToClone,allOrNothing);

                clones.addAll(objectsToClone);
                
                for(sObject thisClone : clones)
                {
                    sourceToCloneMap.put(thisClone.getCloneSourceId(),thisClone.Id);
                }
                            
                objectIds.addAll(new list<id>(previousSourceToCloneMap.keySet()));
                //get the ids of all these objects.                    
            }
            else
            {
                //get the ids of all these objects.
                for(sObject thisObj :objectsToClone)
                {
                    objectIds.add(thisObj.Id);
                }
    
                //create a select all query to get all the data for these objects since if we only got passed a basic sObject without data 
                //then the clone will be empty
                string objectDataQuery = buildSelectAllStatment(relatedObjectType);
                
                //add a where condition
                objectDataQuery += ' where id in :objectIds';
                
                //get the details of this object
                list<sObject> objectToCloneWithData = database.query(objectDataQuery);
    
                for(sObject thisObj : objectToCloneWithData)
                {              
                    sObject clonedObject = thisObj.clone(false,true,false,false);
                    clones.add(clonedObject);               
                }    
                
                //insert the clones
                cloneInsertResult = database.insert(clones,allOrNothing);
                
                for(sObject thisClone : clones)
                {
                    sourceToCloneMap.put(thisClone.getCloneSourceId(),thisClone.Id);
                }
            }        
            
            for(database.saveResult saveResult :  cloneInsertResult)
            {
                if(saveResult.success)
                {
                    allCreatedObjects.add(saveResult.getId());
                }
                else if(allOrNothing)
                {
                    cleanUpError();
                    return allCreatedObjects;
                }
            }
              
            //Describes this object type so we can deduce it's child relationships
            Schema.DescribeSObjectResult objectDescribe = globalDescribeMap.get(relatedObjectType).getDescribe();
                        
            //get this objects child relationship types
            List<Schema.ChildRelationship> childRelationships = objectDescribe.getChildRelationships();
    
            system.debug('\n\n\n-------------------- ' + objectDescribe.getName() + ' has ' + childRelationships.size() + ' child relationships');
            
            //then have to iterate over every child relationship type, and every record of that type and clone them as well. 
            for(Schema.ChildRelationship thisRelationship : childRelationships)
            { 
                          
                Schema.DescribeSObjectResult childObjectDescribe = thisRelationship.getChildSObject().getDescribe();
                string relationshipField = thisRelationship.getField().getDescribe().getName();
                
                try
                {
                    system.debug('\n\n\n-------------------- Looking at ' + childObjectDescribe.getName() + ' which is a child object of ' + objectDescribe.getName());
                    
                    if(!childObjectDescribe.isCreateable() || !childObjectDescribe.isQueryable())
                    {
                        system.debug('-------------------- Object is not one of the following: queryable, creatable. Skipping attempting to clone this object');
                        continue;
                    }
                    if(onlyCloneCustomObjects && !childObjectDescribe.isCustom())
                    {
                        system.debug('-------------------- Object is not custom and custom object only clone is on. Skipping this object.');
                        continue;                   
                    }
                    if(Limits.getQueries() >= Limits.getLimitQueries())
                    {
                        system.debug('\n\n\n-------------------- Governor limits hit. Must abort.');
                        
                        //if we hit an error, and this is an all or nothing job, we have to delete what we created and abort
                        if(!allOrNothing)
                        {
                            cleanUpError();
                        }
                        return allCreatedObjects;
                    }
                    //create a select all query from the child object type
                    string childDataQuery = buildSelectAllStatment(childObjectDescribe.getName());
                    
                    //add a where condition that will only find records that are related to this record. The field which the relationship is defined is stored in the maps value
                    childDataQuery+= ' where '+relationshipField+ ' in :objectIds';
                    
                    //get the details of this object
                    list<sObject> childObjectsWithData = database.query(childDataQuery);
                    
                    system.debug('\n\n\n-------------------- Object queried. Found ' + childObjectsWithData.size() + ' records to clone');
                    
                    if(!childObjectsWithData.isEmpty())
                    {               
                        map<id,id> childRecordSourceToClone = new map<id,id>();
                        
                        for(sObject thisChildObject : childObjectsWithData)
                        {
                            childRecordSourceToClone.put(thisChildObject.Id,null);
                            
                            //clone the object
                            sObject newClone = thisChildObject.clone();
                            
                            //since the record we cloned still has the original parent id, we now need to update the clone with the id of it's cloned parent.
                            //to do that we reference the map we created above and use it to get the new cloned parent.                        
                            system.debug('\n\n\n----------- Attempting to change parent of clone....');
                            id newParentId = sourceToCloneMap.get((id) thisChildObject.get(relationshipField));
                            
                            system.debug('Old Parent: ' + thisChildObject.get(relationshipField) + ' new parent ' + newParentId);
                            
                            //write the new parent value into the record
                            newClone.put(thisRelationship.getField().getDescribe().getName(),newParentId );
                            
                            //add this new clone to the list. It will be inserted once the deepClone function is called again. I know it's a little odd to not just insert them now
                            //but it save on redudent logic in the long run.
                            newClones.add(newClone);             
                        }  
                        cloneData thisCloneData = new cloneData(newClones,childRecordSourceToClone);
                        nextInvocationCloneMap.put(childObjectDescribe.getName(),thisCloneData);                             
                    }                                       
                       
                }
                catch(exception e)
                {
                    system.debug('\n\n\n---------------------- Error attempting to clone child records of type: ' + childObjectDescribe.getName());
                    system.debug(e); 
                }            
            }          
        }
        
        system.debug('\n\n\n-------------------- Done iterating cloneable objects.');
        
        system.debug('\n\n\n-------------------- Clone Map below');
        system.debug(nextInvocationCloneMap);
        
        system.debug('\n\n\n-------------------- All created object ids thus far across this invocation');
        system.debug(allCreatedObjects);
        
        //if our map is not empty that means we have more records to clone. So queue up the next job.
        if(!nextInvocationCloneMap.isEmpty())
        {
            system.debug('\n\n\n-------------------- Clone map is not empty. Sending objects to be cloned to another job');
            
            deepClone nextIteration = new deepClone();
            nextIteration.thisInvocationCloneMap = nextInvocationCloneMap;
            nextIteration.allCreatedObjects = allCreatedObjects;
            nextIteration.onlyCloneCustomObjects  = onlyCloneCustomObjects;
            nextIteration.allOrNothing = allOrNothing;
            id  jobId = System.enqueueJob(nextIteration);       
            
            system.debug('\n\n\n-------------------- Next queable job scheduled. Id is: ' + jobId);  
        }
        
        system.debug('\n\n\n-------------------- Cloneing Done!');
        
        return allCreatedObjects;
    }
     
    /**
    * @description create a string which is a select statement for the given object type that will select all fields. Equivalent to Select * from objectName ins SQL
    * @param objectName the API name of the object which to build a query string for
    * @return string a string containing the SELECT keyword, all the fields on the specified object and the FROM clause to specify that object type. You may add your own where statements after.
    **/
    public string buildSelectAllStatment(string objectName){ return buildSelectAllStatment(objectName, new list<string>());}
    public string buildSelectAllStatment(string objectName, list<string> extraFields)
    {       
        // Initialize setup variables
        String query = 'SELECT ';
        String objectFields = String.Join(new list<string>(globalDescribeMap.get(objectName).getDescribe().fields.getMap().keySet()),',');
        if(extraFields != null)
        {
            objectFields += ','+String.Join(extraFields,',');
        }
        
        objectFields = objectFields.removeEnd(',');
        
        query += objectFields;
    
        // Add FROM statement
        query += ' FROM ' + objectName;
                 
        return query;   
    }    
    
    public void cleanUpError()
    {
        database.delete(allCreatedObjects);
    }
    
    public class cloneData
    {
        public list<sObject> objectsToClone = new list<sObject>();        
        public map<id,id> previousSourceToCloneMap = new map<id,id>();  
        
        public cloneData(list<sObject> objects, map<id,id> previousDataMap)
        {
            this.objectsToClone = objects;
            this.previousSourceToCloneMap = previousDataMap;
        }   
    }    
}    

It’ll clone your record, your records children, your records children’s children’s, and yes even your records children’s children’s children (you get the point)! Simply invoke the deepClone.clone() method with the id of the object to start the clone process at, whether you want to only copy custom objects, and if you want to use all or nothing processing. Deep Clone takes care of the rest automatically handling figuring out relationships, cloning, re-parenting, and generally being awesome. As always I’m happy to get feedback or suggestions! Enjoy!

-Kenji


Salesforce True Deep Clone, the (Im)Possible Dream

So getting back to work work (sorry alexa/amazon/echo, I’ve gotta pay for more smart devices somehow), I’ve been working on a project where there is a fairly in depth hierarchy of records. We will call them surveys, these surveys have records related to them. Those records have other records related to them, and so on. It’s a semi complicated “tree” that goes about 5 levels deep with different kinds of objects in each “branch”. Of course with such a complicated structure, but a common need to copy and modify it for a new project, the request for a better clone came floating across my desk. Now Salesforce does have a nice clone tool built  in, but it doesn’t have the ability to copy an entire hierarchy, and some preliminary searches didn’t turn up anything great either. The reason why, it’s pretty damn tricky, and governor limits can initially make it seem impossible. What I have here is an initial attempt at a ‘true deep clone’ function. You give it a record (or possibly list of records, but I wouldn’t push your luck) to clone. It will do that, and then clone then children, and re-parent them to your new clone. It will then find all those records children and clone and re-parent them as well, all the way down. Without further ado, here is the code.

    //clones a batch of records. Must all be of the same type.
    //very experemental. Small jobs only!
    public  Map<String, Schema.SObjectType> globalDescribeMap = Schema.getGlobalDescribe();    
    public static list<sObject> deepCloneBatched(list<sObject> objectsToClone) { return deepCloneBatched(objectsToClone,new map<id,id>());}
    public static list<sObject> deepCloneBatched(list<sObject> objectsToClone, map<id,id> previousSourceToCloneMap)
    {
        system.debug('\n\n\n--------------------  Cloning record ' + objectsToClone.size() + ' records');
        list<id> objectIds = new list<id>();
        list<sobject> clones = new list<sobject>();
        list<sObject> newClones = new list<sObject>();
        map<id,id> sourceToCloneMap = new map<id,id>();
        
        
        if(objectsToClone.isEmpty())
        {
            system.debug('\n\n\n-------------------- No records in set to clone. Aborting');
            return clones;
        }
                
        //if this function has been called recursively, then the previous batch of cloned records
        //have not been inserted yet, so now they must be before we can continue. Also, in that case
        //because these are already clones, we do not need to clone them again, so we can skip that part
        if(objectsToClone[0].Id == null)
        {
            //if they don't have an id that means these records are already clones. So just insert them with no need to clone beforehand.
            insert objectsToClone;
            clones.addAll(objectsToClone);
            
            for(sObject thisClone : clones)
            {
                sourceToCloneMap.put(thisClone.getCloneSourceId(),thisClone.Id);
            }
                        
            objectIds.addAll(new list<id>(previousSourceToCloneMap.keySet()));
            //get the ids of all these objects.                    
        }
        else
        {
            //get the ids of all these objects.
            for(sObject thisObj :objectsToClone)
            {
                objectIds.add(thisObj.Id);
            }
            
            for(sObject thisObj : objectsToClone)
            {
                sObject clonedObject = thisObj.clone(false,true,false,false);
                clones.add(clonedObject);               
            }    
            
            //insert the clones
            insert clones;
            
            for(sObject thisClone : clones)
            {
                sourceToCloneMap.put(thisClone.getCloneSourceId(),thisClone.Id);
            }
        }        

        //figure out what kind of object we are dealing with
        string relatedObjectType = objectsToClone[0].Id.getSobjectType().getDescribe().getName();
        
        //Describes this object type so we can deduce it's child relationships
        Schema.DescribeSObjectResult objectDescribe = globalDescribeMap.get(relatedObjectType).getDescribe();
                    
        //get this objects child relationship types
        List<Schema.ChildRelationship> childRelationships = objectDescribe.getChildRelationships();

        system.debug('\n\n\n-------------------- ' + objectDescribe.getName() + ' has ' + childRelationships.size() + ' child relationships');
        
        //then have to iterate over every child relationship type, and every record of that type and clone them as well. 
        for(Schema.ChildRelationship thisRelationship : childRelationships)
        { 
                      
            Schema.DescribeSObjectResult childObjectDescribe = thisRelationship.getChildSObject().getDescribe();
            string relationshipField = thisRelationship.getField().getDescribe().getName();
            
            try
            {
                system.debug('\n\n\n-------------------- Looking at ' + childObjectDescribe.getName() + ' which is a child object of ' + objectDescribe.getName());
                
                if(!childObjectDescribe.isCreateable() || !childObjectDescribe.isQueryable() || !childObjectDescribe.isCustom())
                {
                    system.debug('-------------------- Object is not one of the following: queryable, creatable, or custom. Skipping attempting to clone this object');
                    continue;
                }
                if(Limits.getQueries() >= Limits.getLimitQueries())
                {
                    system.debug('\n\n\n-------------------- Governor limits hit. Must abort.');
                    return clones;
                }
                //create a select all query from the child object type
                string childDataQuery = buildSelectAllStatment(childObjectDescribe.getName());
                
                //add a where condition that will only find records that are related to this record. The field which the relationship is defined is stored in the maps value
                childDataQuery+= ' where '+relationshipField+ ' in :objectIds';
                
                //get the details of this object
                list<sObject> childObjectsWithData = database.query(childDataQuery);
                
                if(!childObjectsWithData.isEmpty())
                {               
                    map<id,id> childRecordSourceToClone = new map<id,id>();
                    
                    for(sObject thisChildObject : childObjectsWithData)
                    {
                        childRecordSourceToClone.put(thisChildObject.Id,null);
                        
                        //clone the object
                        sObject newClone = thisChildObject.clone();
                        
                        //since the record we cloned still has the original parent id, we now need to update the clone with the id of it's cloned parent.
                        //to do that we reference the map we created above and use it to get the new cloned parent.                        
                        system.debug('\n\n\n----------- Attempting to change parent of clone....');
                        id newParentId = sourceToCloneMap.get((id) thisChildObject.get(relationshipField));
                        
                        system.debug('Old Parent: ' + thisChildObject.get(relationshipField) + ' new parent ' + newParentId);
                        
                        //write the new parent value into the record
                        newClone.put(thisRelationship.getField().getDescribe().getName(),newParentId );
                        
                        //add this new clone to the list. It will be inserted once the deepClone function is called again. I know it's a little odd to not just insert them now
                        //but it save on redudent logic in the long run.
                        newClones.add(newClone);             
                    }  
                    //now we need to call this function again, passing in the newly cloned records, so they can be inserted, as well as passing in the ids of the original records
                    //that spawned them so the next time the query can find the records that currently exist that are related to the kind of records we just cloned.                
                    clones.addAll(deepCloneBatched(newClones,childRecordSourceToClone));                                  
                }                    
            }
            catch(exception e)
            {
                system.debug('\n\n\n---------------------- Error attempting to clone child records of type: ' + childObjectDescribe.getName());
                system.debug(e); 
            }            
        }
        
        return clones;
    }
     
    /**
    * @description create a string which is a select statment for the given object type that will select all fields. Equivilent to Select * from objectName ins SQL
    * @param objectName the API name of the object which to build a query string for
    * @return string a string containing the SELECT keyword, all the fields on the specified object and the FROM clause to specify that object type. You may add your own where statments after.
    **/
    public static string buildSelectAllStatment(string objectName){ return buildSelectAllStatment(objectName, new list<string>());}
    public static string buildSelectAllStatment(string objectName, list<string> extraFields)
    {       
        // Initialize setup variables
        String query = 'SELECT ';
        String objectFields = String.Join(new list<string>(Schema.getGlobalDescribe().get(objectName).getDescribe().fields.getMap().keySet()),',');
        if(extraFields != null)
        {
            objectFields += ','+String.Join(extraFields,',');
        }
        
        objectFields = objectFields.removeEnd(',');
        
        query += objectFields;
    
        // Add FROM statement
        query += ' FROM ' + objectName;
                 
        return query;   
    }

You should be able to just copy and paste that into a class, invoke the deepCloneBatched method with the record you want to clone, and it should take care of the rest, cloning every related record that it can. It skips non custom objects for now (because I didn’t need them) but you can adjust that by removing the if condition at line 81 that says

|| !childObjectDescribe.isCustom()

And then it will also clone all the standard objects it can. Again this is kind of a ‘rough draft’ but it does seem to be working. Even cloning 111 records of several different types, I was still well under all governor limits. I’d explain more about how it works, but the comments are there, it’s 3:00 in the morning and I’m content to summarize the workings of by shouting “It’s magic. Don’t question it”, and walking off stage. Let me know if you have any clever ways to make it more efficient, which I have no doubt there is. Anyway, enjoy. I hope it helps someone out there.


Entity is deleted on apex merge

Hey guys,

Just a little quick fix post here, a silly little bug that took me a bit of time to hunt down (probably just because I hadn’t had enough coffee yet). Anyway, the error happens when trying to merge two accounts together. I was getting the error ‘entity is deleted’. The only thing that made my code any different from other examples was that, the account I was trying to merge was being selected by picking it from a lookup on the master.  The basic code looked like this (masterAccount was being set by the constructor for the class, so it is already setup properly).

            try
            {
                Account subAccount = new Account(id=masterAccount.Merge_With__c);
                merge masterAccount subAccount;
                mergeResult = 'Merge successful';
            }
            catch(exception e)
            {
                mergeResult = e.getMessage();
            }

Can you spot the problem here? Yup, because the Merge_With__c field on the master account would now be referencing an account that doesn’t exist (since after a merge the child records get removed) it was throwing that error. So simple once you realize it. Of course the fix for it is pretty easy as well. Just null out the lookup field before the merge call.

            try
            {
                Account subAccount = new Account(id=masterAccount.Merge_With__c);
                masterAccount.Merge_With__c = null;
                merge masterAccount subAccount;
                mergeResult = 'Merge successful';
            }
            catch(exception e)
            {
                mergeResult = e.getMessage();
            }

There you have it. I realize this is probably kind of a ‘duh’ post but it had me stumped for a few minutes, and I’m mostly just trying to get back into the swing of blogging more regularly, so I figured I’d start with something easy. ‘Till next time!




Angel IVR REST API wrapper for Salesforce Apex

Hey all,

Just a random post to help out any developers who may be trying to use the Angel IVR outbound calling features of their new REST API. This is a wrapper class that should do all the hard work for you. It handles all the HTTP traffic, batching, parsing of responses and serialization for ya. You’ll need to create a custom setting called Angel IVR Site and store your API token, API endpoint, subscriber Id in there (or just change the references to settings.whatever in the code to be hard coded. The test class shows creation of one of these objects, along with the expected fields names.

Here is the code. I’ll probably post up a sample app later and maybe even an installable package. I just wanted to get this out there before I forget, or get too lazy to do anything else with it.

/*Angel IVR API Wrapper
Description: Simple class for placing calls via the Angel IVR REST API. Also has experemental
implementations of the other API calls, including cancel, and request (gets job status)

See
https://www.socialtext.net/ivrwiki/outbound_rest_api_documentation
for API details.

Author: Daniel Llewellyn (Twitter: @Kenji776)
Date: 11/16/2012
*/

global class angelIVRWrapper
{
    class applicationException extends Exception {}

    public Angel_IVR_Site__c settings = Angel_IVR_Site__c.getValues('Prod');
    global static boolean isTest = false;

    //a single call item to place to angel. You will always pass a list of these. To make calls create a list
    //of these things (one for each person you wish to call if the call has variables unique to each person, or a single callitem with all the phone numbers included if
    //they are not unique). Then pass them into the campaignCall function along with the angel site you wish to use.
    global class callItem
    {
        public integer maxWaitTime = 30;
        public string phoneNumbers = '';
        public map<string,string> variables = new map<string,string>();
    }

    //a generic API response container. Will contain any error messages and status codes if something bombs.
    //otherwise it should contain a jobId you can later use for cancelling, checking status, etc. Also contains
    //a list of all the call items we attempted to place calls from, all the call items that where skipped (due to being invalid for some resaon)
    //and a list of the responses as provided by angel.
    global class callResponse
    {
        public string jobId = '';
        public string message = 'Calls Placed Successfully';
        public integer httpResponseCode = 200;
        public string httpResponse = 'ok';
        public boolean success = true;
        public list<callRequest> callRequestResponses = new list<callRequest>();
        public list<callItem> placedRequests = new list<callItem>();
        public list<callItem> skippedRequests = new list<callItem>();
    }

    //return object type from the API that contains details about a single call placed using the outbound API.
    global class callRequest
    {
        public string code = '';
        public string callStartTime = '';
        public string callEndTime = '';
        public string phonenumber='';
        public string phoneLineRequestID='';
        public string message = '';
    }    

    @RemoteAction
    global static list<callResponse> campaignCall(list<callitem> callItems, string angelSite)
    {
        angelIVRWrapper controller = new angelIVRWrapper();
        return controller.campaignCall(callItems , angelSite, true);
    }

    //wrapper for the campaignCall function of the Angel IVR. Pass it a list of call items, one for each person you wish to call.
    //it will return a call response object which should contain the job Id you can use for getting the status later.
    public list<callResponse> campaignCall(list<callitem> callItems, string angelSite, boolean allowPartial)
    {
        list<FeedItem> posts = new list<FeedItem>();
        set<string> phoneNumbers = new set<string>();

        //experemental idea for breaking a large number of call items into batches, delayed
        //by a number of seconds. This will likely have to use a recursive scheduled job or something.
        integer batchDelaySeconds = 600;

        list<callResponse> res = new list<callResponse>();
        map<string,string> params = new map<string,string>();
        params.put('allowPartial',string.valueOf(allowPartial));     

        //ask the broker to make a call to angel using the campaignCalls method, passing in the list of call items, and set the allowPartial 
        //url param as well.
        integer counter = 0;
        list<callItem> thisBatch = new list<callItem>();
        list<callItem> skippedRequests = new list<callItem>();

        //break the overall list into batches of 250, since that is the maximum amount you can place in one request.
        for(callItem callItem : callItems)
        {  
            counter++;
            if(callItem.variables.size() <= 50 && !phoneNumbers.contains(callItem.phoneNumbers))
            {              
                thisBatch.add(callItem); 
                phoneNumbers.add(callItem.phoneNumbers);

                if(callitem.variables.containsKey('ID'))
                {
                    FeedItem post = new FeedItem();
                    post.ParentId = callitem.variables.get('ID'); 
                    post.Body = 'Placed outbound call to this record using phone number '+callItem.phoneNumbers+' to Angel site ' + angelSite;    
                    posts.add(post);        
                }                       
            }
            //if this call item has too many variables, or we already have a call for this phone number in the queue, add the call item to our list
            //of skipped calls.
            else
            {
                skippedRequests.add(callItem);
            }

            if(thisBatch.size() == 250 || counter == callItems.size())
            {
                callResponse thisResponse = brokerRequest('POST','campaignCalls',thisBatch, angelSite, params);
                thisResponse.skippedRequests.addAll(skippedRequests);
                res.add(thisResponse);  
                thisBatch.clear();  
                skippedRequests.clear();    
            }
        }
        insert posts;
        return res;
    }

    //wrapper for the requests function of the Angel IVR. Pass it a job id and get back the current status of that job.
    public callResponse requests(string jobId)
    {        
        //ask the broker to make a call to angel using the campaignCalls method, passing in the list of call items, and set the allowPartial 
        //url param as well.  
        callResponse res = brokerRequest('GET','requests/job/'+jobId,null,null,null);        
        return res;
    } 

    //wrapper for the cancels function of the Angel IVR. Pass it a job id and that job will be cancelld if it is currently queued.
    public callResponse cancels(string jobId)
    {
        //ask the broker to make a call to angel using the campaignCalls method, passing in the list of call items, and set the allowPartial 
        //url param as well.  
        callResponse res = brokerRequest('GET','cancels/job/'+jobId,null,null,null);        
        return res;    
    }

    //handles the actual sending of http requests, handling of the response, formatting, etc.
    public callResponse brokerRequest(string httpVerb, string method, list<callitem> callitems, string angelSite, map<string,string> urlParams)
    {
        //create a call response object to pass back.
        callResponse callResponse = new callResponse();

        string requestURI;
        //create the endpoint URI with a bit of string concatination.
        if(angelSite !=null)
        {
            requestURI = settings.API_Endpoint__c+'/'+settings.Subscriber_ID__c+'/'+angelSite+'/'+method+'?apiKey='+settings.API_Key__c;
        }
        else
        {
            requestURI = settings.API_Endpoint__c+'/'+settings.Subscriber_ID__c+'/'+method+'?apiKey='+settings.API_Key__c;
        }    
        HttpRequest req = new HttpRequest();
        //setup the http request.
        req.setMethod(httpVerb);  
        req.setHeader('Content-Type','application/xml');     

        if(urlParams !=null)
        {
            for(string param : urlParams.keySet())
            {
                requestURI += '&'+param+'='+urlParams.get(param);
            }
        }
        req.setEndpoint(requestURI);

        if(callItems != null)
        {    
            //generating Angel XML using the serializer and set that as the request body.                  
            req.setBody(serializeCallItemAngelXml(callitems));
        }
        //send http request
        Http http = new Http();
        HttpResponse res = new HttpResponse();
        string responseBody;
        try
        {
            //some handling for if this is a test class or not. Can't make outbound calls in tests, so we need a mock response
            //if its a test.
            if(!isTest)
            {
                res = http.send(req); 
                responseBody = res.getBody();
            }
            else
            {
                responseBody = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><outboundRequest jobID="0a14021a-1c-13b0b0b3e8a-7abc2f20-d09"><callRequest><requestDetails number="9522206974" phoneLineRequestID="200158136763"/><attempt callEndTime="" callStartTime="" code="queued"><message>queued</message></attempt></callRequest><timeCreated>2012-11-16T16:06:24.331-05:00</timeCreated></outboundRequest>';           
            }

            //if the http response doesn't have a 200 response code, an error happened, so we gotta toss an error, set the success to false, etc.
            //trying to parse whatever is in the body of the http request would probably cause an error as well, so we want to avoid doing that.

            if(res.getStatusCode() != 200 && !isTest)
            {
                throw new applicationException('Error during HTTP Request. Status Code:' + res.getStatusCode() + ' Status:' + res.getStatus() + ' Body Text: ' + res.getBody());
            }

            //if all has gone well until now, parse the results of the http request into a callResponse object and pass that back. This will
            //contain the job id and status of the call(s)
            callResponse = deserializeAngelOutboundRequestXML(responseBody);          
        }
        catch(exception e)
        {          
            callResponse.success = false;
            callResponse.message = e.getMessage() + ' on line: ' + e.getLineNumber() + '. Root cause: ' + e.getCause();   
            callResponse.httpResponseCode = res.getStatusCode();   
            callResponse.httpResponse = res.getStatus();

        }   
        callResponse.placedRequests.addAll(callItems);             
        return callResponse;           
    }

    //takes a list of callItem objects and turns them into valid AngelXML to send to the API. I wish
    //this was more dynamic (using some kind of reflection to iterate over the object properties, but whatever).
    //remember you can include variables in the callItem object to customize the information sent to Angel for each 
    //particular call.
    public static string serializeCallItemAngelXml(list<callitem> callitems)
    {
        string angelXML = '<callItems>';

        for(callitem thisCallItem : callItems)
        {
            angelXML += '<callItem>';
            angelXML += '<maxWaitTime>' + thisCallItem.maxWaitTime + '</maxWaitTime>';
            angelXML += '<phoneNumbers>' + thisCallItem.phoneNumbers + '</phoneNumbers>';
            for(string thisVar : thisCallItem.variables.keySet())
            {
                angelXML += '<variables><name>'+thisVar+'</name>';
                angelXML += '<value>'+thisCallItem.variables.get(thisVar)+'</value></variables>';
            }
            angelXML += '</callItem>';
        }

        angelXML += '</callItems>';
        return angelXML;
    }

    public static callResponse deserializeAngelOutboundRequestXML(string angelXMLResponse)
    {
        Xmlstreamreader reader = new Xmlstreamreader(angelXMLResponse);

        callResponse thisResponse = new callResponse();
        callRequest thisRequest;

        while (reader.hasNext()) 
        { 
            if(reader.getEventType() == XmlTag.START_ELEMENT && reader.getLocalName() == 'outboundRequest')
            {
                thisResponse.jobId = reader.getAttributeValue(null,'jobID'); 
            }  
            if(reader.getEventType() == XmlTag.START_ELEMENT && reader.getLocalName() == 'callRequest')
            {
                thisRequest = new callRequest();
            }            
            else if(reader.getEventType() == XmlTag.START_ELEMENT && reader.getLocalName() == 'requestDetails')
            {
                thisRequest.phonenumber = reader.getAttributeValue(null,'number');
                thisRequest.phoneLineRequestID = reader.getAttributeValue(null,'phoneLineRequestID');
            }
            else if(reader.getEventType() == XmlTag.START_ELEMENT && reader.getLocalName() == 'attempt')
            {
                thisRequest.callStarttime = reader.getAttributeValue(null,'callStartTime');
                thisRequest.callEndtime = reader.getAttributeValue(null,'callEndTime');
                thisRequest.code = reader.getAttributeValue(null,'code');
            }

            else if(reader.getEventType() == XmlTag.START_ELEMENT && reader.getLocalName() == 'message')
            {
                reader.next();
                thisRequest.message = getDecodedString(reader);
            }
            else if(reader.getEventType() == XmlTag.END_ELEMENT && reader.getLocalName() == 'attempt')
            {
                thisResponse.callRequestResponses.add(thisRequest);
            }            
            reader.next();
        }

        return thisResponse;
    }

    public static String getDecodedString(Xmlstreamreader reader)
    {
        return EncodingUtil.urlDecode(reader.getText(), 'UTF-8').trim();
    }

    @isTest
    public static void angelIVRWrapper()
    {
        isTest = true;

        //weird workaround to avoid mixed dml error, as seen here
        //http://boards.developerforce.com/t5/Apex-Code-Development/DML-not-allowed-on-user-in-test-context/m-p/98393
        User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
            System.runAs ( thisUser ) {
            Angel_IVR_Site__c settings = new Angel_IVR_Site__c();
            settings.name = 'Prod';
            settings.Angel_Site_Id__c = 'test';
            settings.API_Endpoint__c = 'http://www.test.com';
            settings.API_Key__c = 'test api key';
            settings.Subscriber_ID__c = '402342';
            insert settings;
        }

        angelIVRWrapper controller = new angelIVRWrapper();
        list<angelIVRWrapper.callitem> callItems = new list<angelIVRWrapper.callitem>();
        Respondent__c testRespondent = testDataGenerator.createTestRespondent();

        angelIVRWrapper.callitem thisCallItem = new angelIVRWrapper.callItem();
        thisCallItem.phoneNumbers = '5555555555';
        thisCallItem.variables.put('RESPONDENT__R_NAME','Frank Jones');
        thisCallItem.variables.put('ID',testRespondent.id);

        callItems.add(thisCallItem);

        callResponse requestStatus = controller.requests(response[0].jobId);

        callResponse sendCancel = controller.cancels(response[0].jobId);

        list<callResponse> sendCalls = angelIVRWrapper.campaignCall(callItems, '200000124604');
    }
}

Displaying and Caching Salesforce Attachment Images in Sites

This time around we are going to be talking about images. How to store them, how to query for them, display them and cache them, in Salesforce, using javascript remoting. We’ll be building a simple application using jQuery, Salesforce and Apex to query for attachments, display them and cache them reduce load times and overhead.

Abstract:
First off, I’m having a bit of a hard time organizing all my thoughts on this topic. It’s kind of big, so please forgive if I skip around a bit. Feel free to ask for clarifications in the comments. So let’s say you are building an application to be hosted on Salesforce. Your application is going to need to publicly accessible (so you are going to be using sites) and the application is going to need to show images that may change frequently and hence would be configured by some non developer types. Your application is going to show all the products you have available, along with pictures of said products.

There is of course many ways you can go about storing your images and relating them to your products but the most straight forward option is to use the notes and attachments feature. That would allow users to easily manage the pictures related to each opportunity without having to go to some central picture repository, or building any additional relationships between objects or URLS. The problem of course is that attachments don’t have a publicly accessible URL to them. You can view them from within Salesforce but you don’t have any way to display them on a site. This could be an issue. Not so fast!

Images as Data
You know those images you uploaded to Salesforce via the attachments feature exist somewhere on Salesforce servers. We also know that Salesforce hates file storage and loves databases. It should come as little surprise that the attachments are actually stored in a table as blob data. That data can be queried for just like any other data. Another little know thing is that in HTML while the img tag normally has it’s src attribute set to a URL, it can in-fact accept base64 encoded image data by specified the data type (). Perhaps we can put all this information together into something useful. Yes, yes we can.

Getting The Image Data
So go ahead and get a visualforce page and controller set up. I’m calling mine productList and productListController respectively. Let’s get the code for our controller in place. Copy and paste this.

global class productListController
{

    //get all the products in the org along with their attachments.
    @remoteAction
    global static remoteObject getProducts()
    {
        remoteObject returnObj = new remoteObject();

        try
        {

            list<Product2> products = [select 
                                                Name,
                                                ProductCode,
                                               Description,
                                               Family,
                                               isActive,
                                               (SELECT Attachment.Name, Attachment.Id FROM Product2.Attachments)
                                               from product2
                                               where isActive = true];
            returnObj.sObjects = products;
        }
        catch(Exception e)
        {
            returnObj.success = false;
            returnObj.message = 'Error getting products';
            returnObj.data = 'Error Type: ' + e.getTypeName() + ' ' + e.getCause() + ' ' + ' on line: ' +e.getLineNumber(); 
        }

        return returnObj;       
    }

    //gets a single attachment (photo) by id. The data is returned as a base64 string that can be plugged into an html img tag to display the image.
    @RemoteAction
    global static remoteObject getAttachment(id attachmentId)
    {   
        remoteObject returnObj = new remoteObject();
        try
        {
            list<Attachment> docs = [select id, body from Attachment where id = :attachmentId limit 1]; 
            if(!docs.isEmpty())
            {
                returnObj.data = EncodingUtil.base64Encode(docs[0].body); 
            }    
        }
        catch(exception e)
        {
            returnObj.success = false;
            returnObj.message = e.getMessage();
            returnObj.data = 'Error Type: ' + e.getTypeName() + ' ' + e.getCause() + ' ' + ' on line: ' +e.getLineNumber();        
        } 
        return returnObj;    
    }   

    global class remoteObject
    {
        public boolean success = true;
        public string message = 'operation successful';
        public string data = null;
        public list<sObject> sObjects = new list<sObject>();
    }    
}

As you can see it’s a pretty simple little controller. We have one method that gets a listing of all the products and the Id’s of the associated attachments using a subquery. That prevents us from having to run another query to get the attachment Id’s. The second function takes a specific attachment id and will return an object with the base64 encoded version of the image. That’s what I was talking about earlier. You can query for an attachment and get it’s raw binary/blob data. Then you can base64 encode it for transfer from the controller back to the requesting page. With that you can get the image data out Salesforce and to your public application.

This does introduce another problem though. Caching. Normally images would be cached by the browser when they are loaded. It uses the filename to create a cached version of the image so next time your browser needs to load it it can just pull it off the hard drive instead of across the internet. The problem with base64 images is they can’t really be cached easily. By the time you have enough data to find it in the cache, you already loaded the whole thing, totally defeating the entire point of the cache. How can we fix this? Caching is too important to just skip in most applications, but yet we need to use base64 encoded images in our app.

Local Storage
With HTML5 we now have something called local storage. Basically it lets us store just about anything we want on the users computer for use at a later time. Basically cookies on steroids. Also where as cookies had to be small little text files, local storage gives us much more flexibility with size. We can leverage this to build own our cache.

Here is the game plan. We’ll run our query to find all the products. We’ll loop over each product we find and create a create an img tag that contains the ID of the image/attachment that needs to go there. After that, we’ll loop over each image tag and populate it with the image. We’ll check to see if we have a local storage item with the ID of the image/attachment. If so, we’ll load that data from the local cache. If not, we’ll make a remoting call to our Apex getAttachment method, and cache the results with local storage then load the data into the img tag. Here is what that looks like.

<apex:page controller="productListController">
    <head>
    <title>Product List</title>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script>

    <script>
        $(document).ready(function() {
            getProducts(function(){
                $('.cacheable').each(function(index){
                    var img = $(this);
                     getImage($(this).attr('id'),function(imageId,imageData){
                         $(img).attr('src', 'data:image/png;base64,'+imageData);
                     });
                });               
            });            
        });  

        function getProducts(callback)
        {
                    Visualforce.remoting.Manager.invokeAction(
                        '{!$RemoteAction.productListController.getProducts}',
                        function(result, event)
                        {
                            if (event.status && (result.success == true || result.success == 'true')) 
                            {    
                               var html='';
                               for(var i = 0; i<result.sObjects.length;i++)
                               {
                                   var imageId = 'default image id here';
                                   if(result.sObjects[i].hasOwnProperty('Attachments'))
                                   {
                                        imageId = result.sObjects[i].Attachments[0].Id;
                                   }
                                   html += '<li><img class="cacheable"  id="'+imageId+'">'+result.sObjects[i].Name+'</li>';

                               }
                               $('#products').html(html);
                               callback();
                            } 
                            else
                            {
                                $("#responseErrors").html(event.message);
                            }
                        }, 
                        {escape: true});                   
        } 

        function getImage(imageId,callback)
        {
             var imageData;

              if ( localStorage.getItem(imageId))
              {   
                console.log('Getting image from local storage!');
                imageData = localStorage.getItem(imageId);
                callback(imageId,imageData);    
              }
              else 
              {
                   console.log('Getting image remote server!');
                    Visualforce.remoting.Manager.invokeAction(
                        '{!$RemoteAction.productListController.getAttachment}',
                        imageId,
                        function(result, event)
                        {
                            if (event.status && (result.success == true || result.success == 'true')) 
                            {    
                                 imageData = result.data;
                                 localStorage.setItem(imageId,imageData);      
                                 callback(imageId,imageData);    
                            } 
                            else
                            {
                                $("#responseErrors").html(event.message);
                            }
                        }, 
                        {escape: true});                   
              }      
        } 
    </script>
    </head>

    <body>
            <ul  id="products"></ul>
    </body>            
</apex:page>

So if you are familiar with jQuery and callbacks it’s pretty easy to make sense of what’s going on here. Once the DOM loads we are going to call the getProducts function. getProducts is going to use remoting to run the getProducts apex method. It will iterate over the results and create a list item for each product as well as that empty tag with the id attribute we talked about earlier. It also assigns the img tag the cacheable class so we can easily iterate over them once we are done. Once the looping and list building is complete, we call the callback functions. Since remoting requests are asyncronous we need to use callbacks when we only want to call one function when the other has completed first. Callbacks are a bit beyond the scope of this article, but just know that if we didn’t use them the get $(‘.cachable’).each() loop would run before the list had finished being populated.

So anyway getProducts finishes running and creating the list. Then comes the loop that uses jQuery to find any element that has the ‘cacheable’ class. For each element it finds, it calls the getImage() function on it, passing in the Id of that element. GetImage is where the cacheing magic happens. It will check to see if a local storage item exists with the id it gets passed. If so, it calls back with that content, if not, it queries Salesforce for an attachment with that id, creates a local storage element for it, and then again returns that content. The loop takes the returned content and sets the src tag of the img element with the base64 encoded data and boom! We have an image.

There you have it. Using Salesforce attachments to house images, using Apex and jQuery to query for them and display them, and HTML5 local storage to cache them. Pretty cool eh? I could write more, but I’m tired and I don’t feel like it. Hit me with questions if ya got em.


Extracting Strings with RegEx in Salesforce Apex

Hey everyone. This is just another quick tip type of deal. It’s pretty easy to replace strings with Apex and regular expressions, but it’s a little bit harder to extract that string. In this example I want to extract a project number from an email subject line. The project number will be between { } braces. So how exactly do I got about doing this? Well it looks a bit like this.

string subject = 'this is a test {12312-D} email subject [dfasdfa]';
Pattern p = Pattern.compile('\\{([^}]*)\\}');
Matcher m = p.matcher(subject);
if (m.find()) 
{
   system.debug(m.group(1)); 
}

First I create a string to search. then I create matching pattern by using the pattern class and my nifty little regular expression. Remember to use Java style regular expressions! then I do a match against the subject line. After that I want to check and see if there was a match, and if so I debug out the first grouping. the 0th grouping contains the match with the brackets, and the 1st contains the text without. So there you have it. Just modify the regular expression to suit your needs and you should be on your way. Have fun!


Apex Captcha with Javascript Remoting and jQuery

So at one time or another, we’ll likely all have to create a public facing form to collect data. We will also find about 2 seconds afterwards that it is getting spammed to hell. To stop the flood of crap, we have reCaptcha. An awesome little utility that will prevent bots from submitting forms. You already know what captcha is though, that’s probably how you found this post, by googling for apex and captcha. First off, there is already an awesome post on how to do with by Ron Hess (Here), but his approach is a bit complicated, and visualforce heavy. Of course being kind of anti visualforce, and the complexities of properties and all that, I made my own little approach. So here we go.

This is assuming you already signed up with reCaptcha. You can go here and sign up for recaptcha (yes you can just enter force.com as the domain)
After that, course add an entry for google to your remote sites in the admin setup under security. Disable protocol security.
Then create your visualforce page, and apex class. I called my class utilities, since this is kind of a re-usable function and I wanted to keep it generic.

Now put this crap in your controller. Also, your controller needs to be global (to use javascript/apex remoting)

@RemoteAction
    global static boolean validCaptcha(string challenge, string response)
    {
      boolean correctResponse = false;
      string secret = 'your recaptcha secret key here. Maybe make this into a custom setting?';
      string publicKey = 'your recaptcha public key here. Maybe make this into a custom setting?';
      string baseUrl = 'http://www.google.com/recaptcha/api/verify'; 

      string body ='privatekey='+ secret +  '&remoteip=' + remoteHost() + '&challenge=' + challenge + '&response=' + response + '&error=incorrect-captcha-sol';
      
      HttpRequest req = new HttpRequest();   
      req.setEndpoint( baseUrl );
      req.setMethod('POST');
      req.setBody ( body);
      try 
      {
        Http http = new Http();
        HttpResponse captchaResponse = http.send(req);
        System.debug('response: '+ captchaResponse);
        System.debug('body: '+ captchaResponse.getBody());
        if ( captchaResponse != null ) 
        {  
            correctResponse = ( captchaResponse.getBody().contains('true') );
        }          
       
      } 
      catch( System.Exception e) 
      {
         System.debug('ERROR: '+ e);
      }                             
      return correctResponse;
    }

    global static string remoteHost() 
    { 
        string ret = '127.0.0.1';
        // also could use x-original-remote-host 
        try
        {
            map<string , string> hdrs = ApexPages.currentPage().getHeaders();
            if ( hdrs.get('x-original-remote-addr') != null)
            {
                ret =  hdrs.get('x-original-remote-addr');
            }
            else if ( hdrs.get('X-Salesforce-SIP') != null)
            {   
                ret =  hdrs.get('X-Salesforce-SIP');
            }
        }
        catch(exception e)
        {
        
        }
        return ret;
    }

Ok, great, now your controller is ready. You just need to pass the right info and it will tell you if it’s right or wrong. Lets get a visualforce page set up to do that.

<apex:page controller="utilities" standardStylesheets="false" sidebar="false"  >

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" />


<script>
$(function() {

    $( "#validateButton" ).click(function(){
        
        validCaptcha(function(valid){
            if(valid)
            {
                $('#validationResultDiv').html('Valid Captcha!');
                
                //Do whatever here now that we know the captcha is good.
            }
            else
            {
                $('#validationResultDiv').html('Invalid Captcha Entered');
            }
           
        });           
    });
});

function validCaptcha(callback)
{
    var challenge = document.getElementById('recaptcha_challenge_field').value;
    var response = document.getElementById('recaptcha_response_field').value;

    utilities.validCaptcha(challenge,response, function(result, event)
    {
        if(event.status)
        {
           callback(result);
        }
    }, {escape:true});
}

</script>

<div id="captchaEnter" title="Form Submission Validation">
    <center>
    <script type="text/javascript" src="https://www.google.com/recaptcha/api/challenge?k=YOUR PUBLIC KEY GOES HERE DONT FORGET IT"></script>
    <noscript>
       https://www.google.com/recaptcha/api/noscript?k=YOUR_PUBLIC_KEY
     </noscript>  
     <div id="validationResultDiv"></div>   
     <button id="validateButton" class="inline">Submit</button>
       
     </center>
</div>


</apex:page>

Boom! Just that easy. Hook up an event handler to the submit button that runs the validCaptcha function. It will get the proper values, and send them to the apex class, which sends them to reCaptcha to verify. Once an answer comes back, it is passed into the callback function, which the can run whatever action you require. Don’t forget to replace the place holder public key in the script line above. Have fun!



Salesforce Custom Calendar with jQuery and Visualforce

Hey all,

I know I’ve been promising a new calendar for a while, and I’m sorry it’s taken so long. I didn’t quite know how in depth I wanted to go, and how much stuff I should build. I finally just decided to release a nice simple framework for other developers to build on. This is based on the super awesome excellent jQuery fullCalendar plugin by Adam Shaw. What this allows you to do is create full calendar records (a custom object). Each record represents a calendar. Each calendar has a source object, a start and end field, and a list of detail fields. When the calendar is loaded, it then queries the specified object for all records with a start date and end date falling in the visible range of the calendar. When an event is clicked a popup box appears with further information that is configurable on the fullcalendar record.

All the more configuration that is needed to create a calendar

Sample popup info when event is clicked


Click here for a demo (go to December 2011 to see some sample events).

You can grab the unmanaged package here

Or just grab the raw project and source from here (first time hosting a file on box.net, we’ll see how this goes).

Anyway, I hope this helps some people who are looking for a simple calendar system, or one to build on. I’m happy to review suggestions and ideas, but I can’t commit to getting anything done. Hope ya dig it!


Salesforce jQuery Calendar

Over the last year there has been a lot of people excited about my Salesforce jQuery calendar. Problem is, for one the code isn’t available due to a lack of hosting. Problem two is that it sucks. It uses some goofy visualforce page to pass information off the the apex class, and it can only query against one type of object. Overall, it’s pretty lame and not a good sample of the kind of work that is possible these days. So I am rebuilding it. In fact, I already have the core up and running. But now I want to know what kind of features you guys are interested in. Do you want a super bare bones easy to understand release, or do we want a little more robust full featured kind of thing? Let me know in the comments what you’d like to see in a new Salesforce calendar, and I’ll see what I can do.

For those who just want my basic functional super skeletal framework I’ll be releasing it sometime tomorrow. I need to clean up a few little things, and I’ll probably release it as an unmanaged package for easy install, and I’ll host the code on my new box.net account.


Salesforce Apex CSV Parsing to sObject

So for a recent project I’ve been working on, a person wants to be able to email in a small CSV file to an automated bot. The bot will extract the attachment, iterate through the data and import the data. So of course first I had to get together a CSV parser. Thankfully that was already handled by the awesome people over at the developer force wiki. So first, grab their Apex CSV parser. So that returns a list of a list of strings. Each list entry is a list of the values in that row. So now while this is nice, it’s still not idea for importing. You need to convert that data into an sObject, or a list of them. So I drafted this little function that works in tandem with the first one. You can pass it that data you get from the first parser, and the type of sObject you want to serialize the data into and it will give you back a list of sObjects. Some things to note about this function.

  • You must pass in the column headers as the first row
  • The column headers must match the API names of the fields. So your column headers must match the sObject field names
  • The parser can deal with invalid field names. It will simple not set them on the sObject. So you can include extra data, it will just be discarded
  • I havn’t tested it much. It may fail with some data types, but I’m not sure
//Name: parseCSV
//Description: Class for parsing and casting CSV content to sObjects
//Author: Daniel Llewellyn and blog post at http://www.preludeinteractive.com/2009/09/parsing-csv-files-in-apex/ (author unknown)
//Date: December 1 2011
public class parseCSV
{   
    //code borrowed from http://www.preludeinteractive.com/2009/09/parsing-csv-files-in-apex/
    public static List<List<String>> parseCSV(String contents,Boolean skipHeaders)
    {
        List<List<String>> allFields = new List<List<String>>();
    
        // replace instances where a double quote begins a field containing a comma
        // in this case you get a double quote followed by a doubled double quote
        // do this for beginning and end of a field
        contents = contents.replaceAll(',"""',',"DBLQT').replaceall('""",','DBLQT",');
        // now replace all remaining double quotes - we do this so that we can reconstruct
        // fields with commas inside assuming they begin and end with a double quote
        contents = contents.replaceAll('""','DBLQT');
        // we are not attempting to handle fields with a newline inside of them
        // so, split on newline to get the spreadsheet rows
        List<String> lines = new List<String>();
        try {
            lines = contents.split('\n');
        } catch (System.ListException e) {
            System.debug('Limits exceeded?' + e.getMessage());
        }
        Integer num = 0;
        for(String line : lines) {
            // check for blank CSV lines (only commas)
            if (line.replaceAll(',','').trim().length() == 0) break;
            
            List<String> fields = line.split(',');  
            List<String> cleanFields = new List<String>();
            String compositeField;
            Boolean makeCompositeField = false;
            for(String field : fields) {
                if (field.startsWith('"') && field.endsWith('"')) {
                    cleanFields.add(field.replaceAll('DBLQT','"'));
                } else if (field.startsWith('"')) {
                    makeCompositeField = true;
                    compositeField = field;
                } else if (field.endsWith('"')) {
                    compositeField += ',' + field;
                    cleanFields.add(compositeField.replaceAll('DBLQT','"'));
                    makeCompositeField = false;
                } else if (makeCompositeField) {
                    compositeField +=  ',' + field;
                } else {
                    cleanFields.add(field.replaceAll('DBLQT','"'));
                }
            }
            
            allFields.add(cleanFields);
        }
        if (skipHeaders) allFields.remove(0);
        return allFields;       
    }
 
    public static list<sObject> csvTosObject(List<List<String>> parsedCSV, string objectType)
    {
        Schema.sObjectType objectDef = Schema.getGlobalDescribe().get(objectType).getDescribe().getSObjectType();
        system.debug(objectDef);
        
        list<sObject> objects = new list<sObject>();
        list<string> headers = new list<string>();
        
        for(list<string> row : parsedCSV)
        {
            for(string col : row)
            {
                headers.add(col);
            }
            break;
        }
        system.debug('========================= File Column Headers');
        system.debug(headers);
            
        integer rowNumber = 0;
        for(list<string> row : parsedCSV)
        {
            system.debug('========================= Row Index' + rowNumber);
            if(rowNumber == 0)
            {
                rowNumber++;
                continue;
            }
            else
            {
                sObject thisObj = objectDef.newSobject();
                integer colIndex = 0;
                for(string col : row)
                {                   
                    string headerName = headers[colIndex].trim();
                    system.debug('========================= Column Name ' + headerName);
                    if(headerName.length() > 0)
                    {                  
                        try
                        {                       
                            thisObj.put(headerName,col.trim());
                        }
                        catch(exception e)
                        {
                            system.debug('============== Invalid field specified in header ' + headerName);                           
                        }
                        colIndex++;
                    }
                } 
                objects.add(thisObj);
                rowNumber++;
            }       
        }
        return objects;
    }
    @isTest
    public static void testParseCSV()
    {
        string csvContent = 'firstname,lastname\nTest,Guy';
        List<List<String>> parsedContent = parseCSV(csvContent,false);
        list<contact> contactList = (list<contact>) csvTosObject(parsedContent, 'contact');
        system.assertEquals(contactList.size(),1);
        system.assertEquals(contactList[0].firstname,'Test');
        system.assertEquals(contactList[0].lastname,'Guy');
    
    }    
}

If nothing else this should at least be a jumping off spot for anyone trying to work with CSV files in Apex. If you make any improvements, I’d love to see/hear them. Hope this helps someone!


Cloudspokes Challenge jQuery Clone and Configure Records

Hey everyone,
Just wrapped up another CloudSpokes contest entry. This one was the clone and configure records (with jQuery) challenge. The idea was to allow a user to copy a record that had many child records attached, then allow the user to easily change which child records where related via a drag and drop interface. I have a bit of jQuery background so I figured I’d give this a whack. The final result I think was pretty good. I’d like to have been able to display more information about the child records, but the plugin i used was a wrapper for a select list so the only data available was the label. Had I had more time I maybe could have hacked the plugin some to get extra data, or maybe even written my own, but drag and drop is a bit of a complicated thing (though really not too bad with jQuery) so I had to use what I could get in the time available. Anyway, you can see the entry below.

jQuery Clone and Configure Record


Cloudspokes Challenge – Open Social Toolkit Voting App

Hey all,
Another week another CloudSpokes challenge done. This one is the open social toolkit, voting application. It allows users to create topics to vote on, lets other users vote on those things, and have discussions about them. Integrated with facebook, and totally force.com based. I used jQuery mobile here to make sure it works on phones and iPads and whatnot, and the super awesome force.com platform for hosting and schema. Really a match made in heaven if you ask me.

You can see the demo app here

See the videos of it in action too!
Interface and Front end Video
Backend and Schema Video

I’ll be doing a post later about the nifty facebook integration, cause to me, that is the coolest part.


While This is Awesome, There Must be a Better Way.

This is half an interesting post about how I solved a fairly complicated problem, and half me looking for a better way to do it. The problem I was solving in theory is fairly simple.

I want to import answers from an external survey software into our Salsforce org.

Pretty simple right? Standard import functionality. Nothing too complex. But now let’s build on this.

1) It should be automated. No manual triggering of the import.
2) It should be imported as it is created. Closer to real time than to ETL.
3) The place the data is coming from has no API. We only have direct ODBC access to it.
4) Since the process must be closer to real time, we should use a ‘push’ style mentality for import. The survey software should push the data into Salesforce as it is created, instead of Salesforce requesting it.
5) The survey software only gives me access to javascript to add functionality. No server side processing of any kind.
6) Solution should be as cloud based as possible. Ideally no code on our servers (we have a cold fusion server we use for a lot of data brokering, but we would like to get rid of it).

Suddenly got harder eh? Right off the bat, point 3 means we are going to need to use some kind of middle-ware (in this case our Coldfusion webserver that can talk to the database). Salesforce has no method to talk directly to a database, as it shouldn’t. Everything is done with API’s these days, nobody directly queries databases anymore. At least they shouldn’t. So my first task was to write an API that Salesforce could access to get it’s data. So I wrote up a simple ColdFusion webservice that queries the survey database, formats the data in a reliable way, and returns a JSON array. While not ideal because it does use our server, at least it’s fairly transparent. It’s just a webservice call that could possibly be replaced in the future if the survey software does release an API in the future.

With the webservice up and running, now I need some Apex code to call out to it, get the data and handle it. So I wrote a nice little Apex method that uses a simple HTTP get with some URL params to invoke my ColdFusion webservice. Now it can get the JSON data. Using the new awesome JSON parser in winter 12 I am able to parse the data into a list of custom objects. Hooray.

So now I need a Salesforce object to store this data right? Actually I am going to want a few. I ended up creating 3 in total. The first object ‘survey’, is just a simple container object with pretty much no fields. The second object, ‘survey entry’ is just an object that will contain all the answer objects for a person in a given survey. It of course has a lookup to the ‘survey’ object, as well as a lookup to a contact, and some other info (when they took the survey, etc). The third object ‘survey answer’ is where the real juicy data is. It has the ID of the question, the text of the question, the persons answer, and a lookup to the survey entry.

So now I modified my Apex class a bit to create the survey answers objects, and relate them to the proper ‘survey entry’ (and create one if one does not exist for this person in this survey yet). Boom, so now all the ‘hard’ work is done. I have a class that can be called that will import the survey data for a person into Salesforce. But wait, how do I actually call this thing? I don’t want this on a scheduler, I want it to get called when new data is available. So I need to make this class itself into a webservice of some kind.

I have a bit of experience with Apex REST so I decided that would be a fitting way to handle this. This class only needs the ID of the survey, and the person for whom it needs to import data. That information is easily included in the URL or in POST fields, so I quickly modified my class to be an Apex REST service. Now it was ready to begin being accessed from the outside world. The question now is, how do I invoke the service itself?

First I used the apigee app console to make sure it was working as required. Apigee handles the oAuth and lets you specify params so testing your Apex REST service couldn’t be easier. Once I had verified that it worked, I needed some method to allow the survey software to invoke it. Problem is of course, if you remember that the survey software only supports JavaScript. JavaScript is still subject to that cross domain security policy BS. Normally you could use the script injection technique to make a callout to a different domain, but I need to set headers and such in the request, as well as making it a post request, so that wasn’t going to fly. On top of that I have would have no idea how to let JavaScript start using oAuth or get a valid session ID. So here is where things get a little murky.

How could I allow a javascript only application invoke my Apex REST service? Looks like I would again have to turn to my ColdFusion middleware box. I wrote another webservice which can invoke the desired Apex method from ColdFusion. You can call Apex REST services using a session ID instead of having to deal with oAuth so I went that route. I already have integration between Salesforce and ColdFusion through use of the awesome CFC library provided at RIA Forge (I actually helped contribute a bit to that). So I just wrote up what basically amounts to be a wrapper. You can invoke it from a simple get request and it will wrap the request with the required headers (authorization, content-length, content-type) and send it off to Salesforce. ColdFusion web services have the awesome feature of being able to be called via a URL, instead of having to use a WSDL or whatever. Come to think of it, they are almost a forerunner for REST, but I digress.

So now I have a URL that when called (with some arguments/params) will invoke my Apex REST service that goes and gets the survey data and imports it. So now I still need to get the survey software to call this URL. Here I use the classic script injection technique to make my cross domain request (because the survey software and my ColdFusion box live on different domains) and it much to my surprise it all worked. If you are curious, the code to do that looks like this.


function loadJSON(url)
{
var headID = document.getElementsByTagName("head")[0];
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.src = url;
headID.appendChild(newScript);
}
var survey = '12345';
var token = 'mkwcgvixvxskchn';
var contact = '003GASDFADFAFDAS';
newUrl = 'http://XXXXXXXXXXXXX/webservice.cfc?method=importData&survey='+survey+'&token&='+token+'&contact='+contact;
loadJSON(newUrl);

So in the end, this is the process I came up with.

1) User takes online survey from 3rd party site (lets call it survey.com)
2) survey.com invokes javascript which calls the ColdFusion webservice (which includes survey id and person id in the request)
3) ColdFusion receives the request, and ‘wraps’ it with the needed authorization information to make a valid HTTP request.
4) Salesforce custom Apex REST class receives the request (with survey id and person id still included)
5) Salesforce sends request BACK to a different ColdFusion webservice, which requests the actual question/answer data.
6) ColdFusion receives request. Queries survey database and encodes database info as an array of JSON encoded objects.
7) JSON encoded data is returned to the calling Apex, where it is parsed into custom objects and committed to the database.

Seems kind of obtuse eh? Yet I can’t think of any way to make it leaner. I really would like to eliminate the 2nd and 3rd step and just have the survey software invoke the Apex REST directly somehow, or at least make the call totally cloud based. I suppose I could host a visualforce page that does the same thing, and have the JavaScript call that…

So anyway, here you can see an interesting case study of integrating a lot of different crap using some fairly new methods and techniques. I am totally open to suggestions on how to refine this. Right now there are just so many points of failure that it makes me nervous but again it seems to be about the best I can do. Thoughts and feedback welcome in the comments.


Salesforce – Pushing Custom Buttons to the Limit With jQuery and Apex

This might fall more in the realm of tech demo than really useful, but I think it awesome. So many of us are aware of custom buttons for Salesforce objects. They allow you to open custom links, go to visualforce pages, and even run custom javascript. That last part is what we are interested in. Sometimes you want to give your users more functionality without having to create a whole visualforce page. We used to have sControls, but then they took those away. It turns out, if you are clever custom buttons can do just about anything you want. The other great thing is that you can call Apex methods from them.

As readers of my blog may also know, I freaking love jQuery. It’s just great. So how can we combine these awesome two things into something even better? Combine jQuery and Apex through the user interface for epic sweetness. First hard part is actually getting jQuery loaded in the dom, and making sure it’s ready. Second tricky part is calling your Apex method without having it become blocking and holding up the jQuery processing. In my example I want to display a nice dialog to the user while the apex code runs. It can take a while so I wanted the dialog to show up immediately and update the message when the apex call was complete. In the end, this is what I came up with.

//Get the Salesforce apex connection libraries
{!REQUIRESCRIPT("/soap/ajax/10.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/10.0/apex.js")}

var interval;

//The main function that does all the work
function appendScript()
{
    //We want to use jQuery as well as the UI elements, so first lets load the stylesheet by injecting it into the dom.
    var head= document.getElementsByTagName('head')[0];
    var v_css  = document.createElement('link');
    v_css.rel = 'stylesheet'
    v_css.type = 'text/css';
    v_css.href = 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/redmond/jquery-ui.css';
    head.appendChild(v_css);

    //Okay, now we need the core jQuery library, lets fetch that and inject it into the dom as well
    var script= document.createElement('script');
    script.type= 'text/javascript';
    script.src= 'https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js';
    head.appendChild(script);
    
    //And of course we need the jQuery UI elements
    var scriptUI = document.createElement('script');
    scriptUI.type = 'text/javascript';
    scriptUI.src = 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js';   
    head.appendChild(scriptUI);

    
    //It takes a second to load, so put in a delay (we don't want to try and reference the         
    //script before it is actually loaded. We store the interval in the global variable, and set up
    //this interval dealio. This will keep running until jQuery has been found to be loaded and then
    //clears the interval so it doesn't keep running.

    interval=self.setInterval(function(){
                                       
        //Check to see if jQuery has loaded                           
        if(jQuery)
        {
            //if jQuery has loaded, clear the interval
            window.clearInterval(interval);
            
            //create a div in the body which we will use for our dialog.
            $(document.getElementsByTagName('body')[0]).append("<div id=infoNotice title='Creating Checks'>Creating Checks Please Wait...<div id='infoNoticeResult'>Just chill, its working.</div></div>");    
            
            //register our newly created div as a dialog
            $( "#infoNotice" ).dialog();   
            
            //setTimeout is non blocking (basically async) so lets put our apex call in a timeout so it doesn't
            //stop our dialog from showing.
            setTimeout(function(){
                                
                //Call out to our apex webservice that does the work. Store the results in the callResult variable                
                var callResult = sforce.apex.execute("campaignClasses","createChecksBatch",{campaignId:"{!Campaign.Id}"});
                
                //Write the result of the call into the div. Apex webservices return arrays, even if the return type
                //is set to string. So just reference the 0th position element to get the string that was returned 
                //to report to the user.
                $( "#infoNoticeResult" ).text(callResult[0]);
            },10);
        }
    }, 300);    
}
appendScript();

If you want to try and copy and paste this, create a custom button on your desired object. Set it to onclick javascript. Add it to your objects page layout. Of course in the apex call change the campaignClasses to your class, and createChecksBatch to your method name.

Like I said, this is just more proof of concept and something to build on. This shows you how you can leverage jQuery in your standard object pages, as well as Apex to build some pretty awesome stuff without having to start trying to inject visualforce pages.


Deleting Duplicate Records But Leave One – Salesforce SOQL

So this is a pretty common thing in regular SQL. You have a bunch of duplicates, in this scenario case objects (we have an automatic case creation process that recently went haywire and created a bunch of cases that where all the the same). So of course we wanted to delete the duplicates, yet leave one of the original records (even though there were dupes, it was still a valid case). So in a panic I threw together this quick method for removing duplicate cases by their subject and leave one of each dupe. This was written pretty hastily, but it should work in most instances. Just run this anonymously using your favorite IDE or I think you can do it in the system log as well.

//First we need to find any cases that have duplicate records. This whole deal uses the subject field to
//identify dupes. So if you need to modify this for another object, find a field you can use identify dupes and
//replace anything that says 'subject' with that field.
list<AggregateResult> badCases = [select count(id)numCases, subject from case where createdDate = LAST_90_DAYS and isClosed = false and subject !='' group by subject  having count(id) > 1];
list<string> badCaseNames = new list<string>();

//loop over every row we found, and add the subject to a list so we can find them again in another query.
for(AggregateResult ar : badCases)
{
        badCaseNames.add(string.valueOf(ar.get('subject')));
}
//Now run a query that gets the ID's of the offending cases. The order by line at the end is CRUCIAL. You MUST
//order the records by the field you are using to identify them as dupes.
list<case> listCases = [select id, subject from case where subject in :badCaseNames order by subject];
//Since we don't want to delete ALL the cases we just found (we have to leave one behind) we create another list
//of cases that will actually get deleted.
list<case> casesToDelete = new list<case>();

//A variable to hold the subject of the last case looked at. If it matches, then it's a dupe.
//hence the reason we needed to sort by subject
string lastCaseName = 'placeholder12345';
for(case c : listCases)
{
    //here is that logic I was talking about. If the current case name
    //is the same as the one we just looked at, then obviously it's a dupe
    //and should get deleted. Otherwise don't do anything cause it's the one case
    //we want to leave behind.
    if(c.subject == lastCaseName)
    {
        casesToDelete.add(c);
    }
    //set the variable for the next iteration
    lastCaseName = c.subject;
}
//If there is anything to delete
if(!casesToDelete.isEmpty())
{
    //delete those suckers.
    delete casesToDelete;
}

Apex – Sorting a map

So this is going to be one of the more apex heavy posts. This is a challenge I think many developers have come across, and while what I propose is by no means the most elegant thing ever, it does do the job until hopefully salesforce implements a native map sorting method. So here is the basic approach

1) populate map with information
2) create another map with the keys as the values you want to sort by, and the value as the key for the other map.
3) create a list whos values are the keyset of the map created in step 2
4) sort the list
5) iterate over the list which now has your values in order, get the value from map 2 using the current loop iterator as the key.

Sounds pretty complicated eh? It’s not SO bad once you kinda get the hang of it, but there is one gotcha that kind of sucks, but we’ll cover that in a minute.

Here is a sample using a simple object called contestEntry. We’ll create a bunch of them with random ordering, and then sort them and loop over the sorted result. You should be able to run this in any org so you can see the principals in action.

        public class contestEntry
        {
            public decimal rank{get;set;}
            public string name{get;set;}
        }
        
        map<string,contestEntry> entries = new map<string,contestEntry>();
        
        contestEntry entry1 = new contestEntry();
        entry1.rank = 5;
        entry1.name = 'Frank';
        entries.put(entry1.name,entry1);
        
        contestEntry entry2 = new contestEntry();
        entry2.rank = 3;
        entry2.name = 'Bob';
        entries.put(entry2.name,entry2);
        
        contestEntry entry3 = new contestEntry();
        entry3.rank = 1;
        entry3.name = 'Jones';
        entries.put(entry3.name,entry3);
        
        contestEntry entry4 = new contestEntry();
        entry4.rank = 4;
        entry4.name = 'Sandy';
        entries.put(entry4.name,entry4);
        
        contestEntry entry5 = new contestEntry();
        entry5.rank = 2;
        entry5.name = 'Felix';
        entries.put(entry5.name,entry5);
        
        //oh no, these entries are all out of order. 
        system.debug(entries) ;
        
        //lets get sorting these guys. First we'll need a map to store the rank, and the contestEntry that rank is 
        //associated with
        map<decimal,string> rankToNameMap = new map<decimal,string>();
        for(contestEntry entry : entries.values())
        {
            rankToNameMap.put(entry.rank,entry.name);
        }
        //now lets put those ranks in a list
        list<decimal> ranksList = new list<decimal>();
        ranksList.addAll(rankToNameMap.keySet());
    
        //now sort them
        ranksList.sort();
        
        //ok, so now we have the ranks in order, we need to figure out who had that rank
        for(decimal rank : ranksList)
        {
            String thisEntryName = rankToNameMap.get(rank);    
            contestEntry thisEntry = entries.get(thisEntryName);
            system.debug(thisEntry);
        }

Walking through it first we just make a sample object to use here. Normally this would be whatever you are actually trying to sort, but for the sake of easyness I just created an object called contestEntry. It just holds a name and a rank.

So then I make a map of those things, keyed by the persona name, and containing the contestEntry object. You might in real life have a map of sObjects keyed by their Id and containing the sObject itself. So then I make a bunch of those and add them to the map in random order so my sorting actually has some work to do 😛

The next thing is creating a map with the key of the value I want to sort this list by. The value is key of the first map. So in real life this might be a dollar amount on an opportunity and then the opportunity Id if the original map was a list of opportunities keyed by their Id.

We loop over all the objects in the original map, and add them to our temporary sorting map, again keyed by value to sort by, and value with key from original map.

Then we create a list of the type of the key of the temporary sorting map. Your key was a decimal? Then your list is of decimals as well, etc. Then add all the keys from the sorting map to the list you just made.

Sort the list.

Iterate over the sorted list, each entry in this list will be a key you can use to get the entry from the sorting map, which will contain the key to the original map. You now have a reference to your original map value by whatever value you sorted on.

There is however one gotcha with this approach. If you have duplicates in the value you are going to sort by, you are going to end up with collisions in your sorting map, which will end up with values overwriting each other and ultimately values missing in your final iteration. This happens because say in my example I have two people with rank 1. First person comes through, their rank is 1, and their name is Sandy. So the sorting map has 1=sandy. Then another person comes through, they also have rank 1 and their name is jones. Now the map has 1=jones. Sandy just fell out of the list. How do you deal with this? The best hack-ish fix I could come up with is to see if the key you are attempting to write to already exists, if so, then write to a slightly higher value key. Basically replace

        for(contestEntry entry : entries.values())
        {
            rankToNameMap.put(entry.rank,entry.name);
        }

with

        for(contestEntry entry : entries.values())
        {
                decimal rank = entry.rank;
                while(rankToNameMap.containsKey(rank))
                {
                    system.debug('------ INCRIMENTING Rank TOTAL FOR ' + entry.name);
                    rank += 0.001;
                }

                rankToNameMap.put(rank,entry.name);
        }

This won’t affect the value displayed when you retrieve and display the object, it just changes the sort order. I haven’t tested this throughly though so don’t rely on it extensively.

Anyway, there you have it Apex fans. A method to reliable (if not quickly or efficiently) sort Apex maps by just about anything. Once you understand the concepts it’s fairly easy to expand to sort to your hearts desire.


Organizing Your Salesforce Apex Codebase

Hey all,
So this is a topic that is constantly on my mind. I am a little bit OCD and I am always looking for the cleanest, fastest, overall best way to store and organize things. It’s borderline obsessive.

When I first started coding in Apex, I had no idea how you were supposed to structure things. I wrote a trigger and a class for every single task I wanted to do (if I wrote a class at all, often I would just jam everything in a trigger). It was an awful mess, but I was also a total n00b so I didn’t know any better. I couldn’t really find any suggestions on how to organize your code base, or what best practice were for triggers, classes and the ever popular unit tests.

I eventually started to realize you can in fact have multiple actions in one trigger, have multiple methods in your classes, reference classes from each other, and some of of those other things that seem so very obvious now. So after about 3 or 4 years, here are some suggestions for you newbies, or those who still don’t really know how they want to set things up. This is just my approach and it’s totally ‘home brewed’. I have no idea these ideas are best practice or not, but they seem to work really well for me.

1) One trigger file for every object type that needs Apex logic

When you first start, you may think it is good to be super modular and have a sepearte trigger file for every action (I thought that was a pretty slick idea at first too). And honestly, functionally it’s fine. However it does lead to a very cluttered code base, and it’s hard to turn individual triggers on and off. It’s also hard to see all the logic attached to an object. That is why I suggest making ONE trigger that has some if statements that control which logic gets fired when. Here, I’ll show you what I mean. We have an object in our org called a respondent (they basically power our whole org, and there is a hell of a lot of logic attached to them).

trigger RespondentTriggers on Respondent__c (after delete, after insert, after undelete, 
after update, before delete, before insert, before update) 
{
    
    Respondent__c[] respondents = Trigger.new;
    Respondent__c[] oldRespondents = Trigger.old;
    //This set of triggers is responsible for all actions related to respondent__c objects.
    
    //Before execution Triggers
    if(Trigger.isBefore)
    {
        if(Trigger.isInsert)
        {
            respondentClasses.populateRespondentData(respondents);
            respondentClasses.checkDupeHouseholdContacts(respondents,respondents);
            
        }
        else if(Trigger.isUpdate)
        {
            respondentClasses.populateRespondentData(respondents);
            respondentClasses.checkDupeHouseholdContacts(respondents,oldRespondents);
            
        }
    
        else if(Trigger.isDelete)
        {
            
        }
    
        else if(Trigger.isUnDelete)
        {
            
        }    
    }

    //After execution Triggers
    else if(Trigger.isAfter)
    {
        if(Trigger.isInsert)
        {
            respondentClasses.checkChildCampaignSpotsAvailable(respondents);
            respondentClasses.createPayments(respondents);
            respondentClasses.updateCounters(respondents);
            respondentClasses.flagRecentlyTested(respondents);
            respondentClasses.updateCampaignMembers(respondents);
            respondentClasses.setFirstRecruitDate(respondents);
            
        }
        else if(Trigger.isUpdate)
        {
            respondentClasses.updateCounters(respondents);
            respondentClasses.updateCampaignMembers(respondents);
            respondentClasses.flagRecentlyTested(respondents);
            respondentClasses.setFirstRecruitDate(respondents);
            respondentClasses.updateRelatedPayment(respondents);
            respondentClasses.clearPastParticipationOnCancel(respondents);
            
        }
    
        else if(Trigger.isDelete)
        {
            respondentClasses.updateCounters(oldRespondents);
        }
    
        else if(Trigger.isUnDelete)
        {
            respondentClasses.updateCounters(respondents);
        }    
    }            
}

Here you can easily see ALL the logic attached to my object (thanks in part to descriptive method names). You can also see it is very easy to control the order of execution of my triggers (which I have no idea how to do if you have separate trigger files), and you can easily turn off chunks by commenting out one line. It makes for a very clean setup in my opinion.

2) Group all logic for objects in one class if possible

Just like how I want all my trigger logic for each object in its own file, it is nice to keep all my methods for an object in it’s own class file. I know sometimes methods will be shared between objects (in that case I recommend trying to abstract them and put them in their own utilities class) but in general you can keep things pretty straight forward if you group similar methods into one class. Some methods will touch multiple types of objects, in that case I generally just put the method in the class for the object which triggers the method to fire. Example if I have a method that updates accounts and contacts, you might not be sure where to put it, but if you are updating all contacts as a result of an account update, but that method in your account methods class.

3) Use standardized naming

As programmers we all know the importance of descriptive variable and method names. However beyond just description I think it is important to be standardized. I want to look at a method or class and be able to know what it does, and what I can expect it to contain by looking at the name. For me, my classes fall into two categories generally.

A) Classes that contain logic for triggers
B) Classes that contain logic for custom visualforce pages

I have taken to using the simple naming convention of either [object]Classes or [pageName]Controller. Example my class with methods for my account trigggers is called accountClasses, while my class with methods for my online scheduling software is called schedulingController. It’s maybe not perfect, but it’s helpful and it looks nice when I look at the list of files in Eclipse 😛

4) Create a utilities class

There are some methods that are handy to have all over the place. Don’t recreate them in every class, simple create a single utilities class and reference its methods when you need. For example my utilities file has methods for reading an XML attribute from an XML string, breaking an serialized string (sent from an html form, serialized with jQuery) into a map, generating a random string of a given length, converting a sObject into JSON (though this won’t be needed after winter 12), and doing simple encryption/description. These methods don’t really belong to any particular object, they are just helpers that are handy to have.

5) Put your unit tests in the class they are testing

Unit tests have been a sticking point for me since day one. At first I didn’t understand them, then I didn’t find them useful, then I couldn’t figure out how I wanted to organize them, now I just… hate them. Anyway, I went through a lot of refactoring before I came up with a way of doing unit tests I liked. Like most people I started out putting the unit tests direction in the class. Querying for data I needed, maybe creating it right there whatever. Then I realized, wait I am creating a ton of the same testing data in every stupid class. What if I made one class, broke each class I am testing into it’s own method and just shared the data among the tests. Now I don’t need to make so much testing data and all my tests are compacted into one file. Genius! Or so I thought. Turns out this is an aweful idea. It is the opposite of modular and can make it very hard to deploy code if your sandbox and prod get too badly out of sync (too many schema or code changes). Don’t do this.

Instead, do what I am in the progress of migrating to. Create a class that only creates test data. Make a method in it for creating some of each kind of object you might want. Then put your testing code in each class, and simple call out to your data generating class to make the data you need for testing.

For example lets say I need an account to manipulate for my unit test. In my testDataGenerator class I have this method.

    
global class testDataGenerator 
{
    private static Account testAccount; 
    public static Account createTestAccount()   
    {
        if(testAccount == null)
        {
            //make an account so we can attach a contact to it
            Account localTestAccount = new Account(name='My Test Account', Tax_ID__c='99-9999999');
            insert localTestAccount;
            return localTestAccount;
        }
        else
        {
            return testAccount;
        }   
    }
}

It will make account on it’s first invocation, and simply return the existing account on any subsequent invocations, making it faster. Now if I need an account in my unit test I can just say

Account thisTestAccount = testDataGenerator.createTestAccount();

Boom, now I have an account I can use without having to write a ton of code, and it keeps my actual unit test clean. Of course this also means that since all my unit tests are using this class I only have to update the testDataGenerator if a new field becomes required on the account object, or some other such change is needed.

Anyway, those are just some things I learned from the school of hard knocks. I hope this helps some of you devs out there get your code organized. Till next time!


Rss Feed to Salesforce Chatter Challenge

So I hadn’t really planned on doing any more challenges for a bit seeing as I’m going on a vacation (yay camping!) soon but I was bored today without a whole lot going on so I figured why not try and do one quick. Thankfully there was this cool little challenge to be able to consume an RSS feed and post new entries to a chatter group.

I’ve never used RSS before (I’m a techie who isn’t very techy I guess) but I knew of it. So I did a bit of reading and was… ambivilent about finding that it’s basically just XML. The hardest part of this was building the XML parser and dealing with the stupid date format. I really dislike the inflexibility of Apex date functions. This is one arena they could learn a thing or two about from ColdFusion. I swear I could give Coldfusion “2008,/21bannana/03 05:1:52PM” and it could make a date out of it. Anyway I digress. This was a fun little challenge and a good way to pass the afternoon. Dunno if I’ll win or not (I could see how I could make some upgrades; allow syncing of only 1 feed at a time, a drop down menu or lookup thing for the chatter group instead of requiring an ID) but I am kind of tired of coding for now 😛 Anyway, here is the video.

RSS To Chatter


Cloudspokes Event Stamp Manager

Hey all,

So I just wrapped up my entry for the CloudSpokes Virtual Stamp Manager. This one was a lot of fun. One of the more complex data models I’ve had to set up for a challenge but overall I think the architecture I came up with was pretty solid. The way it’s built allows for easy reporting and good logging of who made what code when. It even has the bonus feature of some basic QR code support (if enabled in the event).

This was also my first app using the jQuery mobile framework. It took a bit of getting used to, but honestly I really like it. It takes a lot of the hard work about ajax stuff out of the equation and lets you focus on building quality apps. No worry about the loading screens or data formatting, size of the content, or even dealing with the whole hash mark bookmark back button mess.

Anyway, enough of my yapping. Check out the video
here.

Or if you want to, you can play with the app here.


Apex Javascript remoting. Web developers Rejoice!

Ok, so it is probably no secret, I am in fact not an awesome object oriented programmer. Apex does not come very naturally for me (although it is getting better) but I often found the integration between VisualForce and Apex to be clunky. Too many properties, weird methods that you don’t invoke by name (when I call data, it’s actually calling getData(), wtf) and other strange behaviors that make little sense to me. So when I head about javascript remoting, which allowed tight integration between javascript and apex, I was totally stoked. No more having to have actionmethods to try and invoke controller code and dealing with properties and all that jazz. For those of us with maybe not so much java/C# background but a fair amount of web development, javascript remoting feels very natural. Once you pair it with jQuery, life just keeps getting better.

Say for example I want to create a signup form to host on a Salesforce site. I can create a form just like I always would in HTML and javascript, then create an apex method that can take the form data and do whatever. The call is asynchronous so it lends itself well to being all ajax-y and cool. To get you started, here is a sample of a form that is really cool because if I want to capture more data, all I need to do is add the fields to the form (that have fieldnames that match those on my contact). My jQuery and apex are smart enough to figure out the rest on their own.

Here is the page code.

<apex:page standardStylesheets="false" expires="1" cache="false" showHeader="false" sidebar="false" id="page" controller="contactClasses">

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script src="http://jquery.bassistance.de/validate/jquery.validate.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js"></script>

<link rel="stylesheet" type="text/css" media="screen" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/cupertino/jquery-ui.css" />
<link rel="stylesheet" type="text/css" media="screen" href="http://jquery-ui.googlecode.com/svn/branches/dev/themes/base/ui.button.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js" type="text/javascript"></script>

<script>
  
function signUp()
{
    if($("#signUpForm").valid())
    {
        $('#submit').attr('disabled', 'disabled');
        var str = $("form").serialize();
    
        contactClasses.registerUser(str , function(contactResult, event)
        {                
            if (event.status) 
            {
                 console.log(contactResult);
                if(contactResult.success == 'true' || contactResult.success == true)
                {
                      $('#statusBoxText').html('Thanks for registering!.' +contactResult.data);
                }
                else
                {
                     $('#statusBoxText').html('Looks like there was a problem registering you.' +contactResult.data);
                }
                
                $('#submit').attr('disabled', null);                
            } 
            
    
        }, {escape:true});                                         
    }
}

    
$().ready(function() {
    // validate the comment form when it is submitted
    $("#signUpForm").validate();
    
    //style the button
    $(".button").button();

    $( "#statusBox" ).dialog({
        autoOpen: false,
        show: "blind",
        hide: "explode"            
    });      
});
</script>
  <style type="text/css">
body {
    font-size: 62.5%;
}
label {
    display: inline-block;
    width: 100px;
}
legend {
    padding: 0.5em;
    margin-left:auto;
    margin-right:auto;
}
fieldset fieldset label {
    display: block;
}
#signUpForm {
    width: 500px;
    margin-left:auto;
    margin-right:auto;
    margin-top:25px;
}
#signUpForm label {
    width: 250px;
}
#signUpForm label.error, #commentForm button.submit {
    margin-left: 253px;
}
#signUpForm {
    width: 670px;
}
#signUpForm label.error {
    margin-left: 250px;
    width: auto;
    display: block;
}
</style>
  <form class="cmxform"  id="signUpForm" >
    <fieldset class="ui-widget ui-widget-content ui-corner-all">
      <legend class="ui-widget ui-widget-header ui-corner-all">Please provide your information in the form below to sign up</legend>
      <p>
        <label>Firstname</label>
        <input name="Firstname" id="Firstname" type="text" maxlegth="15" size="60" class="required"  />
      </p>
      <p>
        <label>Last Name</label>
        <input name="Lastname" id="Lastname" type="text" size="60"  class="required" />
      </p>
      <p>
        <label>Email</label>
        <input name="Email" id="Email"  type="text" size="60"  class="required email"/>
      </p>
      <p>
        <label>Phone</label>
        <input name="Phone" id="Phone" type="text" size="60" maxlength="12" alt="phone" class="required phone"/>
      </p>
      <p>
        <label>Mobile Phone</label>
        <input name="MobilePhone" id="MobilePhone" type="text" size="60" maxlength="12" alt="phone" class="required phone" />
      </p>
      <p>
        <label>Street Address</label>
        <input name="MailingStreet" id="MailingStreet" type="text" size="60" class="required" />
      </p>
      <p>
        <label>City</label>
        <input name="MailingCity" id="MailingCity" type="text" size="60" class="required" />
      </p>
      <p>
        <label>State</label>
        <input name="MailingState" id="MailingState" type="text" size="60" class="required" minlength="2" maxlength="2" />
      </p>
      <p>
        <label>Zip Code</label>
        <input name="MailingPostalCode" id="MailingPostalCode" type="text" size="60" class="required number" minlength="5" maxlength="5" />
      </p>
      <p>
        <label>Gender</label>
        <select name="Gender__c">
          <option>Male</option>
          <option>Female</option>
        </select>
      </p>
      <p>
        <label>Birth Date</label>
        <select id="Month" name="Month">
          <option value="0">--Select One--</option>
          <option value="1">January</option>
          <option value="2">February</option>
          <option value="3">March</option>
          <option value="4">April</option>
          <option value="5">May</option>
          <option value="6">June</option>
          <option value="7">July</option>
          <option value="8">August</option>
          <option value="9">September</option>
          <option value="10">October</option>
          <option value="11">November</option>
          <option value="12">December</option>
        </select>
        <select id="Day" name="Day">
          <option value="0">--Select One--</option>
          <option value="1">1</option>
          <option value="2">2</option>
          <option value="3">3</option>
          <option value="4">4</option>
          <option value="5">5</option>
          <option value="6">6</option>
          <option value="7">7</option>
          <option value="8">8</option>
          <option value="9">9</option>
          <option value="10">10</option>
          <option value="11">11</option>
          <option value="12">12</option>
          <option value="13">13</option>
          <option value="14">14</option>
          <option value="15">15</option>
          <option value="16">16</option>
          <option value="17">17</option>
          <option value="18">18</option>
          <option value="19">19</option>
          <option value="20">20</option>
          <option value="21">21</option>
          <option value="22">22</option>
          <option value="23">23</option>
          <option value="24">24</option>
          <option value="25">25</option>
          <option value="26">26</option>
          <option value="27">27</option>
          <option value="28">28</option>
          <option value="29">29</option>
          <option value="30">30</option>
          <option value="31">31</option>
        </select>
        <select id="Year" name="Year">
          <option value="0">--Select One--</option>
          <option value="1926">1926</option>
          <option value="1927">1927</option>
          <option value="1928">1928</option>
          <option value="1929">1929</option>
          <option value="1930">1930</option>
          <option value="1931">1931</option>
          <option value="1932">1932</option>
          <option value="1933">1933</option>
          <option value="1934">1934</option>
          <option value="1935">1935</option>
          <option value="1936">1936</option>
          <option value="1937">1937</option>
          <option value="1938">1938</option>
          <option value="1939">1939</option>
          <option value="1940">1940</option>
          <option value="1941">1941</option>
          <option value="1942">1942</option>
          <option value="1943">1943</option>
          <option value="1944">1944</option>
          <option value="1945">1945</option>
          <option value="1946">1946</option>
          <option value="1947">1947</option>
          <option value="1948">1948</option>
          <option value="1949">1949</option>
          <option value="1950">1950</option>
          <option value="1951">1951</option>
          <option value="1952">1952</option>
          <option value="1953">1953</option>
          <option value="1954">1954</option>
          <option value="1955">1955</option>
          <option value="1956">1956</option>
          <option value="1957">1957</option>
          <option value="1958">1958</option>
          <option value="1959">1959</option>
          <option value="1960">1960</option>
          <option value="1961">1961</option>
          <option value="1962">1962</option>
          <option value="1963">1963</option>
          <option value="1964">1964</option>
          <option value="1965">1965</option>
          <option value="1966">1966</option>
          <option value="1967">1967</option>
          <option value="1968">1968</option>
          <option value="1969">1969</option>
          <option value="1970">1970</option>
          <option value="1971">1971</option>
          <option value="1972">1972</option>
          <option value="1973">1973</option>
          <option value="1974">1974</option>
          <option value="1975">1975</option>
          <option value="1976">1976</option>
          <option value="1977">1977</option>
          <option value="1978">1978</option>
          <option value="1979">1979</option>
          <option value="1980">1980</option>
          <option value="1981">1981</option>
          <option value="1982">1982</option>
          <option value="1983">1983</option>
          <option value="1984">1984</option>
          <option value="1985">1985</option>
          <option value="1986">1986</option>
          <option value="1987">1987</option>
          <option value="1988">1988</option>
          <option value="1989">1989</option>
          <option value="1990">1990</option>
          <option value="1991">1991</option>
          <option value="1992">1992</option>
          <option value="1993">1993</option>
          <option value="1994">1994</option>
          <option value="1995">1995</option>
          <option value="1996">1996</option>
          <option value="1997">1997</option>
          <option value="1998">1998</option>
          <option value="1999">1999</option>
          <option value="2000">2000</option>
          <option value="2001">2001</option>
          <option value="2002">2002</option>
          <option value="2003">2003</option>
          <option value="2004">2004</option>
          <option value="2005">2005</option>
          <option value="2006">2006</option>
          <option value="2007">2007</option>
        </select>
      </p>
      <p>
        <input type="button" onClick="signUp();" value="Create Account" class="button" />
 
      </p>
    </fieldset>
  </form>

  
    <div id="statusBox" title="Signup Complete!">
        <div id="statusBoxText"></div>
    </div>
</apex:page>

And the controller

global class contactClasses
{   
    global class remoteObject
    {
        public boolean success{get;set;}
        public string message{get;set;}
        public string data{get;set;}
        public list<sObject> sObjects {get;set;} 
    }

    @remoteAction
    global static remoteObject registerUser(string dataString)
    {
        remoteObject returnObj = new remoteObject();
        returnObj.success = true;
        returnObj.message = 'Member Created';
        returnObj.data = 'Booya';
        
        try
        {
            map<string,string> formData = deserializeString(dataString);
            list<Contact> contacts = new list<Contact>();
            Account thisAccount = new Account();
            thisAccount.name = formData.get('accountname');
            insert thisAccount;            
                        
            Contact thisContact = new Contact();
            thisContact.AccountId = thisAccount.id;

            
            for(String fieldName : formData.keySet())
            {
                try
                {
                    thisContact.put(fieldName,formData.get(fieldName)); 
                }
                catch(Exception e)
                {
                    system.debug('Field: ' +fieldName+' does not exist on contact');
                }          
            }
            contacts.add(thisContact);
            
            insert thisContact;
            returnObj.data = thisContact.id;
            returnObj.sObjects = contacts;
        }
        catch(exception e)
        {
            returnObj.success = false;
            returnObj.data = e.getMessage();
        }
        
        
        return returnObj;       
    }

    public static Map<string,string> deserializeString(String argString)
    {     
        string[] params = argString.split('&');
        map<String,String>  formParams = new map<String,String>();
        for(string p : params)
        {        
            formParams.put(EncodingUtil.urlDecode(p.substring(0,p.indexOf('=')),'UTF-8'),EncodingUtil.urlDecode(p.substring(p.indexOf('=')+1,p.length()),'UTF-8'));    
        }        
        return formParams;
    }  
            
    public class customException extends Exception {}
}

So what’s happening here? Well in the page we create a form and style it with jQuery themes. Then we apply some validations using a nifty plugin to make sure the users don’t enter trash data. Nothing too special there. Then we move into where it gets fun. Once you click the submit button, your information is validated. If the validation passes, the entire form gets serialized, meaning all the values get turned into a string. That string is passed as a single argument to the controller using javascript remoting. The string is received and turned into a map by my neato deserializeString method (if there is a built in apex method to do this, I don’t know about it).

So once that method runs we have a map of field names to field values (just like how the original form was). We simply iterate over the values in the map, and attempt to add them to a contact object. If it errors, that means that field is either of the wrong type, or that it doesn’t exist on the contact at all (now you see why it is important to name your fields exactly as they appear on the contact object). Once the iteration is done, we insert the contact.

The last part is returning the data. I created a simple data type called a remoteObject. It’s just an object that contains a boolean success key, a key to hold a message, a key to contain some extra data, and a key that can contain a list of any kind of sObject. The great thing here is that when it gets returned, javascript knows how to handle it. It is able to access the keys, iterate over the sObjects, all that. The only weird thing is the boolean can’t seem to make up it’s mind sometimes if it’s an actual boolean value, or a string that contains true or false. I just test for both.

In your callback function of the remoting call you can evaluate the results and do whatever you like. In this case, I display a simple dialog confirming the results. There you have it, a process that feels much more natural for those of us who may not quite dig the standard VF/Apex design pattern. It’s also fast as hell, like probably faster than the ‘regular’ approach. I’m pretty sure I’m never going to write a a page the old way again.

Anyway, hopefully this helps some people get on their way with javascript remoting. The tools and examples here should make things a lot easier. Especially the trick about serializing a form, then deserializing it on the other end. No need to declare each parameter and do all that painful evaluation for each variable. I know I am digging it anyway 😛