Is there any limitations or issues with using Continuations from an embedded visualforce page? I'm attempting to make an asynchronous callout to the Google Calendar API. I have the callout working successfully if done from Javascript remoting or from simply calling the method from the dev console. However, when I break apart the logic into the asynchronous form recommend, my visualforce page rerenders with an Internal Server error and not many other details. In looking at the Google API on the backend, I can see the callout was never made. Below is the async code for reference:
//google calendar initial token request
public Object tokenRequest() {
String strRequest = 'grant_type='+EncodingUtil.urlEncode('urn:ietf:params:oauth:grant-type:jwt-bearer',
'UTF-8')+'&assertion='+EncodingUtil.urlEncode(GoogleCalendarCallOut.tokenBuilder(),'UTF-8');
// Create continuation with a timeout
Continuation con = new Continuation(120);
// Set callback method
con.continuationMethod='processInitialResponse';
// Create callout request
HttpRequest req = GoogleCalendarCallOut.buildInitialRequest();
system.debug('The request? '+req);
// Add callout request to continuation
this.tokenRequestLabel = con.addHttpRequest(req);
// Return the continuation
return con;
}
//callback method for token request
public Object processInitialResponse() {
system.debug('Are we ever getting here?');
// Get the response by using the unique label
HttpResponse response = Continuation.getResponse(this.tokenRequestLabel);
// Set the result variable that is displayed on the Visualforce page
this.tokenResult = response.getBody();
//parse the response
Map<String, Object> parsedResponse = (Map<String, Object>) JSON.deserializeUntyped(tokenResult);
//ok now we have the token, now we need to actually make the request to calendar api to
//get the data that we want, the availability
//parse the token out
String access_token = (String)parsedResponse.get('access_token');
system.debug('The access token: '+access_token);
//create a new continuation for the second callout
Continuation chainedContinuation = null;
// Chain continuation if some condition is met
if (access_token != null) {
// Create a second continuation
chainedContinuation = new Continuation(60);
// Set callback method
chainedContinuation.continuationMethod='processMainResponse';
// Create callout request
HttpRequest req = GoogleCalendarCallOut.buildMainRequest(access_token, this.userEmailList,
this.scheduleDateTime, (Integer)this.l.Last_Timezone_Offset__c);
// Add callout request to continuation
this.mainRequestLabel = chainedContinuation.addHttpRequest(req);
}
// Start another continuation
return chainedContinuation;
}
//callback method for main request to process the main callout response
public Object processMainResponse() {
// Get the response by using the unique label
HttpResponse mainResponse = Continuation.getResponse(this.mainRequestLabel);
//parse the response into a map
Map<String, Object> parsedMainResponse = (Map<String, Object>) JSON.deserializeUntyped(mainResponse.getBody());
system.debug('Main Response Parsed: '+parsedMainResponse);
//further parse to just get the calendars (which are the users email addresses)
system.debug(parsedMainResponse.get('calendars'));
//ok now we need to loop through all of the calendars and check the busy attribute
//if the busy array is empty, then it means that person is available and the AR can book time there
Map<String, Object> parsedCalendars = (Map<String, Object>)parsedMainResponse.get('calendars');
system.debug('Parsed Calendars: '+parsedCalendars);
for(String s: parsedCalendars.keySet()) {
Map<String,Object> busyMap = (Map<String,Object>)parsedCalendars.get(s);
List<Object> busyCheck = (List<Object>)busyMap.get('busy');
if(busyCheck.size() == 0) {
this.availableUsers.add(s);
}
}
system.debug('Specific calendar check: '+parsedCalendars.values());
return null; //for now
}