Apex Batch, accessing global variable from an other class, getting null value - salesforce

I have a simple batch with global variable as :
global with sharing class sampleBatchApex implements Database.Batchable<sObject>{
global List<Case> myList;
global Database.QueryLocator start(Database.BatchableContext BC){
}
global void execute(Database.BatchableContext BC, List<sObject> scope){
//some stuff;
}
global void finish(Database.BatchableContext BC){
myList = SELECT ID ... FROM ...
}
}
And an other where I try to get myList
public class BatchApexProgressIndicatorController {
public static sampleBatchApex myBatchObject = new sampleBatchApex();
the batch is executed in an other method, and I'm monitoring the job. Once it's finished, I'm calling the following method to get myList
#AuraEnabled
public static List<Case> getCases(){
return myBatchObject.myList;
}
}
It keeps me getting empty list.
However if I System.debug the list in the finish method of the batch, i can see that the list is not empty.
Could you please hint me on how can I get this list from the other class ?
Thank you

You can't do that. Batch Apex and #AuraEnabled Lightning controller code execute in completely separate transaction contexts; they do not share any variables.
When your batch class is enqueued for execution it is serialized and later deserialized and executed by the platform. Your calling code does not retain a reference to the actual, executing batch instance. Further, your class isn't declared with the Database.Stateful marker interface, so it won't retain member variable values between btches in any case.
You'll need to use a different strategy to monitor your batch job, depending on just what your batch job does. This could be polling sObjects with SOQL, posting Platform Events from the batch, etc.

Related

Retrieve executionId inside CommandInterceptor

I am implementing my own Activiti command intereceptor like this :
public class ActivitiCommandInterceptor extends AbstractCommandInterceptor {
private RuntimeService runtimeService;
private CommandInterceptor delegate;
public ActivitiSpringTxCommandInterceptor(RuntimeService runtimeService, CommandInterceptor delegate) {
this.runtimeService = runtimeService;
this.delegate=delegate;
}
#Override
public <T> T execute(CommandConfig config, Command<T> command) {
String myVariable = runtimeService.getVariable(<missingExecutionId>, "myVariableName");
...
}
}
Inside the execute() method I need to retrieve a variable from the execution context related to this command.
To do that, I need to have the executionId, but I can't find a way to retrieve it.
How can I get my variable from this interceptor?
Thanks
You can create a nativeExecutionQuery
This allows us to use SQL to perform operations directly on DB.
For your case, just find all the execution IDs that contains your variables, and filter them according to your need.

Creating a test Class for batch apex

I am having truble creating a test class for this particular class. If anyone could provide some code that would implement this I would be very grateful.
Many thanks
Class:
global class TalentIntCustomerBatch implements Database.Batchable<sObject>, Database.AllowsCallouts{
global final String query;
global TalentIntCustomerBatch(String q){
query=q;
}
global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<sObject> scope){
for(sObject s : scope){
Contact c = (Contact)s;
TalentIntegrationUtils.updateCustomer(c.Id, c.LastName);
}
}
global void finish(Database.BatchableContext BC){}
}
You will need to populate the data in test to create the contacts and any other objects your TalentIntegrationUtils class needs, but the following code should work to test it:
string query = 'Select Id, LastName From Contact';
TalentIntCustomerBatch ticb = new TalentIntCustomerBatch(query);
Database.executeBatch(ticb);
From the name of your class, you may be making call outs to external systems during the test. If this is the case you will either need to add an "if (Test.isRunningTest() == false)" block around all of your call outs or implement a mock response:
Testing Web Service Callouts
Testing HTTP Callouts by Implementing the HttpCalloutMock Interface

Pass Lead into Salesforce APEX class

I am trying to create an APEX class in Salesforce which sends an SMS. This is called from a Lead Trigger.
I want to pass a 'Lead' into the method but get the following error
"Unsupported parameter type SOBJECT:Lead"
My declaration looks like this.
global class SMS_Services {
#future (callout=true)
public static void SendTestDriveReminder(Lead l){
}
}
This is because you have annotated the method as #future future methods can only accept primitive parameters. So you would need to change the parameter type to Id for example:
#future (callout=true)
public static void SendTestDriveReminder(Set<Id> leadIds)
The important thing to note is that I have recommend you change your parameter from a single record to a set of Id's this is because you should be bulkifying your trigger
trigger LeadTriggerExample on Lead (after insert, after update) {
Set<Id> leadIds = new Set<Id>();
for(Lead l : Trigger.new) {
if(/*Certain Criteria is met*/) {
leadIds.add(l.Id);
}
}
SMS_Services.SendTestDriveReminder(leadIds);
}
You only get a small amount of future methods each day, you need to use them sparingly

Static and Normal class combined in one class

I am trying my best to explain the situation. I hope, what I wrote, is understandable.
We already have class defined like
public ref class TestClass
{
public:
TestClass();
virtual ~TestClass();
protected:
Car* m_car;
}
TestClass is managed C++ and Car is unmanaged C++.
So far so good, but now I need to make static object of TestClass also. So I modify the code like below
public ref class TestClass
{
private:
static TestClass^ s_test = nullptr ;
public:
TestClass();
virtual ~TestClass();
static TestClass^ Instance();
protected:
Car* m_car;
}
When I want to use static instant of the class, I just get it from calling
TestClass staticobj = TestClass::Instance();
Elsewhere, just call
TestClass normalobj = gcnew TestClass();
Instance function is creating s_test static object and returns it.
TestClass ^ TestClass::Instance()
{
if(s_test == nullptr)
{
s_test = gcnew TestClass();
s_test->m_car = new Car();
}
return s_test;
}
Is it a good approach?
Is there any other better approach to accomplish same thing?
Edit :
FYI Above code works.
I combined Krizz and Reed Copsey’s solutions. That solve independent Singleton and memory leak.
Here is my sample code,
Special Singleton class derived from test class,
public ref class SpecialSingletonTestClass: public TestClass
{
private:
static SpecialSingletonTestClass ^ s_ SpecialSingletonTestClass = nullptr;
public:
SpecialSingletonTestClass ();
static SpecialSingletonTestClass ^ Instance();
};
Changed the testclass so it has now one more finalizer function.
public ref class TestClass
{
public:
TestClass ();
virtual ~ TestClass ();
! TestClass ();
protected:
Car* m_car;
}
I tested above pattern , it worked.
Thanks you guys,
L.E.
Is it a good approach?
I would probably not consider this a good approach, as you're making a single class both a singleton and a normal class that you can instance directly.
Typically, if you need a singleton, this would preclude the need or desire to be able to instantiate the class.
If you truly need to have a way to have a "global" instance of this class, I would encapsulate that in a separate class which implements the singleton. This would, at least, make it clear that you are dealing with something that's a single instance in that case. I would not mix both use cases into a single class.
Well, actually there is an issue with memory leaks in your code.
You declare only virtual ~TestClass(); which, for managed classes, are internally turned by C++/CLI compiler into implementation of IDisposable.Dispose().
Therefore, if you put delete car into it, it will be called only if you delete test_class or, e.g. wrap into using (TestClass tst) {} block when using from C#.
It will not be called when object is GCed!
To be sure it is called you need to add finalizer to your class !MyClass(); which is turned by compiler into virtual void Finalize() and thus non-deterministically called when GC is freeing an object.
And it is the only way to free m_car of singleton object.
Therefore, I suggest:
TestClass()
{
m_car = new Car();
}
~TestClass()
{
if (m_car)
delete m_car;
m_car = NULL;
}
!TestClass()
{
if (m_car)
delete m_car;
m_car = NULL;
}
I'm unsure as to what situation you could possibly be in that would require both singleton-style semantics and normal creation semantics for the same class.
As far as what you've coded though, it looks completely fine. My only comments would be that your Instance() function shouldn't need to perform construction on Car, the Instance() function should just call the default constructor of TestClass which should do all that.
EDIT
In reference to:
#crush . The class is already define i just need to get static object of it. Singleton means only one object of the class, but in this case, class have multiple normal object. But i want to use only one object of this class for one specific goal only for limited period of time. – L.E. 2 mins ago
A singleton is (usually) a sign of bad design - alot of people call it an anti-pattern actually. Chances are if you just need this one single specific instance of this class for a limited period of time there are some issues:
Singleton design is made for static-style existence - the variable will live for the scope of your program after lazily initialized.
Allowing global access will move your code towards spaghetti logic. You'd be better off dynamically allocating the one you need and passing the pointer to it to where you need it to be. A shared_ptr would be good for this.
You should find a way around the singleton-style implementation in this case even if it's more work for you - it'll almost certainly be better design.

Winforms: access class properties throughout application

I know this must be an age-old, tired question, but I cant seem to find anything thru my trusty friend (aka Google).
I have a .net 3.5 c# winforms app, that presents a user with a login form on application startup. After a successful login, I want to run off to the DB, pull in some user-specific data and hold them (in properties) in a class called AppCurrentUser.cs, that can thereafer be accessed across all classes in the assembly - the purpose here being that I can fill some properties with a once-off data read, instead of making a call to the DB everytime I need to. In a web app, I would usually use Session variables, and I know that the concept of that does not exist in WinForms.
The class structure resembles the following:
public class AppCurrentUser {
public AppCurrentUser() { }
public Guid UserName { get; set; }
public List<string> Roles { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
}
Now, I have some options that I need some expert advice on:
Being a "dumb" class, I should make the properties non-static, instantiate the class and then set the properties...but then I will only be able to access that instance from within the class that it was created in, right?
Logically, I believe that these properties should be static as I will only be using the class once throughout the application (and not creating new instances of it), and it's property values will be "reset" on application close. (If I create an instance of it, I can dispose of it on application close)
How should I structure my class and how do I access its properties across all classes in my assembly? I really would appreciate your honest and valued advice on this!!
Thanks!
Use the singleton pattern here:
public class AppUser
{
private static _current = null;
public static AppUser Current
{
get { return = _current; }
}
public static void Init()
{
if (_current == null)
{
_current = new AppUser();
// Load everything from the DB.
// Name = Dd.GetName();
}
}
public string Name { get; private set; }
}
// App startup.
AppUser.Init();
// Now any form / class / whatever can simply do:
var name = AppUser.Current.Name;
Now the "static" things are thread-unsafe. I'll leave it as an exercise of the reader to figure out how to properly use the lock() syntax to make it thread-safe. You should also handle the case if the Current property is accessed before the call to Init.
It depends on how you setup your architecture. If you're doing all your business logic code inside the actual form (e.g. coupling it to the UI), then you probably want to pass user information in as a parameter when you make a form, then keep a reference to it from within that form. In other words, you'd be implementing a Singleton pattern.
You could also use Dependency Injection, so that every time you request the user object, the dependency injection framework (like StructureMap) will provide you with the right object. -- you could probably use it like a session variable since you'll be working in a stateful environment.
The correct place to store this type of information is in a custom implementation of IIdentity. Any information that you need to identify a user or his access rights can be stored in that object, which is then associated with the current thread and can be queried from the current thread whenever needed.
This principal is illustrated in Rocky Lhotka's CLSA books, or google winforms custom identity.
I'm not convinced this is the right way but you could do something like this (seems to be what you're asking for anyway):
public class Sessions
{
// Variables
private static string _Username;
// properties
public static string Username
{
get
{
return _Username;
}
set
{
_Username = value;
}
}
}
in case the c# is wrong...i'm a vb.net developer...
then you'd just use Sessions.USername etc etc

Resources