Why can't I save this SalesForce Batchable class? - class

I am currently using the Apex Workbook to refresh my knowledge of SalesForce.
Tutorial #15, Lesson 1: Offers the following code:
global class CleanUpRecords implements Database.Batchable<Object>
{
global final String query;
global CleanUpRecords (String q) {query = q;}
global Database.Querylocator start (Database.BatchableContext BC)
{
return Database.getQueryLocator(query);
}
global void execute (Database.BatchableContext BC, List<sObject> scope)
{
delete scope;
Database.emptyRecycleBin(scope);
}
global void finish(Database.BatchableContext BC)
{
AsyncApexJob a = [
SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email
FROM AsyncApexJob
WHERE Id = :BC.getJobId()
];
// Send an email to the Apex job's submitter
// notifying of job completion.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {a.CreatedBy.Email};
mail.setToAddresses(toAddresses);
mail.setSubject('Record Clean Up Completed ' + a.Status);
mail.setPlainTextBody (
'The batch Apex job processed ' + a.TotalJobItems +
' batches with '+ a.NumberOfErrors + ' failures.'
);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
However, regardless of which development interface (e.g. Force IDE, console, setup) I use, when I try to save this, I get:
Multiple markers at this line
- File only saved locally, not to server
- Save error: CleanUpRecords: Class must implement the global interface method: Iterable<Object> start(Database.BatchableContext) from Database.Batchable<Object>, CleanUpRecords: Class must implement the global interface method: void execute(Database.BatchableContext, LIST<Object>) from
Database.Batchable<Object>
(Or some equivalent, depending upon how I try to save it.)
However, it seems to me the required methods are already there.
What's missing?

Prepare to be frustrated ... there's just one character off.
Your class declaration should be:
global class CleanUpRecords implements Database.Batchable<sObject> {
instead of:
global class CleanUpRecords implements Database.Batchable<Object> {

Related

Trigger is firing two times, but first run is empty?

The following Trigger is firing twice:
trigger AccountTrigger on Account ( before insert, after insert, before update, after update, before delete, after delete) {
AccountTriggerHandler handle = new AccountTriggerHandler(trigger.new, trigger.oldMap);
System.debug('AccountTrigger created a handler instance: ' + handle);
// Currently the Trigger is firing twice with no obvious reason.
if (Trigger.isBefore) {
if (Trigger.isInsert) {
handle.beforeInsert();
}
if (Trigger.isUpdate) {
// Call handler here!
}
if (Trigger.isDelete) {
// Call handler here!
}
}
if (Trigger.isAfter) {
if (Trigger.isInsert) {
// Call handler here!
}
if (Trigger.isUpdate) {
// Call handler here!
}
if (Trigger.isDelete) {
// Call handler here!
}
}
}
The debug result is showing two handler instances. The weird thing is: The first one seems to be empty? How can that be?
EDIT 1:
The Testcode:
#isTest
public class AccountTestTest {
#isTest
public static void testAccountInsert() {
// Insert an Account
Account a = new Account(name='TestCustomer');
insert a;
Account queryAccount = [SELECT Account.id, Account.name FROM Account WHERE Id = :a.Id];
System.debug('TEST RESULT: ' + queryAccount);
System.debug('AccountTestTest completed.');
// Actually test something...
}
}
I know it's missing asserts, but for the sake of simplicity, I just tried this one.
It's because of ”before insert”. At that stage ids haven't been generated yet. If you don't have any logic that fits into before insert best (complex validations? Field prepopulation?) remove that event?

Test Event expiration in Drools Fusion CEP

Ciao, I have tested in several ways, but I'm still unable to test and verify the Event expiration mechanism in Drools Fusion, so I'm looking for some little guidance, please?
I've read the manual and I'm interested in this feature:
In other words, one an event is inserted into the working memory, it is possible for the engine to find out when an event can no longer match other facts and automatically retract it, releasing its associated resources.
I'm using the Drools IDE in Eclipse, 5.4.0.Final and I modified the template code created by the "New Drools Project" wizard to test and verify for Event expiration.
The code below. The way I understood to make the "lifecycle" to work correctly is that:
You must setup the KBase in STREAM mode - check
You must Insert the Events in temporal order - check
You must define temporal constraints between Events - check in my case is last Message()
However, when I inspect the EventFactHandle at the end, none of the Event() has expired.
Thanks for your help.
Java:
public class DroolsTest {
public static final void main(String[] args) {
try {
KnowledgeBase kbase = readKnowledgeBase();
// I do want the pseudo clock
KnowledgeSessionConfiguration conf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
conf.setOption(ClockTypeOption.get("pseudo"));
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(conf, null);
SessionPseudoClock clock = ksession.getSessionClock();
KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
// Insert of 2 Event:
Message message = new Message();
message.setMessage("Message 1");
message.setStatus(Message.HELLO);
ksession.insert(message);
ksession.fireAllRules();
clock.advanceTime(1, TimeUnit.DAYS);
Message message2 = new Message();
message2.setMessage("Message 2");
message2.setStatus(Message.HELLO);
ksession.insert(message2);
ksession.fireAllRules();
clock.advanceTime(1, TimeUnit.DAYS);
ksession.fireAllRules();
// Now I do check what I have in the working memory and if EventFactHandle if it's expired or not:
for (FactHandle f : ksession.getFactHandles()) {
if (f instanceof EventFactHandle) {
System.out.println(((EventFactHandle)f)+" "+((EventFactHandle)f).isExpired());
} else {
System.out.println("not an Event: "+f);
}
}
logger.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
private static KnowledgeBase readKnowledgeBase() throws Exception {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("Sample.drl"), ResourceType.DRL);
KnowledgeBuilderErrors errors = kbuilder.getErrors();
if (errors.size() > 0) {
for (KnowledgeBuilderError error: errors) {
System.err.println(error);
}
throw new IllegalArgumentException("Could not parse knowledge.");
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
// following 2 lines is the template code modified for STREAM configuration
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );
return kbase;
}
/*
* This is OK from template, as from the doc:
* By default, the timestamp for a given event is read from the Session Clock and assigned to the event at the time the event is inserted into the working memory.
*/
public static class Message {
public static final int HELLO = 0;
public static final int GOODBYE = 1;
private String message;
private int status;
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return this.status;
}
public void setStatus(int status) {
this.status = status;
}
}
}
Drools:
package com.sample
import com.sample.DroolsTest.Message;
declare Message
#role(event)
end
declare window LastMessageWindow
Message() over window:length(1)
end
rule "Hello World"
when
accumulate( $m : Message(status==Message.HELLO) from window LastMessageWindow,
$messages : collectList( $m ) )
then
System.out.println( ((Message)$messages.get(0)).getMessage() );
end
Please note: even if I add expiration of 1second to the Message event, by
#expires(1s)
I still don't get the expected result that the very first Message event inserted, I would have expected is now expired? Thanks for your help.
Found solution! Obviously it was me being stupid and not realizing I was using Drools 5.4.0.Final while still referring to old documentation of 5.2.0.Final. In the updated documentation for Drools Fusion 5.4.0.Final, this box is added for 2.6.2. Sliding Length Windows:
Please note that length based windows do not define temporal constraints for event expiration from the session, and the engine will not consider them. If events have no other rules defining temporal constraints and no explicit expiration policy, the engine will keep them in the session indefinitely.
Therefore the 3rd requirement I originally enlisted of "You must define temporal constraints between Events" is obviously NOT met because I now understand Sliding Length Window in Drools 5.4.0.Final:
Message() over window:length(1)
are indeed NOT a definition of a temporal constraints for event expiration from the session.
Updating this answer hopefully somebody will find it helpful. Also, just so for your know, me being stupid actually for relying on googling in order to reach the doc, and sometimes you don't get redirected to the current release documentation, so it seems...

GWT Async call execution order problem

I have a problem with a throw execution in GWT. So I want to show a simple String list in Client side located on "Server Side". Ok, I have in my Main class this atributes:
private final GreetingServiceAsync greetingService = Util.getInstance(); // This is like > typing GWT.create( GreetingService.class );
public ArrayList songs = new ArrayList();
and in my onModuleLoad() method I have a call to another private method that make the Async call to the Server class:
songs.addAll(getSongsList());
So my getSongsList method is as follow:
public ArrayList<String> getSongsList() {
final int defaultSize = 4;
final ArrayList<String> temp = new ArrayList<String>();
GWT.log("Enter in getSongsLists");
greetingService.greetSongMostPopular(defaultSize,
new AsyncCallback<ArrayList<String>>() {
public void onSuccess(ArrayList<String> result) {
GWT.log("Result is:" + result);
temp.addAll(result);
GWT.log("Case 1 TEMP= " + temp);
}
public void onFailure(Throwable caught) {
// throw new
// UnsupportedOperationException("Not supported yet.");
Window.alert("Error greeting data");
}
});
GWT.log("CASE 2 TEMP = " + temp);
return temp;
}
My problem is that in Case 1 I get
[INFO] [MainModule] - Case 1 TEMP= [Song 1, Song 2, Song 3, Song 4]
but in CASE 2 I get the ArrayList empty!!!
[INFO] [MainModule] - Case 1 TEMP= []
What am I doing wrong?
Thanks in advance!
The call to greetSongsMostPopular is asynchronous. This means that the call begins and the code continues directly to the next line of code, in your case GWT.log("CASE 2 TEMP..."). When this line of code is executed, the results are not yet available and you end up with an empty list.
Later, in the background, onSuccess is called with the results. At this point you should call a function to process the results. You can use a pattern similar to the AsyncCallback class, with an onSuccess and onFailure so the caller of this code can handle both cases, or you can just have the caller pass in their own AsyncCallback instance which would make it a thin wrapper around your greetSongsMostPopular RPC function.
This is normal : the callback is called when your server send the answer but the greetSongMostPopular return imediatly.
The call is asynchronous.
All code must be done in the callback (call a function)
Here is the exact process :
greetingService.greetSongMostPopular is called
temp is empty
the second GWT.log is called : temp is always empty
the getSongsList method return : temp is always empty
the server send the answer to the callback : temp is filled
You are not doing anything wrong. This is expected since you are not dealing with synchronous calls. So the case 2 is only invoked after the asynchronous call returns from the server side.

Problem with A Sync callback function in GWT

What I'm doing is:
getSecroleByOrgNID(orgList[i-2],cu.currentUser.getProfileObj());
System.out.println("Value of sec role is "+ secondryRole);
where the getSecroleByOrgNID function is:
private String getSecroleByOrgNID(COrganization srOrg, CProfile srUser) {
analyticsSrvc.getSecroleByOrgNID(srOrg, srUser,
new AsyncCallback<String>() {
#Override
public void onFailure(Throwable caught) {
}
#Override
public void onSuccess(String result) {
secondryRole = result;
System.out.println("Assigned role is " + secondryRole);
}
});
return null;
}
where secondryRole is
String secondryRole = " ";
The output is:
Value of sec role is
Assigned role is Admin
Query is why the "value of sec role is " statement prints before "Assigned role is Admin" since the function is called before print statement of "value of sec role is ".
And why does the value of secondryRole remain " " even though its value is reassigned inside the function?
As GWT docs says, in GWT you have to "embrace asynchronous transactions" and forget about synchronous ones.
The problem is that getSecroleByOrgNID() invoke an asynchronous call to the server but this call doesn't stop execution, so it continues his work (server needs more time to return). You are asking for secondryRole when server doesn't response yet.
You should call a method always inside onSuccess() that work with server response.

How to run lengthy tasks from an ASP.NET page?

I've got an ASP.NET page with a simple form. The user fills out the form with some details, uploads a document, and some processing of the file then needs to happens on the server side.
My question is - what's the best approach to handling the server side processing of the files? The processing involves calling an exe. Should I use seperate threads for this?
Ideally I want the user to submit the form without the web page just hanging there while the processing takes place.
I've tried this code but my task never runs on the server:
Action<object> action = (object obj) =>
{
// Create a .xdu file for this job
string xduFile = launcher.CreateSingleJobBatchFile(LanguagePair, SourceFileLocation);
// Launch the job
launcher.ProcessJob(xduFile);
};
Task job = new Task(action, "test");
job.Start();
Any suggestions are appreciated.
You could invoke the processing functionality asynchronously in a classic fire and forget fashion:
In .NET 4.0 you should do this using the new Task Parallel Library:
Task.Factory.StartNew(() =>
{
// Do work
});
If you need to pass an argument to the action delegate you could do it like this:
Action<object> task = args =>
{
// Do work with args
};
Task.Factory.StartNew(task, "SomeArgument");
In .NET 3.5 and earlier you would instead do it this way:
ThreadPool.QueueUserWorkItem(args =>
{
// Do work
});
Related resources:
Task Class
ThreadPool.QueueUserWorkItem Method
Use:
ThreadPool.QueueUserWorkItem(o => MyFunc(arg0, arg1, ...));
Where MyFunc() does the server-side processing in the background after the user submits the page;
I have a site that does some potentially long running stuff that needs to be responsive and update a timer for the user.
My solution was to build a state machine into the page with a hidden value and some session values.
I have these on my aspx side:
<asp:Timer ID="Timer1" runat="server" Interval="1600" />
<asp:HiddenField runat="server" ID="hdnASynchStatus" Value="" />
And my code looks something like:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
PostbackStateEngineStep()
UpdateElapsedTime()
End Sub
Private Sub PostbackStateEngineStep()
If hdnASynchStatus.Value = "" And Not CBool(Session("WaitingForCallback")) Then
Dim i As IAsyncResult = {...run something that spawns in it's own thread, and calls ProcessCallBack when it's done...}
Session.Add("WaitingForCallback", True)
Session.Add("InvokeTime", DateTime.Now)
hdnASynchStatus.Value = "WaitingForCallback"
ElseIf CBool(Session("WaitingForCallback")) Then
If Not CBool(Session("ProcessComplete")) Then
hdnASynchStatus.Value = "WaitingForCallback"
Else
'ALL DONE HERE
'redirect to the next page now
response.redirect(...)
End If
Else
hdnASynchStatus.Value = "DoProcessing"
End If
End Sub
Public Sub ProcessCallBack(ByVal ar As IAsyncResult)
Session.Add("ProcessComplete", True)
End Sub
Private Sub UpdateElapsedTime()
'update a label with the elapsed time
End Sub