I have created a Custom Task in my BPMN and have written a handler extending KogitoWorkItemHandler. The input values were obtained as the parameters and the result was pushed back as a Map<String, Object>. This was working fine in case of an single varaible.
When in case using multiple custom object inputs and expecting multiple custom object outputs, how to identify the specific output variable name corresponding to the same custom object as input, so that it can be assigned correctly?
In order to solve, we can pick the ioSpec from the currently running Node instance and then get the DataDefinition of the variables we need to use as results.
WorkItemNode node =(WorkItemNode) workItem.getNodeInstance().getNode();
IOSpecification ioSpec = node.getIoSpecification();
for(DataDefinition dataDefinition : ioSpec.getDataOutputs()){
if(dataDefinition.getType().equals(fullyQualifiedName)){
return dataDefinition.getLabel();
}
}
Here, the fullyQualifiedName is the name of the custom input object, whcih you can obtain from the input workItem.getParameters().get(parameter).getClass().getName(). It loops through all the output and finds out the name corresponding to the custom type of the input.
Related
I am fairly new to Anylogic and I am trying to figure out how to use the "CustomDistributionOfOptions" constructor to manually create a random distribution of items defined in an "Options list". My goal is to dynamically define the custom distribution of the options-list-items based on a user input. After researching solutions online on how to dynamically define a custom distribution, I came upon this solution: Dynamically Changing Distribution in AnyLogic. In this post, the user uses a constructor to create a custom distribution, which is what I want to do as well. However, every single time I try and initialize the constructor in my "Main" agent as an action on startup, I keep getting an
error that states that that method is undefined for the type Main.
I do not understand why this error keeps popping up, as the documentation states that I can just use the function "CustomDistributionOfOptions()" as a constructor. Please let me know what I am not understanding and/or missing.
Here is an example of initializing a Custom Distribution from one of my models:
CustomDistributionOfOptions<VaccineAttitude> customDistributionVaccineAttitude =
new CustomDistributionOfOptions(
VaccineAttitude.values(),
new double[]{
weight_vacc_acceptor,
weight_vacc_hesitator,
weight_vacc_rejector
},
this
);
What it is doing is declaring a new variable of type CustomDistributionOfOptions<VaccineAttitude>, where VaccineAttitude is the Option List that lists the options for the distribution. The name of the variable is customDistributionVaccineAttitude. As per the AnyLogic documentation, the constructor takes the values of the Option List, VaccineAttitude.values(), an array of weights of type double, and the agent that owns the variable. In this example, the code is located in Main, so this refers to Main.
You may query the distribution as follows:
VaccineAttitude result = customDistributionVaccineAttitude.get();
result will contain random value from the Option List VaccineAttitude drawn from the distribution according to the weights specified in the constructor.
What I'm doing
I'm using Dependency Injection to decouple my classes.
How I'm trying to do it
The class I am making constructs ObjectImplementation (the interface) Objects to hold data and it acts as a sort of container. I'm doing this to parse data and cross reference two data-sets. My problem is that I currently have object construction tied to the data being formatted a certain way. I am using the Factory pattern and a properties file "config.properties".
What I want to be able to do
I want to be able to have the factory take in an array of fields or some other similar type and be able to construct instances of the reflected object type without dependencies on the data. In this case they are Salesrep instances but other times I want to construct Salesrep instances or other classtype instances with different fields filled and different ones null without formatting the data to contain the names of fields.
The end goal
The point is so that I can construct different objects with the same container code. If I want to contain the objects differently I'll simply make a new implementation of the parent interface of this container class.
What I'm thinking is the problem
I've figured out that a Fieldmap was a good idea through previous versions of this question and my own research. Yet there is no way to actually set those fields without having something in the data to match to the Fieldmap
Extra Clarification
I really want to know if I can find a way to achieve my goal without adding field names to the data
//creates new properties object and loads in the file configuration
Properties prop = new Properties();
prop.load(SalesRepbyId.class.getResourceAsStream("config.properties"));
//reflects in the class we wish to use
Class<? extends ObjectImplementation> Classtouse = Class.forName(prop.getProperty("ObjectImplementation")).asSubclass(ObjectImplementation.class);
//initializes the data and some hashmaps to store the data or the methods of the reflected class
ArrayList<String[]> Salesrep_contactlist = FileParser.ReadFile();
Map<String, ObjectImplementation> SalesrepByIdMap = new HashMap<>();
Map<String, Method> MethodMap = new HashMap<>();
//adds in the data (fields) by constructing objects of the reflected type using the ObjectImplementation interface
for (String[] fieldarray : Salesrep_contactlist) {
ObjectImplementation object_to_add = null;
try {
//utilizes the factory pattern to return an instance of the reflected class
object_to_add = Factory.getObjectImpl(prop.getProperty("ObjectImplementation"),fieldarray);
/**
uses a method hashmap to map the name of the method to the Method object.
I did it this way because dynamic variable declarations are not possible and
I wanted to decouple Method declarations from the specific class that has
them. If i just hardcoded in which methods I get from the implementing class
that introduces extra dependencies I don't want.
**/
for (Method method:Classtouse.getMethods()) {
MethodMap.put(method.getName(),method);
}
//same as above but for fields this time
for (Field field:Classtouse.getFields()) {
FieldMap.put(field.getName(),field);
}
//object_to_add is a String[] with the format [Fieldname1:fieldinput1,Fieldname2:Fieldinput2]
//so I want to get this array and get each element, seperate the fieldname and then use that string to access the actual Field object of the same name in FieldMap
String fieldname = object_to_add.get(0).split(":").get(0)
String fieldinput = object_to_add.get(0).split(":").get(1)
Field name_example = Fieldmap.get(fieldname)
name_example.set(String.class,fieldinput)
//This requires the data to have the fieldname in it rather than just the fieldinput (or data). Also it confines the input to be strings because I don't think I can use a generic type to set this field even though potentially I would want to.
There is no way for me to dynamically set Field types without something to go off of in the data or elsewhere. In order to avoid something hard coded like: Salesrep rep = new rep (arg1,arg2,arg3 ...) I needed to use the Fieldmap and be able to match the data coming in to what fields I wanted to set. Since I didn't want to do it by order ex:
List list = new list("bob","800-352-4324","foo#example.com");
int i = 0;
for(i = 0, i > list.size(), i++){
Field field = new Field(//need a name here automatically rather than hardcoded)
field.set(object_to_add,list[i])
i++
}
The above didn't have any reference to the actual name of the Field that I actually use in my class. I didn't want that and then it dawned on me that the first line of my data (which is in CSV format) has the Field names effectively listed. ex:
(in the CSV File) foo.txt:
1: name,phonenumber,email
2: "bob","800-352-4324","foo#example.com"
3: "steve","800-444-4444","annoyingcommercials#example.com"
4: ...
Using this knowledge My solution is to use the first line of my data to specify the field names and their order so that when I take in lines as an array of these strings I can use the first line array as a reference to how to set the fields. I will know that the first element in the array should be the name the second should be the number ect ect. This way I only have to change the first line if I want to change how many fields the data holding class actually has.
puesdocode:
ObjectImpl. Classtouse = refelct in the class to use here from properties file
List(String[]) fieldarray = the raw data taken in and converted to a list of string arrays
String[] firstline = fieldarray.getfirstline()
List(String[]) restoflines = fieldarray.getallotherlines()
for i = 0, i > firstline.size(), i++{
Fieldmap.put(Name of the field from firstline[i], create a new Field object here with the Name);
Field fieldtoset = Fieldmap.get(Name of the field again)
fieldtoset.set(make an instance of the Classtouse here, restoflines[i] which represents the data in the 'Name' column)
}
For some silly reason I had it in my head that there was a way to do this without any change to the data, as if the Factory which created the object could take in arbitrary/generic arguments and somehow just know where each field went. I realized that that was silly because I needed to tell the code how to actually set the fields but In a way that it wasn't hard-coded into the class. This solution puts the dependency on the data so now its not hard-coded into the class. I should have seen this sooner.
I want to create a new column to store an array list in Parse, but I am unable to create the column (without using the dashboard). It needs to be created in the default "User" class. I've tried creating a Parse object in the user class and I tried querying for the column(hoping that if it doesn't find it, it will create it). It needs to be a column that can store an array list. I am not getting any errors in my code so I am unsure what to do next.
My experience is with the .NET API, but I suspect the principle is the same.
Parse will not create a new column simply from a read; you must set a value in at least one instance, and save it to the DB. This will create the column. Previously existing rows will contain "Undefined" for the new column value, and will not contain a key for the column.
My practice has been to derive types for my various ParseObjects. One thing this affords is that I can wrap the check for the key in my property getters, and set a default value if it is missing.
A caveat: (I'm speaking C#-ese here, so you'll have to do a mental translation) When you derive from ParseObject, you decorate the class with a ParseClassName attribute that defines the name for the document type in your database that your class is bound to. However, Parse already has a derived type, ParseUser, and when you derive from that, you must bind to the predefined "_User" class. (This is true for "_Session" and "_Role" also.)
I've got loads of the following to implement.
validateParameter(field_name, field_type, field_validationMessage, visibleBoolean);
Instead of having 50-60 of these in a row, is there some form of nested hashmap/4d array I can use to build it up and loop through them?
Whats the best approach for doing something like that?
Thanks!
EDIT: Was 4 items.
What you could do is create a new Class that holds three values. (The type, the boolean, and name, or the fourth value (you didn't list it)). Then, when creating the HashMap, all you have to do is call the method to get your three values. It may seem like more work, but all you would have to do is create a simple loop to go through all of the values you need. Since I don't know exactly what it is that you're trying to do, all I can do is provide an example of what I'm trying to do. Hope it applies to your problem.
Anyways, creating the Class to hold the three(or four) values you need.
For example,
Class Fields{
String field_name;
Integer field_type;
Boolean validationMessageVisible;
Fields(String name, Integer type, Boolean mv) {
// this.field_name = name;
this.field_type = type;
this.validationMessageVisible = mv;
}
Then put them in a HashMap somewhat like this:
HashMap map = new HashMap<String, Triple>();
map.put(LOCAL STRING FOR NAME OF FIELD, new Field(new Integer(YOUR INTEGER),new Boolean(YOUR BOOLEAN)));
NOTE: This is only going to work as long as these three or four values can all be stored together. For example if you need all of the values to be stored separately for whatever reason it may be, then this won't work. Only if they can be grouped together without it affecting the function of the program, that this will work.
This was a quick brainstorm. Not sure if it will work, but think along these lines and I believe it should work out for you.
You may have to make a few edits, but this should get you in the right direction
P.S. Sorry for it being so wordy, just tried to get as many details out as possible.
The other answer is close but you don't need a key in this case.
Just define a class to contain your three fields. Create a List or array of that class. Loop over the list or array calling the method for each combination.
The approach I'd use is to create a POJO (or some POJOs) to store the values as attributes and validate attribute by attribute.
Since many times you're going to have the same validation per attribute type (e.g. dates and numbers can be validated by range, strings can be validated to ensure they´re not null or empty, etc), you could just iterate on these attributes using reflection (or even better, using annotations).
If you need to validate on the POJO level, you can still reuse these attribute-level validators via composition, while you add more specific validations are you´re going up in the abstraction level (going up means basic attributes -> pojos -> pojos that contain other pojos -> etc).
Passing several basic types as parameters of the same method is not good because the parameters themselves don't tell much and you can easily exchange two parameters of the same type by accident in the method call.
I'm trying to get a value from the databae.
My Database query:
String GroupID1="select idCompanies from companies where Company_Name='ACME';";
here I'm calling to a javabeans which give back an ArrayLIst with one element
ArrayList<?> IdGroup1=oper.getList(GroupID1);
then, I print the result:
System.out.println(IdGroup1);
The query works fine, however I'm getting as a result:
[javabeans.ListOneElement#609f6e68]
Instead of the real value. How can I convert the java object to the real value?
you are printing the ArrayList object IdGroup1,You need to iterate to get the alues
This code will retrieve the first (and only) item from the list:
System.out.println(IdGroup1.get(0).toString());
Adding the following will prevent a nullPointerException:
if (!IdGroup1.isEmpty())
System.out.println(IdGroup1.get(0).toString());
-Added .toString() to get the value of the object
Consider what type of Object oper.getList(GroupID1) will return.
You need to accommodate for whatever object that is and then convert it to String.
You need to:
Unpackage your list (that is a list contains, and is expected by java to possibly contain multiple objects, so it doesn't automatically 'unpack' it for you if you have a list of 1 object)
Extract your string. Here java might cleverly convert a number (int, float, etc. ) to a string for you.
For part two, look at what you expect the object to be by finding the JavaDocs for whatever package is handling your database queries. Then see how to extract your string.
It might be as simple as System.out.println(IdGroup1.get(0).toString());
Where get(0) unpackages the object from the list, and toString() extracts the string.
If you still get back javabeans.ListOneElement#41ccdc4d try other methods to extract your string....toValue() perhaps? It depends on the packages you're using.