I have a Bpmn file with an extension element like this.
<bpmn:extensionElements>
<zeebe:taskDefinition type="customer-interaction-service" retries="0" />
<zeebe:taskHeaders>
<zeebe:header key="operation" value="save" />
<zeebe:header key="#type" value="Organization[]" />
<zeebe:header key="updateReliesOnReferredTypes" value="#Customer.engagedParty" />
</zeebe:taskHeaders>
</bpmn:extensionElements>
I want to access the header elements and get keys and values.
I followed this tutorial for cmn but Bpmn api did not register my custom classes.
You can clone full code from here
I copppy some important parts here.
Main class:
public class Main {
public static void main(String[] args) {
InputStream is = Main.class.getResourceAsStream("/dclm-addservice.bpmn");
BpmnModelInstance model =CustomBpmn.readModelFromStream(is );
ServiceTask serviceTask=model.getModelElementById("ServiceTask_1jn441o");
int count=serviceTask.getExtensionElements().getElementsQuery().filterByType(TaskHeaders.class).count();
System.out.println(count);
count=serviceTask.getExtensionElements().getElementsQuery().count();
System.out.println(count);
}
}
result:
0
2
When filtering by TaskHeaders.class, it has 0 result.
customBpmn
public class CustomBpmn extends Bpmn {
public static CustomBpmn INSTANCE = new CustomBpmn();
public CustomBpmn() {
super();
System.out.println("constructor");
}
#Override
protected void doRegisterTypes(ModelBuilder modelBuilder) {
super.doRegisterTypes(modelBuilder);
System.out.println("registering");
HeaderImpl.registerType(modelBuilder);
TaskHeadersImpl.registerType(modelBuilder);
}
}
header interface
public interface Header extends BpmnModelElementInstance {
public String getKey();
public void setKey(String key);
public String getValue();
public void setValue(String value);
}
TaskHeaders interface
public interface TaskHeaders extends BpmnModelElementInstance {
Collection<Header> getHeaders();
void addHeader(Header header);
boolean addHeaders(List<Header> headers);
List<Header> findByKey(String key);
}
HeaderImpl
public class HeaderImpl extends BpmnModelElementInstanceImpl implements Header {
protected static Attribute<String> keyAttribute;
protected static Attribute<String> valueAttribute;
public static void registerType(ModelBuilder modelBuilder) {
ModelElementTypeBuilder typeBuilder = modelBuilder.defineType(Header.class, HEADER)
.namespaceUri(ZEEBE_SCHEMA)
.instanceProvider(new ModelTypeInstanceProvider<Header>() {
public Header newInstance(ModelTypeInstanceContext instanceContext) {
return new HeaderImpl(instanceContext);
}
});
keyAttribute =typeBuilder.stringAttribute(KEY_NAME)
.namespace(ZEEBE_SCHEMA)
.build();
valueAttribute =typeBuilder.stringAttribute(VALUE_NAME)
.namespace(ZEEBE_SCHEMA)
.build();
typeBuilder.build();
}
public HeaderImpl(ModelTypeInstanceContext instanceContext) {
super(instanceContext);
}
//some getter and setters.
TaskHeadersImple
public class TaskHeadersImpl extends BpmnModelElementInstanceImpl implements TaskHeaders {
protected static ChildElementCollection<Header> headerCollection;
public static void registerType(ModelBuilder modelBuilder) {
ModelElementTypeBuilder typeBuilder = modelBuilder.defineType(TaskHeaders.class, TASK_HEADERS)
.namespaceUri(ZEEBE_SCHEMA)
.instanceProvider(new ModelTypeInstanceProvider<TaskHeaders>() {
public TaskHeaders newInstance(ModelTypeInstanceContext instanceContext) {
return new TaskHeadersImpl(instanceContext);
}
});
SequenceBuilder sequenceBuilder = typeBuilder.sequence();
headerCollection =sequenceBuilder.elementCollection(Header.class)
.build();
typeBuilder.build();
}
public TaskHeadersImpl(ModelTypeInstanceContext instanceContext) {
super(instanceContext);
}
//some getters and setters.
Thanks.
Edit:
I could access TaskHeaders by using Zeebe java api instead of Camunda java api but the above question is still valid because TaskHeaders are not custom bpmn elements for zeebe modeler java api but are custom extension for Camunda.
Related
I have a class that loaded data from scenario steps
my first class is LoadUserStepDfn
public class LoadUserStepDfn extends LoadDataStepDfn<User> {
public LoadUserStepDfn(ReadingUserUsingPoiji readingUserUsingPoiji) {
super.readingExcelUsingPoiji = readingUserUsingPoiji;
}
#Given("^Data is loaded from \"([^\"]*)\"$")
public void data_is_loaded_from (String filePath) throws Throwable {
super.data_is_loaded_from(filePath);
}
and it call class named LoadDataStepDfn
public class LoadDataStepDfn<T> {
public List<T> data;
protected ReadingExcelUsingPoiji readingExcelUsingPoiji;
public void data_is_loaded_from (String filePath) throws Throwable {
data = readingExcelUsingPoiji.TransformExcelToClass(filePath);
}
and here is my class that reads excel and store it to java class
public abstract class ReadingExcelUsingPoiji<T> {
public List<T> TransformExcelToClass(String filePath){
PoijiOptions options = PoijiOptions.PoijiOptionsBuilder.settings().addListDelimiter(";").build();
List<T> data = Poiji.fromExcel(new File(filePath), getMyType(), options);
return data;
}
public abstract Class<T> getMyType();
}
the problem that I want to use one class I don't want it to be abstract and use another one wiche is this class
public class ReadingUserUsingPoiji extends ReadingExcelUsingPoiji<User> {
public Class<User> getMyType(){
return User.class;
}
I am trying to understand here, so you dont want #override, but rather 1 method that returns you the type of class to transform to??
Why can't it be that simple... You have a method that determines what class you should use to transform to...
I dont understand why you are using generics...your logic doesnt seem to really care for it? Especially if you have 1 ReadingExcelUsingPoiji class..it really shouldnt care.
public class ReadingExcelUsingPoiji<T> {
public List<T> transformExcelToClass(String filePath, Class<T> classToTransformTo) {
PoijiOptions options = PoijiOptions.PoijiOptionsBuilder.settings().addListDelimiter(";").build();
List<T> data = Poiji.fromExcel(new File(filePath), classToTransformTo, options);
return data;
}
public static void main(String [] args) {
ReadingExcelUsingPoiji genericConverter = new ReadingExcelUsingPoiji();
List<User> listOfUsers = genericConverter.transformExcelToClass("yourFilePath", User.class);
List<Car> listOfCars = genericConverter.transformExcelToClass("yourFilePath", Car.class);
}
}
public class LoadUserStepDfn extends LoadDataStepDfn<User> {
#Given("^Data is loaded from \"([^\"]*)\"$")
public void data_is_loaded_from (String filePath) throws Throwable {
super.data_is_loaded_from(filePath , User.class);
}
}
public class LoadDataStepDfn<T> {
public List<T> data;
protected ReadingExcelUsingPoiji readingExcelUsingPoiji;
protected void data_is_loaded_from(String filePath, Class<T> classToTransformTo) throws Throwable {
data = readingExcelUsingPoiji.transformExcelToClass(filePath, classToTransformTo);
}
}
Thymeleaf has a number of useful utilities like #strings.capitalize(...) or #lists.isEmpty(...). I'm trying to add a custom one but have no idea how to register this.
Have made a custom Util class:
public class LabelUtil {
public String[] splitDoubleWord(String str) {
return str.split("[A-Z]", 1);
}
}
Now I'm going to use it like this:
<span th:each="item : ${#labels.splitDoubleWord(name)}" th:text="${item}"></span>
Of course, it won't work because I haven't registered the Util and defined #labels var.
So, the question is how and where to do it?
This answer is for thymeleaf 2.x.
If you use thymeleaf 3.x or later, please see other answers.
public class MyDialect extends AbstractDialect implements IExpressionEnhancingDialect {
public MyDialect() {
super();
}
#Override
public String getPrefix() {
// #see org.thymeleaf.dialect.IDialect#getPrefix
return "xxx";
}
#Override
public boolean isLenient() {
return false;
}
#Override
public Map<String, Object> getAdditionalExpressionObjects(IProcessingContext ctx) {
Map<String, Object> expressions = new HashMap<>();
expressions.put("labels", new LabelUtil());
return expressions;
}
}
and register your dialect.
#Configuration
public class ThymeleafConfig {
#Bean
public MyDialect myDialect() {
return new MyDialect();
}
}
thymeleaf-extras-java8time source code is good reference for creating custom thymeleaf expressions.
The API for registering a custom expression object has changed in Thymeleaf 3, for example:
public class MyDialect extends AbstractDialect implements IExpressionObjectDialect {
MyDialect() {
super("My Dialect");
}
#Override
public IExpressionObjectFactory getExpressionObjectFactory() {
return new IExpressionObjectFactory() {
#Override
public Set<String> getAllExpressionObjectNames() {
return Collections.singleton("myutil");
}
#Override
public Object buildObject(IExpressionContext context,
String expressionObjectName) {
return new MyUtil();
}
#Override
public boolean isCacheable(String expressionObjectName) {
return true;
}
};
}
}
Hi ive been reading on some similar topics here but none of them answer my question. Some say you cant even do this which is not a good thing since I cant finnish my course in that case.
Heres som simple code. Think of each block as a separate class.
public interface Interface {
void printMessage(String meddelande);
}
public class Model implements Interface {
String message = "hej!";
public static void main(String[] args) {
Model model1 = new Model();
View view1 = new View();
model1.printMessage(model1.message); //Ska jag anropa funktionen såhär ens?
}
public void printMessage(String str) {
}
}
public class View implements Interface {
printMessage(String str) {
}
}
So, how is it now possible to tel the view to print this string from the model class without the classes knowing about each other? Its not allowed to send a reference of the model-objekt to the view-object. ; (
Define an Interface:
public interface MyInterface {
void printMessage(String str);
}
Define a class that can trigger the notification:
public class ClassNotifier {
MyInterface mInterface;
public ClassNotifier(MyInterface mInterface) {
this.mInterface = mInterface;
}
public void triggerTheMsg(String msg) {
if (mInterface != null) {
mInterface.printMessage(msg);
}
}
}
Define a class that will be informed:
public class InformedClass implements MyInterface {
public static void main(String[] args) throws Exception {
InformedClass c = new InformedClass();
ClassNotifier cn = new ClassNotifier(c);
}
#Override
public void printMessage(String newMsg) {
System.out.println("A new msg is here: " + newMsg);
}
}
How does it works?:
this is named a callback parttern, the class ClassNotifier has a reference to the interface MyInterface, which is impl. by Informed class to, so every time the ClassNotifier calls the method printMessage, the method printMessage in the class Informed will be triggered too.
I advice you to use dependency injection, for example:
public class Model {
String message = "hej!";
Interface printer;
public void Model(Interface printer) {
printer = printer;
}
public static void main(String[] args) {
Model model1 = new Model(new View());
model1.printMessage(model1.message);
}
public void printMessage(String str) {
printer.printMessage(str);
}
}
before refactor:
public interface Service {
public void hello(Person p);
}
public class BlackPersonServiceImpl implements Service {
#Override
public void hello(Person p) {
//...
}
}
public class WhitePersonServiceImpl implements Service {
#Override
public void hello(Person p) {
//...
}
}
public class BeforeRefactor {
public static void main(String[] args) {
String str = args[0];
Person p = JSON.parseObject(str, Person.class);
Service service = getServiceFromSpringContainer();
service.hello(p);
}
private static Service getServiceFromSpringContainer() {
//...
return null;
}
}
after refactor:
public interface Service {
public void hello(String str);
}
public class WhitePersonServiceImpl implements Service {
#Override
public void hello(String str) {
Person person = JSON.parseObject(str, Person.class);
//do something to person...
//...
}
}
public class AfterRefactor {
public static void main(String[] args) {
String str = args[0];
Service service = getServiceFromSpringContainer();
service.hello(str);
}
private static Service getServiceFromSpringContainer() {
//...
return null;
}
}
That's what I want(I think "pull down" is not the "right" word to describe it...).
I tried "introduce parameter object" in eclipse, and it does not work.
There are many implementations of "Service". I dont want to change them one by one.
Is there a good way to solve this problem?
Thanks!
You can do it somewhat for a single class and a single method (although it's akward and a succession of small refactoring steps), but not across several types at the same time.
I would like to create an enum containing one attribut, a list of objects extending the same interface or the same abstract class.
The objective is to have a loop on each list of my enum to call methods dynamically.
public interface Regles {
void verifier();
}
public class Regle01 implements Regles {
#Override
public void verifier() {
}
}
public class Regle02 implements Regles {
#Override
public void verifier() {
}
}
public enum ListRegles {
ENUM1(Arrays.asList(new Regle01(), new Regle02())),
ENUM2(Arrays.asList(new Regle01()))
private List<Regles> regles = new ArrayList<Regles>();
ListRegles(List<Regles> r) {
regles = r;
}
}
how can i do this please ?
enum:
public enum ListRegles {
ENUM1(new Regle01(),new Regle02()),
ENUM2(new Regle01());
private List<Regles> regles ;
ListRegles(Regles... regles) {
this.regles = new ArrayList<>(Arrays.asList(regles));
}
public void verify() {
for (Regles regle : regles) {
regle.verifier();
}
}
}
Will call verifier for Regle01 and Regle02
ListRegles.ENUM1.verify();