“AsyncApexTests Limit exceeded” blocker

I’ve just hit this “AsyncApexTests Limit exceeded” error when I try to run tests in an org. Running the tests in a different way reports this:

To protect all customers from excessive usage and Denial of Service attacks, we limit the number of long-running requests that are processed at the same time by an organization. Your request has been denied because this limit has been exceeded by your organization. Please try your request again later.

Googling reveals posts like this. And the limit is documented in Understanding Execution Governors and Limits.

But having to wait 24 hours before I can continue working? FUBAR.

“New” action pre-processing override results in “Error: Invalid Data…” on “Save & New”

You can create a custom page and controller and then hook them up to the “New” action for an object – see e.g. Overriding a Standard Button. One situation where this is useful is where you want to do some of your own processing and then forward on to the default UI page.

Here is the sort of page you might use for this purpose:

<apex:page
    standardController="MyCustomObject__c"
    extensions="MyCustomObjectController"
    action="{!url}
    />

and controller:

public with sharing class MyCustomObjectController {

  // Controller extension
  public MyCustomObjectController(ApexPages.StandardController ignored) {
  }

  public PageReference url() {

    // Custom processing logic goes here

    // Standard URL pattern for "New"
    String keyPrefix = MyCustomObject__c.SObjectType.getDescribe().getKeyPrefix();
    PageReference newPr = new PageReference('/' + keyPrefix + '/e');

    // Preserve any query string parameters
    Map<String, String> oldParams = ApexPages.currentPage().getParameters();
    Map<String, String> newParams = newPr.getParameters();
    newParams.putAll(oldParams);

    // Avoid an infinite loop - go to default UI not back to this controller
    newParams.put('nooverride', '1');

    return newPr;
  }
}

This works well when “Save” is clicked in the resulting default UI page. But when “Save & New” is clicked, this (confusing) error message results:

Error: Invalid Data.
Review all error messages below to correct your data.
The page you submitted was invalid for your session. Please click Save again to confirm your change.

After much stripping back of the controller code and comparisons with the typical URL patterns, the problem turns out to be that in the “Save & New” case a save_new parameter is added for part of the cycle but that should not be present in the URL of the final page that is presented.

Adding this line of code (or otherwise making sure the parameter is not present in the final URL) fixes the problem:

    newParams.remove('save_new');

How much harm can one line of code do?

Suppose you are developing a feature that does programmatic manipulation of sharing rules. You go ahead and set the sharing default for your CustomObject to other than “Public Read/Write” in your development org. This automatically creates the CustomObject__Share object to go with your CustomObject__c and so allows you to add a class with a signature such as this:

global class Xyz {
    global void doSomething(List<CustomObject__Share> shares) {
        // ...
    }
}

And then you go ahead and create a managed released package.

The good news is that you now have a managed package that works well for customers who want to configure sharing rules. But the bad news is that you have made sharing rules mandatory for all your customers: the package cannot be installed unless the sharing default for CustomObject is set to other than “Public Read/Write” in the org the package is deployed to.

Woops.

So you go to fix this. The signature you would like to use instead is:

global class Xyz {
    global void doSomething(List<SObject> shares) {
        // ...
    }
}

But then you realize that global method signatures can’t be changed once included in a managed released package. Using @deprecated doesn’t help in this case: it is the presence of CustomObject__Sharing in the signature (whether the method is marked as deprecated or not) that creates the problem. Bottom line is that you are stuck.

Woops WTF.

Be careful what you put in the signature of global methods.

Cleaner inner class test fixture pattern

I favor this inner class test fixture pattern for Apex unit tests where a set of related objects are required. It leverages Apex’s support for named parameters when concrete SObject types are created making the code self describing and quick to modify including when fields are added. (Patterns like builder typically need extra methods adding when new fields are added.) And rather late in the day I’ve noticed that the result of an assignment is the value assigned (as in languages like Java).

These two language features together allow this high signal-to-noise ratio fixture style where a single line initializes, assigns and inserts each object:

@isTest
private class OneTwoThreeTest {
    class Fixture {
        One__c one;
        Two__c two;
        Three__c three;
        Fixture() {
            insert one = new One__c(Number__c = 12.34);
            insert two = new Two__c(One__c = one.Id, String__c = 'Hello');
            insert three = new Three__c(Two__c = two.Id, Checkbox__c = true);
        }
    }
    @isTest
    static void test() {
        Fixture f = new Fixture();
        // ...
    }
}

FullCalendar using a JavaScript remoting callback

FullCalendar quick start illustrates a simple way to get FullCalendar working in a Visualforce page. All the event data was just emitted as JSON text in the generated page. But FullCalendar is typically used where the date range being displayed can be changed making that approach impractical. Two alternate ways to supply the event data are supported:

  • via a json feed – a GET url is configured
  • via a function – an arbitrary piece of JavaScript is configured

Both of these are passed the date range that is required for the calendar so that only the relevant events can be returned. The second of these provides more opportunity to do processing on the client side and is the approach described below.

Here is a simplified version of the Apex controller. The Event class models the values required for each event by FullCalendar and Apex automatically serializes the returned list of these as JSON because of the RemoteAction annotation. The arguments to the events method are two Apex Date primitives and an SObject (whose fields are displayed in the page and provide additional control over the calendar content):

public with sharing class CalendarController {
    
    public class Event {
    
        public String title;
        public String tip;
        public DateTime starts;
        public DateTime ends;
        
        public Event(String title, String tip, DateTime starts, DateTime ends) {
            this.title = title;
            this.tip = tip;
            this.starts = starts;
            this.ends = ends;
        }
    }

    // Page calls back into this
    @RemoteAction
    public static Event[] events(Date starts, Date ends, Filter__c filter) {

        System.debug('>>> starts=' + starts + ' ends=' + ends + ' filter=' + filter);

        List<Event> events = new List<Event>();

        // Loop goes here here where query results are turned into Event objects

        return events;
    }
}

Here is the change to what is assigned to “events” in the Visualforce page. Each time FullCalendar requires event data it invokes this JavaScript function. The function obtains values from the SObject fields in the page and passes those together with the start and end dates to the controller via the standard remote action call that automatically serializes the request as JSON. The returned results are passed into FullCalendar by invoking the callback function supplied in the original function call:

events: function(start, end, callback) {
    
    // JQuery references to the hidden id fields for lookups
    // and also to checkbox fields assigned to fields whose
    // names match the Filter__c SObject
    var filter = {
        Booking__c: bookingLkid.val(),
        Class__c: clazzLkid.val(),
        ShowAvailable__c: showAvailable.prop('checked'),
        ShowBooked__c: showBooked.prop('checked')
    };
    
    // JavaScript dates need formatting to be accepted at the Apex side
    Visualforce.remoting.Manager.invokeAction(
        '{!$RemoteAction.CalendarController.events}',
        start.toUTCString(),
        end.toUTCString(),
        filter, 
        function(result, event) {
            if (event.status) {
                // Jobs done here:
                // 1) In Apex "end" is a reserved word so using "ends"; change back
                // 2) The Apex DateTime is serialized as milliseconds; change to Date
                // 3) The HTML < and > are replaced by entities; turn back
                for (var i = 0; i < result.length; i++) {
                    var r = result[i];
                    r.start = new Date(r.starts);
                    r.end = new Date(r.ends);
                    r.tip = r.tip.replace(/&lt\;/g, '<').replace(/&gt\;/g, '>');
                }
                // Invoke FullCalendar function
                callback(result);
            } else {
                alert('ERROR:\n' + event.message + '\n' + event.where);
            }
        });
}

Gotchas along the way were (API 25.0):

  • Although the remote class and method being invoked are explicit in the call, if the class isn’t the controller or an extension, a page build error of “No remoted actions found to resolve…” results.
  • The automatic serialization of Date appears broken in both directions: see the JavaScript above for work-arounds; there may be similar issues with other types.
  • As the JSON serialization can’t be configured its awkward to generate JSON that includes any Apex reserved words.
  • The “tip” string is HTML generated by the Apex code and so needed some manipulation on the client-side to remove the encoding introduced by the serialization.
  • The Force.com documentation is short on details and examples so expect to spend time debugging to figure out what is actually happening.

Finally I’d like to mention that adding a tooltip to FullCalendar took less than 5 minutes and worked first time: all that was needed was the qTip JavaScript and this small addition:

eventRender: function(event, element) {
    element.qtip({
        content: event.tip
    });
}

Only some types work as Apex map keys from Visualforce

The “Referencing Apex Maps and Lists” section of the Visualforce Developer’s Guide provides examples of how to reference data held in an Apex map in the controller from a Visualforce page. I haven’t found examples where the key values used have been other than strings or integers and the documentation is not explicit. But now that there is support for Non-primitive Types in Map Keys and Sets, I thought it would be worth trying a DateTime value as a map key in a page I have that heavily uses DateTime objects.

But DateTime as a map key type does not work from Visualforce:

Incorrect parameter type for subscript. Expected java.lang.Class, received DateTime

To get some sense of what does and what does not work I created the controller and page listed at the end of this post (both set to API 26.0). I found two further failing map key types.

Time as a map key type results in:

Unsupported type shared.xml.soap.Time encountered.

A custom Apex class as a map key type results in:

Map key Custom:[value=987] not found in map

i.e. value semantics are not supported (but the generally less useful reference semantics are).

I’ll create a case with Salesforce about the types that don’t work.

<apex:page controller="MapTestController">
  <h1>Map Test</h1>
  <br/><apex:outputText value="{!stringKeyMap[stringKey]}"/>
  <br/><apex:outputText value="{!integerKeyMap[integerKey]}"/>
  <br/><apex:outputText value="{!longKeyMap[longKey]}"/>
  <br/><apex:outputText value="{!decimalKeyMap[decimalKey]}"/>
  <br/><apex:outputText value="{!dateKeyMap[dateKey]}"/>
  <br/><apex:outputText value="{!customByReferenceKeyMap[customByReferenceKey]}"/>
  <!--
  <br/><apex:outputText value="{!timeKeyMap[timeKey]}"/>
  -->
  <!--
  <br/><apex:outputText value="{!dateTimeKeyMap[dateTimeKey]}"/>
  -->
  <!--
  <br/><apex:outputText value="{!customByValueKeyMap[customByValueKey]}"/>
  -->
</apex:page>
public class MapTestController {

    public String stringKey {
        get {
            return 'key';
        }
    }
    public Map<String, String> stringKeyMap {
        get {
            return new Map<String, String>{stringKey => 'string value'};
        }
    }
    
    public Integer integerKey {
        get {
            return 1234;
        }
    }
    public Map<Integer, String> integerKeyMap {
        get {
            return new Map<Integer, String>{integerKey => 'integer value'};
        }
    }
    
    public Long longKey {
        get {
            return 1234;
        }
    }
    public Map<Long, String> longKeyMap {
        get {
            return new Map<Long, String>{longKey => 'long value'};
        }
    }
    
    public Decimal decimalKey {
        get {
            return 3.25;
        }
    }
    public Map<Decimal, String> decimalKeyMap {
        get {
            return new Map<Decimal, String>{decimalKey => 'decimal value'};
        }
    }
    
    public Date dateKey {
        get {
            return Date.newInstance(2012, 1, 1);
        }
    }
    public Map<Date, String> dateKeyMap {
        get {
            return new Map<Date, String>{dateKey => 'date value'};
        }
    }
    
    public Time timeKey {
        get {
            return Time.newInstance(8, 20, 30, 0);
        }
    }
    public Map<Time, String> timeKeyMap {
        get {
            return new Map<Time, String>{timeKey => 'time value'};
        }
    }
    
    public DateTime dateTimeKey {
        get {
            return DateTime.newInstance(2012, 1, 1, 0, 0, 0);
        }
    }
    public Map<DateTime, String> dateTimeKeyMap {
        get {
            return new Map<DateTime, String>{dateTimeKey => 'date time value'};
        }
    }
    
    public class Custom {
        private Integer value;
        public Custom(Integer value) {
            this.value = value;
        }
        public Boolean equals(Object other) {
            return this.value == ((Custom) other).value;
        }
        public Integer hashCode() {
            return value;
        }
    }
    
    private static final Custom customInstance = new Custom(321);
    public Custom customByReferenceKey {
        get {
            return customInstance;
        }
    }
    public Map<Custom, String> customByReferenceKeyMap {
        get {
            return new Map<Custom, String>{customByReferenceKey => 'custom (by reference) value'};
        }
    }
    
    public Custom customByValueKey {
        get {
            return new Custom(987);
        }
    }
    public Map<Custom, String> customByValueKeyMap {
        get {
            return new Map<Custom, String>{customByValueKey => 'custom (by value) value'};
        }
    }
}

FullCalendar quick start

I was pleasantly surprised at how painlessly Adam Shaw’s FullCalendar worked in a Visualforce page so am posting a basic controller and page here to help others get started. This is the output they produce (with of course all the hard work done by FullCalendar):

The controller emits hard-coded data: a real controller would build the data from various SObjects and provide actions to be invoked from the client-side JavaScript:

public with sharing class CalendarDemoController {
    public String events {
        get {
            JSONGenerator g = JSON.createGenerator(true);
            g.writeStartArray();
            for (Integer i = -2; i <= 2; i++) {
                g.writeStartObject();
                g.writeStringField('title', 'Event ' + i);
                g.writeDateTimeField('start', DateTime.now().addDays(i).addHours(i));
                g.writeDateTimeField('end', DateTime.now().addDays(i).addHours(i + 1));
                g.writeEndObject();
            }
            g.writeEndArray();
            return g.getAsString();
        }
    }
}

The fullcalendar-1.5.4.zip download is setup as a single static resource with the various pieces of content accessed via their paths in the Visualforce page. The calendar is rendered using a mixture of static configuration and the events JSON string provided by the controller:

<apex:page controller="CalendarDemoController" tabStyle="Contact">

<link href="{!URLFOR($Resource.fullcalendar,'fullcalendar-1.5.4/fullcalendar/fullcalendar.css')}" rel="stylesheet" type="text/css"/>
<link href="{!URLFOR($Resource.fullcalendar,'fullcalendar-1.5.4/fullcalendar/fullcalendar.print.css')}" rel="stylesheet" type="text/css" media="print"/>
<script src="{!URLFOR($Resource.fullcalendar, 'fullcalendar-1.5.4/jquery/jquery-1.8.1.min.js')}" type="text/javascript" language="javascript"></script>
<script src="{!URLFOR($Resource.fullcalendar, 'fullcalendar-1.5.4/fullcalendar/fullcalendar.min.js')}" type="text/javascript" language="javascript"></script>

<apex:sectionHeader title="Calendar Demo"/>

<!-- Calendar is rendered here by the fullcalendar Javascript -->
<apex:pageBlock >
    <div id='calendar'/>
</apex:pageBlock>

<!-- Fullcalendar configuration plus event data supplied by controller -->
<script type="text/javascript" language="javascript">
$(document).ready(function() {
    $('#calendar').fullCalendar({
        header: {
            left: 'title',
            center: 'month,agendaWeek,agendaDay',
            right: 'prevYear prev,today,next nextYear'
        },
        defaultView: 'agendaWeek',
        allDayDefault: false,
        minTime: 8,
        maxTime: 21,
        events:
{!events}
    });
});
</script>
</apex:page>

“Argument 1 cannot be null” with no line number

The stack trace generation in Apex seems to be broken for at least one NullPointerException case.

This test case illustrates the problem:

@isTest
private class NpeTest {
    private static void f() {
        Decimal dec1 = 0.00;
        Decimal dec2 = null;
        dec1 += dec2;
    }
    @isTest
    static void test() {
        f();
    }
}

The test results in these messages:

System.NullPointerException: Argument 1 cannot be null
External entry point Class.cve.NpeTest.test: line 10, column 1

and the corresponding debug log adds little.

You can infer that the problem is somewhere in the function f. In this case it is then easy to find: dec1 is being incremented by a null dec2 value at line 6.

But in longer functions (and given that the message “Argument 1 cannot be null” doesn’t immediately suggest a problem in an increment operation) the root cause can be much harder to find.

PS Winter ’13 fixes this.

Keeping track of the selected tab of an apex:tabPanel in the controller – using Javascript remoting

While this Keeping track of the selected tab of an apex:tabPanel in the controller implementation works, taking a look at the “Network” view of Chrome’s “Developer Tools” brings the bad news that the call to the server made when a tab is clicked on involves (in my case) a 700k byte data transfer and an elapsed time of around 3 seconds. This is a lot of overhead to just transmit the name of the selected tab to the server. This cost and time delay is not immediately apparent because the browser remains responsive. Looking at the payload sent to the server, the problem is that the full view state is being sent as part of the request.

The “writing the name of that tab back to the controller” technique I should have used in the first place is JavaScript remoting. Changing to that reduces the data transfer size to a few hundred bytes and the elapsed time to a few hundred milliseconds.

Here is the changed Visualforce and Apex:

<apex:page id="p" standardController="Xyz__c" extensions="XyzController">
    <apex:form id="f">
        <apex:tabPanel id="tp" switchType="client" value="{!selectedTab}" onclick="setSelectedTabOnController()">
            <apex:tab name="Tab1" label="Tab1" id="Tab1">
                <!-- Tab content -->
            </apex:tab>
            <apex:tab name="Tab2" label="Tab2" id="Tab2">
                <!-- Tab content -->
            </apex:tab>
        </apex:tabPanel>
    </apex:form>
<script type="text/javascript">
function getSelectedTabName() {
    if (RichFaces) {
        var tabs = RichFaces.panelTabs['p:f:tp'];
        for (var i = 0; i < tabs.length; i++) {
            var tab = tabs[i];
            if (RichFaces.isTabActive(tab.id + '_lbl')) {
                return tab.name;
            }
        }
    }
    return null;
}
function setSelectedTabOnController() {
    // Invoke server remote action method
    XyzController.updateLastViewedTab('{!Xyz__c.Id}', getSelectedTabName(), callbackHandler)
}
function callbackHandler(result, event) {
    if (event.type == 'exception') {
        alert(event.message);
    }
}
</script>
</apex:page>
global with sharing class XyzController  {
    private Xyz__c xyz;
    @RemoteAction
    global static void updateLastViewedTab(Id xyzId, String tabName) {
    	upsert new Xyz__c(Id = xyzId, LastViewedTab__c = tabName);
    }
    public String selectedTab {
        get {
            if (selectedTab == null) {
                if (xyz.LastViewedTab__c != null) {
                    selectedTab = xyz.LastViewedTab__c;
                } else {
                    selectedTab = 'Tab1';
                }
            }
            return selectedTab;
        }
        // Setter has to be public as some (but not all) actions do result in an update
        set;
    }
    // Other code...
}

Keeping track of the selected tab of an apex:tabPanel in the controller

PS Read the next few paragraphs for some context but then move on to the better implementation described in Keeping track of the selected tab of an apex:tabPanel in the controller – using Javascript remoting.

I have a heavily used page that presents a dozen or so fairly complex panels using apex:tab/apex:tabPanel. The controller can set the tab that is initially displayed by providing a property that is used for the “value” (not the “selectedTab”) of the apex:tabPanel. But I also want tab selections made by the user to be recorded back on the controller (and then persisted). This is to improve usability so that the next time the user returns to the page they can continue where they left off. This approach also avoids the need to encode the current tab selection in saveURL and retURL parameters that are part of links to allow child objects to be added or edited and then the same tab returned to when a Save or Cancel is done.

One approach I found suggested is to use a “switchType” of “server” or “ajax” instead of “client”. For my page using either of these settings changed the instantaneous tab switch of the “client” setting to a glacial and feedback-less several second delay in the tab switch. I also found postings that implied that “client” would write the current tab name back to the controller but in my tests it did not.

If you know of a recently tested platform-supported way to do this please comment. Meanwhile here is what I ended up doing.

The problem has two parts:

  • finding which tab is currently selected
  • writing the name of that tab back to the controller

Solving the first problem means inspecting the platform’s implementation classes and so will break if they change. Solving the second problem makes use of published platform functionality and Matt Lacey’s apex:actionFunction and apex:param – Or How to Pass Values from Javascript to an Apex Controller.

Here is an outline of the Visualforce:

<apex:page id="p" standardController="Xyz__c" extensions="XyzController">
    <apex:form id="f">
        <apex:tabPanel id="tp" switchType="client" value="{!selectedTab}" onclick="setSelectedTabOnController()">
            <apex:tab name="Tab1" label="Tab1" id="Tab1">
                <!-- Tab content -->
            </apex:tab>
            <apex:tab name="Tab2" label="Tab2" id="Tab2">
                <!-- Tab content -->
            </apex:tab>
        </apex:tabPanel>
        <apex:actionFunction id="af" name="selectTabActionFunction" action="{!selectTab}" reRender="">
            <apex:param name="selectedTab" assignTo="{!selectedTab}" value="{!selectedTab}"/>
        </apex:actionFunction>
    </apex:form>
<script type="text/javascript">
function getSelectedTabName() {
    if (RichFaces) {
        var tabs = RichFaces.panelTabs['p:f:tp'];
        for (var i = 0; i < tabs.length; i++) {
            var tab = tabs[i];
            if (RichFaces.isTabActive(tab.id + '_lbl')) {
                return tab.name;
            }
        }
    }
    return null;
}
function setSelectedTabOnController() {
    selectTabActionFunction(getSelectedTabName());
}
</script>
</apex:page>

and an outline of the corresponding controller Apex:

public with sharing class XyzController  {
    private Xyz__c xyz;
    // "Get" called when page rendered; "set" called by client-side Javascript
    public String selectedTab {
        get {
            if (selectedTab == null) {
                if (xyz.LastViewedTab__c != null) {
                    // Select the last saved tab
                    selectedTab = xyz.LastViewedTab__c;
                } else {
                    // Select a default tab
                    selectedTab = 'Tab1';
                }
            }
            return selectedTab;
        }
        set {
            if (value != selectedTab) {
                // Persist just the tab change
                upsert new Xyz__c(Id = xyz.Id, LastViewedTab__c = value);
            }
            selectedTab = value;
        }
    }
    // Method for client-side Javascript to invoke; does nothing
    public PageReference selectTab() {
        return null;
    }
    // Other code...
}

Note that the “onclick” event on apex:tabPanel happens after the selected tab has already switched ensuring it is the new tab name that is written to the controller not the old tab name. And the performance of the write to the controller is good enough that the tab switch remains pretty much instantaneous.