How to retrieve process variable in Camunda-bpm? - java

While reading (https://docs.camunda.org/manual/7.5/user-guide/process-engine/variables/) I am not sure how you retrieve a variable?
At the moment I am struggling to find out how to access previously set process variables. What I tried is:
I have a simple bpmn process in which i have start event, 1 service task and end event, I am starting my process by passing 2 variables (a&b) and my service task is implementing following java class:
public class Addition implements JavaDelegate {
public void execute(DelegateExecution exe) throws Exception {
System.out.println("Inside calculator again");
Integer x = (Integer) exe.getVariable("a");
Integer y = (Integer) exe.getVariable("b");
int add = x+y;
System.out.println("Addition of two number is"+add);
exe.setVariable("add",add);
}
I am starting my process as follows:
public void sayHello(ProcessEngine processEngine)
{
Map<String,Object> variables = new HashMap<String, Object>();
variables.put("a", 3);
variables.put("b", 5);
ProcessInstance instance= processEngine.getRuntimeService().startProcessInstanceByKey("Process_3", variables);
}
I want to access add variable (present in Addition class) in sayHello class?
As process has been completed so I can't use runtimeService so I tried to use history service but couldn't find out any solution.
Is there any Java API which I can use or is there any other way?

If you want to get all historic variable instances use the list method in the HistoricVariableInstanceQuery.
For Example
List<HistoricVariableInstance> variables = processEngine.getHistoryService().createHistoricVariableInstanceQuery.list();
If you want to get specific variables with the given name you can use the method variableName(String)
For Example:
List<HistoricVariableInstance> variables = processEngine.getHistoryService().createHistoricVariableInstanceQuery().variableName("myVar").list();
To get the variables of a specific process instance use the method processInstanceId
For Example:
List<HistoricVariableInstance> variables = processEngine.getHistoryService().createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId()).variableName("myVar").list();
See for further information the documentation of the
HistoryService and HistoricVariableInstanceQuery

for anyone struggling with the same issue the variables used to start the process are process variables, the ones we retrieve via delegate are local ones so you have to somehow get to the process instance. To make your code works I'll rewrite it as follow (will change from implementing JavaDelegate to implementing ActivityBehavior and to get the variable you have to go througth call to getParent()).
public class Addition implements ActivityBehavior{
public void execute(ActivityExecution exe) throws Exception {
System.out.println("Inside calculator again");
int x = (int) exe.getParent().getVariable("a");
int y = (int) exe.getParent().getVariable("b");
int add = x+y;
System.out.println("Addition of two number is: " + add);
exe.setVariable("add",add);
}
The sayHello method won't change
public void sayHello(ProcessEngine processEngine)
{
Map<String,Object> variables = new HashMap<String, Object>();
variables.put("a", 3);
variables.put("b", 5);
ProcessInstance instance=
processEngine.getRuntimeService().startProcessInstanceByKey("Process_3", variables);
}

Related

How to get value outside of asynchronous listener methods

I want to get frame counts which can be obtain on listener's overridden methods.
But if I use try to assign value to outer variable I get error.
error: local variables referenced from an inner class must be final or effectively final
public void Test5 (String path, Callback cb){
// 1. initialised count variable
int count = 0;
decoder.addRenderListener(
new WebPDecoder.RenderListener(){
#Override
public void onStart(){
// 2. assigning value to count variable
count = decoder.getFrameCount();
Log.d(TAG, count); count is non zero
}
#Override
public void onRender(ByteBuffer byebuffer){}
#Override
public void onEnd(){
decoder.stop();
}
}
);
decoder.start();
// 3. accessing the count variable
Log.d(TAG,"count : "+count); // still count is 0
// this won't run as count is 0
for(int i=0; i < count i++)
bitmaps.add(decoder.getFrameBitmap(i));
// and getFrameBitmap(i) is not useful inside above listener overriden methods. This returns bitmap only outside of listener.
}
I tried SharedPreference and it works but I can't use for reliablity and also app crashes.
I also Tried to use custom class. It does not give error But the value is still zero.
frameData.setFrameCount(frameCount); // setting in onStart()
frameData.getFrameCount(); // getting out of listener
but still zero because it executes before assignment
I wonder how sharedPreference gives non zero value but not this custom class
To get around the must be final you may use a
final AtomicInteger count = new AtomicInteger(0);
and then
count.addAndGet(1);
Anyway, line
Log.d(TAG,"count : "+count.get());
will always return 0, as long it is before decoder.start(). Probably you want to put into a Handler and run periodically ?.
Well a more effective way to achieve to control this would be using a LiveData object to keep track of the active counts.
Define the count variable as a MutableLiveData<Integer> and update this livedata whenever the onStart method called. This may be much faster than writing to and reading from the shared preferences. See the example snippet for an example implementation.
// Define the live data object within a correct scope in your class
MutableLiveData<Integer> mldCount = new MutableLiveData<>(0);
// In the part where you want to control and avoid the index out of bounds observe the count live data
mldCount.observe(<Pass the lifecycle owner here>, count -> {
// Check the new count here
});
public void Test5 (String path){
decoder.addRenderListener(
new WebPDecoder.RenderListener(){
#Override
public void onStart(){
// 2. assigning value to count variable
int count = decoder.getFrameCount();
// If this callback is called from a background thread use:
mldCount.postValue(count);
// If it is called in main thread then use:
mldCount.setValue(count);
Log.d(TAG, count); count is non zero
}
#Override
public void onRender(ByteBuffer byebuffer){}
#Override
public void onEnd(){
decoder.stop();
}
}
);
// This will not show the valid actual values
Log.d(TAG,"count : "+mldCount.getValue()); // still count is 0
decoder.start();
}
I got solution but won't accept is as answer beacuse it is not a solution for specified problem in question.
I invoked decoder.stop() in override OnStart() and then I could access the Bitmaps after stopping. So now no need to get frameCount outside of decoder.

How to count the times of calling a method in a inner class?

//get the number of tweets with keyword
public ArrayList<StreamStatus> getStream(String keyWord, int number) {
TwitterStream twitterStream = new TwitterStreamFactory().getInstance();
ArrayList<StreamStatus> list = new ArrayList<StreamStatus>();
StatusListener listener = new StatusListener() {
#Override
public void onStatus(Status status) {
if(status.getGeoLocation() != null) {
StreamStatus stramStatus = new StreamStatus();
list.add(stramStatus); //don't allow do that !!!
//cannot refer to a-non-final variable inside a inner class defined in a different method
}
}
};
twitterStream.addListener(listener);
String[] keyword = {"ebola"};
FilterQuery filtro = new FilterQuery().track(keyword);
twitterStream.filter(filtro);
if(list.size() == 100) {
twitterStream.cleanUp();
twitterStream.shutdown();
}
return list;
}
I use other's API to implement my programming and there is a inner class in it. It seems twitterStream will use the class many times.I want to record how many times ispublic void onStatus(Status status) called?
To saying about counter, I think that is more easy to understand my problem. Actually, I just want to know how to implement list.add(stramStatus); //don't allow do that !!! as I post above.
This:
ArrayList<StreamStatus> list = new ArrayList<StreamStatus>();
should be declared final so you can use it.
like:
final List<StreamStatus> list = new ArrayList<StreamStatus>();
the error you get should give you a hint that you aren't allowed to access non-final stack variables.
alternatively, you can hook it up to an instance variable instead. (push the list up to the class instead of inside the method).
I have my doubts if your method will get to this:
twitterStream.filter(filtro);
if(list.size() == 100) {
twitterStream.cleanUp();
twitterStream.shutdown();
}
I think the list will not be exactly 100 all the time, and I you are not looping until it gets to there. you are risking it skips past 100 and you end up missing your cleanup/shutdown. probably you need to do:
while (list.size() < 100) {
Thread.yield();
twitterStream.filter(filtro);
}
twitterStream.cleanUp();
twitterStream.shutdown();
but this is just a guess as I haven't used twitterstream before and I'm only assuming the methods work as I think they do. but just keep an eye on it. ==100 is dangerous anyways in case multipel messages push it past 100 so whatever you do probably >= 100 is better even if my suggestion is completely wrong.
The problem is, as the compiler is saying, that you're referring to a non-final variable inside an inner class. Change it to final ArrayList<StreamStatus> list = new ArrayList<StreamStatus>();.

set methods in Java

Could anubody explain how to use set methods? Problem:
class Sonum {
private int prior;
public Sonum(int prior) {
this.prior = prior;
}
public int getPrior() {
return prior;
}
public void setPrior(int prior) {
this.prior = prior;
}
class Tel {
// Please explain how can I set the value for prior? (for example 2)
}
Well, first you need an instance of Sonum on which you want to set the prior value. For example:
class Test {
public void foo() {
Sonum sonum = new Sonum(5);
// Use it with a prior of 5
// ...
sonum.setPrior(10);
// Now use it with a prior of 10
}
}
Sonum mySonum = new Sonum(1); //prior is currently 1
mySonum.setPrior(2); //now prior is 2
Take a deep breath. The Java Tutorial. Read it. You will understand.
Refer
Creating Objects & Using Objects
http://download.oracle.com/javase/tutorial/java/javaOO/objectcreation.html
"Setter methods" aren't magic. They're just regular methods. You need an instance of that class, and then you can call the methods on it. Just like any other Java object.
set method deal with a private value that we would like to prevent the direct way to him using our client, therefor there are get \ set method.
The biggest advantage of get \ set methods is the control ability !
We can for example control a minimum age when we want to set an age, and many other simple examples.
Example:
setAge (int age)
{
if ( age < 0 )
{
System.out.println ( "Wrong age !!" );
}
}
Now I think you can easily understand this HW :)

Can I un-assign (clear) all fields of an instance?

Is there a simple way to clear all fields of an instance from a an instance? I mean, I would like to remove all values assigned to the fields of an instance.
ADDED
From the main thread I start a window and another thread which controls state of the window (the last thread, for example, display certain panels for a certain period of time). I have a class which contains state of the window (on which stage the user is, which buttons he already clicked).
In the end, user may want to start the whole process from the beginning (it is a game). So, I decided. So, if everything is executed from the beginning, I would like to have all parameter to be clean (fresh, unassigned).
ADDED
The main thread, creates the new object which is executed in a new thread (and the old thread is finished). So, I cannot create a new object from the old thread. I just have a loop in the second thread.
I don't get it. How can you programmatically decide how to clear various fields?
For normal attributes it can be easy (var = null) but what about composite things or collection? Should it be collection = null, or collection.removeAll()?
This question is looking for synctactic sugar that wouldn't make so much sense..
The best way is to write out your own reset() method to customize the behaviour for every single object.. maybe you can patternize it using an
interface Resettable
{
void reset()
}
but nothing more than that..
Is there a simple way to clear all fields of an instance from a an instance? I mean, I would like to remove all values assigned to the fields of an instance.
Yes, just assign a default value to each one of them. It would take you about 20-30 mins. and will run well forever*( YMMV)
Create a method: reset and invoke it
class YourClass {
int a;
int b;
boolean c;
double d;
String f;
// and so on...
public void method1(){}
public void method2(){}
public void method3(){}
// etc.
// Magic method, reset all the attributes of your instance...
public void reset(){
a = 0;
b = 0;
c = false;
d = 0.0;
f = "";
}
}
And then just invoke it in your code:
....
YourClass object = new YourClass();
Thread thread = YourSpecificNewThread( object );
thread.start();
... // Later on you decide you have to reset the object just call your method:
object.reset(); // like new
I don't really see where's the problem with this approach.
You may use reflection:
Try something like this:
Field[] fields = object.getClass().getDeclaredFields();
for (Field f : fields) {
f.setAccessible(true);
f.set(object, null);
}
It's not a beautifull solution, but may work for you.
There is no other way than setting null to all of them.
As an aside, i find that a particular weird idea. You would have better re-creating a new instance, instead of trying to reset your old one.
If you want to clear a filter (Serializable) that your application "can handle his null" fields, you can use BeanUtils (Apache Commons):
Field[] fields = filter.getClass().getDeclaredFields();
for (Field f : fields) {
if (f.getName().endsWith("serialVersionUID")) {
continue;
}
try {
BeanUtils.setProperty(filter, f.getName(), null);
} catch (IllegalAccessException | InvocationTargetException e) {
FacesUtils.handleError(LOG, "Erro limpar filtro...", e);
}
}
I hope it can help you.

Easymock: does the order of captures matter?

This might seem like a pretty detailed question about Easymock, but I'm having a hard time finding a support site/forum/mailing list for this library.
I'm encountering a bug when using the captures() method that seems to return the captured parameters out of order.
Here's a simplified version of what I am testing:
public class CaptureTest extends TestCase {
// interface we will be mocking
interface Processor {
void process(String x);
}
// class that uses the interface above which will receive the mock
class Component {
private Processor processor;
private String[] s = { "one", "two", "three", "four" };
Component(Processor processor) {
this.processor = processor;
}
public void doSomething() {
for (int i = 0; i < s.length; i++) {
processor.process(s[i]);
}
}
}
public void testCapture() {
//create the mock, wire it up
Processor mockProcessor = createMock(Processor.class);
Component component = new Component(mockProcessor);
//we're going to call the process method four times
//with different arguments, and we want to capture
//the value passed to the mock so we can assert against it later
Capture<String> cap1 = new Capture<String>();
Capture<String> cap2 = new Capture<String>();
Capture<String> cap3 = new Capture<String>();
Capture<String> cap4 = new Capture<String>();
mockProcessor.process(and(isA(String.class), capture(cap1)));
mockProcessor.process(and(isA(String.class), capture(cap2)));
mockProcessor.process(and(isA(String.class), capture(cap3)));
mockProcessor.process(and(isA(String.class), capture(cap4)));
replay(mockProcessor);
component.doSomething();
//check what values were passed to the mock
assertEquals("one", cap1.getValue());
assertEquals("two", cap2.getValue());
assertEquals("three", cap3.getValue());
assertEquals("four", cap4.getValue());
verify(mockProcessor);
}
}
(Please note that this is just a simplified test case - I know that I could specify the exact value of the arguments I expect passed to my mock, but in my real case the arguments are complex objects with a handful of fields, and I want to capture the object so I can assert against just a few of those fields without re-creating the entire object in my test case).
When I run the test, it fails at:
junit.framework.ComparisonFailure: expected:<[one]> but was:<[four]>
Meaning that the parameter that EasyMock is capturing in cap1 is not the first call to the method, but the last (since the value is four). I get the same results if I reverse the captures() declarations, i.e. use cap4 with the first method call, etc.
This seems like it might be a bug within EasyMock - different parameters passed to the same method in different invocations don't seem to be capture correctly.
Is anyone else using capture() with EasyMock and having similar problems? Is there an easy workaround you know of, or a different way I can capture the parameters being passed to my mock's methods?
Update 1: fixed code sample to show I am using createMock, not createStrictMock, but I get the same error with both (although the actual value of what is captured changes).
I've received an answer on the bug I submitted to the Easymock sourceforge site, and a developer has confirmed it is indeed a bug with this version of Easymock.
It is indeed a bug. The capture is done even if it was already done. The
current workaround is to implement your own capture object and override
setValue to do this:
#Override
public void setValue(T value) {
if(!hasCaptured()) {
super.setValue(value);
}
}
I was playing around with your test and could not solve.
However I extended the Capture Class to see if the values were set in a different order (I was suspicious that EasyMock internally was using a hash with a key generated from the methods and the parameters) I was wrong the methods are set in the correct order. But there is something really weird going on.. It seems that the algorithm does some kind assigning pattern.. Well let me show the code and the strange output.... BTW the changes from mock, niceMock and strictMock didn't make anydifference..
class MyCapture extends Capture<String> {
private String id;
public MyCapture(String id) {
super();
System.out.printf("Constructor %s expecting %s\n", id, this.getClass().getName());
this.id = id;
}
private static final long serialVersionUID = 1540983654657997692L;
#Override
public void setValue(String value) {
System.out.printf("setting value %s expecting %s \n", value, id);
super.setValue(value);
}
#Override
public String getValue() {
System.out
.printf("getting value %s expecting %s \n", super.getValue(), id);
return super.getValue();
}
}
public void testCapture() {
// create the mock, wire it up
Processor mockProcessor = createStrictMock(Processor.class);
Component component = new Component(mockProcessor);
// we're going to call the process method four times
// with different arguments, and we want to capture
// the value passed to the mock so we can assert against it later
Capture<String> cap1 = new MyCapture("A");
Capture<String> cap2 = new MyCapture("B");
Capture<String> cap3 = new MyCapture("C");
Capture<String> cap4 = new MyCapture("D");
mockProcessor.process(and(isA(String.class), capture(cap1)));
mockProcessor.process(and(isA(String.class), capture(cap2)));
mockProcessor.process(and(isA(String.class), capture(cap3)));
mockProcessor.process(and(isA(String.class), capture(cap4)));
replay(mockProcessor);
component.doSomething();
// check what values were passed to the mock
assertEquals("A", cap1.getValue());
assertEquals("B", cap2.getValue());
assertEquals("C", cap3.getValue());
assertEquals("D", cap4.getValue());
verify(mockProcessor);
}
}
*And this is the output *
Constructor A expecting com.comp.core.dao.impl.CaptureTest$MyCapture
Constructor B expecting com.comp.core.dao.impl.CaptureTest$MyCapture
Constructor C expecting com.comp.core.dao.impl.CaptureTest$MyCapture
Constructor D expecting com.comp.core.dao.impl.CaptureTest$MyCapture
calling process A
setting value A expecting A
calling process B
setting value B expecting A <<Setting the wrong guy
setting value B expecting A <<Setting the wrong guy
setting value B expecting B <<Ops this is the right one..stop
calling process C
setting value C expecting B <<Setting the wrong guy
setting value C expecting B <<Setting the wrong guy
setting value C expecting C <<Setting the wrong guy
calling process D
setting value D expecting C <<Setting the wrong guy
setting value D expecting C <<Setting the wrong guy
setting value D expecting D <<Ops this is the right one..stop
getting value B expecting A
Sorry I can't help you more. It might be indeed a bug in easy mock.
You can also try using EasyMock.createNiceMock(...) instead of EasyMock.createStrictMock(...) or EasyMock.createMock(...).
Although, I agree that it looks more like a bug with createMock.
This is a problem more appropriate for state-based testing, I think.
With JMockit, you could solve it like this:
import mockit.*;
import static mockit.Mockit.*;
import mockit.integration.junit3.*;
public class CaptureTest extends JMockitTestCase
{
interface Processor { void process(String x); }
class Component
{
private final Processor processor;
private final String[] s = {"one", "two", "three", "four"};
Component(Processor processor) { this.processor = processor; }
public void doSomething()
{
for (String value : s) {
processor.process(value);
}
}
}
#MockClass(realClass = Processor.class)
static class MockProcessor
{
private final String[] expectedValues;
private int i;
MockProcessor(String... expectedValues) { this.expectedValues = expectedValues; }
#Mock
void process(String x)
{
assertEquals(expectedValues[i++], x);
}
}
public void testCapture()
{
Processor mockProcessor = setUpMock(new MockProcessor("one", "two", "three", "four"));
Component component = new Component(mockProcessor);
component.doSomething();
}
}
In short, here's what worked for me:
MyClass myMock = EasyMock.createStrictMock(MyClass.class);
...
EasyMock.checkOrder(myMock, true); // before the capture and verify, not sure if it matters
...
Capture<MyArg> capturedArgs = new Capture<MyArg>();
expect(myMock.search(capture(capturedArgs))).andReturn(someRandomReturn);
PS: I'm using EasyMock 3.0
Instead of calling EasyMock.createStrictMock(...) just call EasyMock.createMock(...). Should solve your problems.

Categories

Resources