I'm using jbpm-console (6.0.0.Final) with custom work item handlers. I've embedded a custom work item handlers JAR in my jbpm-console WAR as described in post #7 here:
https://community.jboss.org/thread/221748
This is all fine so far, as I can successful start a process definition in jbpm-console, and it kicks off my custom WorkItemHandler code.
However, in my WorkItemHandler, I want to set some variables on the ProcessInstance. When I try something like this:
public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
// BLOWS UP HERE
//
KieSession session = kContainer.newKieSession();
WorkflowProcessInstance processInstance =
session.getProcessInstance(workItem.getProcessInstanceId());
// SET VARIABLE
processInstance.setVariable("foo", "bar");
}
It "Cannot find a default KieSession":
11:21:03,177 ERROR Exception: java.lang.RuntimeException: Cannot find a default KieSession
at org.drools.compiler.kie.builder.impl.KieContainerImpl.findKieSessionModel(KieContainerImpl.java:302) [drools-compiler-6.0.0.Final.jar:6.0.0.Final]
at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:295) [drools-compiler-6.0.0.Final.jar:6.0.0.Final]
at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:278) [drools-compiler-6.0.0.Final.jar:6.0.0.Final]
What am I missing here? Do I have to set something additional up? I'm just using the out-of-the-box (with the exception of the custom work item handler embedded jar) "demo" install from here:
http://sourceforge.net/projects/jbpm/files/jBPM%206/jbpm-6.0.0.Final
Thanks!
Do you have a kmodule.xml in your resources folder? If not maybe that's the problem. You can have a pretty simple xml file like:
<kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://jboss.org/kie/6.0.0/kmodule">
</kmodule>
Pass your kieSession into your workItemHandler as a constructor parameter.
Then your kieSession is available to your workItemHandler.
You can register your workItemHandler when you need it with the appropriate kieSession, you do not have to do it only once.
Or you pass the rulesManager at the start and generate a kieSession on demand
Related
I am using java8 for my web application. I would like to change the settings of JAVA DNS Cache.
This is the code:
java.security.Security.setProperty("networkaddress.cache.ttl", "60");
java.security.Security.setProperty("sun.net.inetaddr.negative.ttl", "10");
I would like to know where exactly I should write the code (in which class file) to reflect the changes in JVM before DNS chance gets initialised.
I would like to make the change using a java utility class file.Please suggest for the same.
And also suggest how to configure the same change in build.xml(ant)?
I agree with answers updated where they have suggested to change security file.But i would like to know the configuration in other ways too due to limitations that i have in my project.
You can also set it globally by add this line
networkaddress.cache.ttl=60
to $JAVA_HOME/jre/lib/security/java.security file.
Your best bet is to set it directly in the java.security file located in /lib/security
Note: if you are using a shared JVM, you'll need to set this in your startup command -Djava.security.properties=/DirectoryPath/filename and set the value of security.overridePropertiesFile to true.
If you want to set this in code then you have a number of options - you just need to put the code in a place that you know will be executed before the first message is processed after application startup.
My preference would be to register a ContextListener and put the code in there.
I encountered a similar issue where my java application wouldn't resolve the URL.
In addition to what is suggested ( i.e.,networkaddress.cache.ttl and networkaddress.cache.negative.ttl) I had to reset the caches in the URL Object.
URL url = new URL(urlSrt);
URLConnection con = url.openConnection();
con.setUseCaches(false);
I am not aware of (build.xml)ant. I will still give it a try just in case you are using spring framework. Following is what I did to set the networkaddress.cache.ttl at the time of application initialisation.
Define a new Java class as follows.
package com.example.util;
public class SecurityManager {
public SecurityManager() {
java.security.Security.setProperty("networkaddress.cache.ttl", "60");
}
}
Ask spring framework to instantiate the object of above class as a singleton at the time on spring container creation.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="securityManager"
class="com.example.util.SecurityManager" scope="singleton" />
</beans>
I am trying to set up a kmodule with persistence. I am using guice internally so the spring example isn't very helpful to me.
My current setup looks like that:
I have a core project that manages my sessions
I have multiple other projects that contribute sessions through META-INF/kmodule.xml files
This works fine, however I have only done this programatically (setting the environment's EntityManager and TransactionManager). Now I want to have this configuration in the kmodule so the modules themselves can define if they'd like to be persisted or not.
The issue is, that I don't know how to create the session for that, or how to configure the module. For example the easiest code snippets that I could find would look something like that:
<kmodule
xmlns="http://jboss.org/kie/6.0.0/kmodule">
<kbase name="kbase1">
<ksession name="ksession1"/>
</kbase>
</kmodule>
At which point the session is created like this:
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
KieSession kSession = kContainer.newKieSession(name);
However, how does one configure persistence in the module, or if that is not possible, how does one pass the correct session name in a programatical setup. What I have is:
// Guice inject Entitymanager and TransactionManager and setup the Environment variable env
KieSessionConfiguration ksconf = ks.newKieSessionConfiguration();
ksconf.setOption(ClockTypeOption.get("realtime"));
JPAKnowledgeService.newStatefulKnowledgeSession(kbase, ksconf, env);
I was thinking that maybe there is a way to pass the session name to the JPAKnowledgeService class through the KieSessionConfiguraton but I can't seem to find any way.
Alternatively it would be even cooler to configure that in the kmodule itself. I could use the spring approach, but I somewhat doubt that injection will work like that. As far as I know, the Postprocessor in spring would do the persistence injections. I don't think guice can do that even if I provide them?
Thanks
So I looked into it and dug into a lot of drools code to try and work this out.
All the KieContainer#newSession does is to query the model and then ask the base for a new session with the session's configuration:
public KieSession newKieSession(String kSessionName, Environment environment, KieSessionConfiguration conf) {
KieSessionModelImpl kSessionModel = (KieSessionModelImpl) getKieSessionModel(kSessionName);
if ( kSessionModel == null ) {
log.error("Unknown KieSession name: " + kSessionName);
return null;
}
if (kSessionModel.getType() == KieSessionModel.KieSessionType.STATELESS) {
throw new RuntimeException("Trying to create a stateful KieSession from a stateless KieSessionModel: " + kSessionName);
}
KieBase kBase = getKieBase( kSessionModel.getKieBaseModel().getName() );
if ( kBase == null ) {
log.error("Unknown KieBase name: " + kSessionModel.getKieBaseModel().getName());
return null;
}
KieSession kSession = kBase.newKieSession( conf != null ? conf : getKnowledgeSessionConfiguration(kSessionModel), environment );
wireListnersAndWIHs(kSessionModel, kSession);
registerLoggers(kSessionModel, kSession);
kSessions.put(kSessionName, kSession);
return kSession;
}
At the same time, this is exactly what the StoreService implementation does as well, with some advanced harry potter code to make things persistent. It however ignores the configuration of the session, which I would almost say is a bug.. (might raise one after this)
The configuration created by the KieContainer however only takes 2 options into account anyway:
private KieSessionConfiguration getKnowledgeSessionConfiguration(KieSessionModelImpl kSessionModel) {
KieSessionConfiguration ksConf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
ksConf.setOption( kSessionModel.getClockType() );
ksConf.setOption( kSessionModel.getBeliefSystem() );
return ksConf;
}
This means, that I would have 2 options to solve this:
either write my own KieContainerImpl that does the right thing (why bother...) or simulate the session configuration. I decided to do the second.
public KieSession createJPASession(final String kieBaseId, Optional<String> clockType, Optional<String> beliefSystem) {
log.info(String.format("Creating JPA Session for kieBase %s, clockType %s, beliefSystem %s", kieBaseId, clockType, beliefSystem));
KieBase kieBase = kContainer.getKieBase(kieBaseId);
KieSessionConfiguration ksConf = ks.newKieSessionConfiguration();
// Set this thing up manually. Looking at the impl/docs these are the only two options available to set.
// The Storage service will remove those options from a default session for whatever reason, however we can set this manually
// This means we can use the base configuration and have things run in a normal way
if (clockType.isPresent()) {
ksConf.setOption(ClockTypeOption.get(clockType.get()));
}
if (beliefSystem.isPresent()) {
ksConf.setOption(BeliefSystemTypeOption.get(beliefSystem.get()));
}
KieSession jpaSession = ks.getStoreServices().newKieSession(kieBase, ksConf, env);
sessions.put(jpaSession.getIdentifier(), jpaSession);
return jpaSession;
}
This last code snippet will create the configured session while making it persistent as well.
Alternatively, by casting KieContainer to KieContainerImpl one gets access to the public method needed to query the KieSession object in the KieModule. (man that's a lot of Kie's) That way one could use the same methods and access the XML configuration.
My approach is a mix of that (use xml config for KieBase/Module while programatically set the beliefesystem and the clocktype). Reason being that I do not want to depend on the internal implementation and I didn't want to bother implementing my own KieContainer and wiring it in.
I hope this helps someone out. If someone else knows the "correct" way to do that, please post it.
I am creating a Drools stateful session as described in the JBPM persistence documentation:
http://docs.jboss.org/jbpm/v5.1/javadocs/org/drools/persistence/jpa/JPAKnowledgeService.html
However, I came across the following exception
javax.persistence.TransactionRequiredException: joinTransaction has been called on a resource-local EntityManager which is unable to register for a JTA transaction.
My code is :
EntityManagerFactory emf = Persistence.createEntityManagerFactory("metadata.model");
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
env.set(EnvironmentName.TRANSACTION_MANAGER, TransactionManagerServices.getTransactionManager());
env.set(EnvironmentName.TRANSACTION, TransactionManagerServices.getTransactionManager());
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
KieBase kBase = kContainer.getKieBase();
StatefulKnowledgeSession kSession = JPAKnowledgeService.newStatefulKnowledgeSession(kBase, null, env);
The exception is thrown at the last line. Beforehand, I have bound the JDBC JTA Datasource as described in the aforementioned documentation.
PoolingDataSource ds = new PoolingDataSource();
ds.setUniqueName("jdbc/BitronixJTADataSource");
ds.setClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource");
ds.setMaxPoolSize(3);
ds.setAllowLocalTransactions(true);
ds.getDriverProperties().put("user", "root");
ds.getDriverProperties().put("password", "****");
ds.getDriverProperties().put("URL", "jdbc:mysql://localhost:3306/metadatadb");
ds.init();
I am using the EclipseLink persistence provider alongside the MySQL JDBC driver.
Finally, I have made it work. The most important mistake I was making was that I was trying to use EclipseLink as JPA provider. This approach will not work, since besides the custom persistency classes, Drools uses two other persistency-annotated classes: org.drools.persistence.info.SessionInfo and org.drools.persistence.info.WorkItemInfo. These two contain Date fields which are not annotated with the JPA Temporal annotation. They appear to be tailored specifically for Hibernate.
Another important aspect that came to my attention is the need to add the following line after setting the environment variable:
env.set(EnvironmentName.OBJECT_MARSHALLING_STRATEGIES,
new ObjectMarshallingStrategy[] {
new JPAPlaceholderResolverStrategy(domainEnv),
new SerializablePlaceholderResolverStrategy(
ClassObjectMarshallingStrategyAcceptor.DEFAULT) });
This is performed in order to announce your intention to persist the current session state using JPA.
The exception I mentioned above was, however, due to the fact that EclipseLink was creating a "ResourceLocal" transaction wrapper even though JTA was explicitly specified in persistence.xml. This is due to the fact that there was no target-server property specified. Consequently, there were no external transaction controllers attached to the database session that was created and the wrapper that was provided simply couldn't support the joinTransaction operation. To work around this issue, add the following line to your persistence.xml file:
<property name="eclipselink.target-server" value="JBoss"/>
and before initializing the datasource, add:
Configuration conf = TransactionManagerServices.getConfiguration();
conf.setJndiUserTransactionName("java:/TransactionManager");
Of course, I am presuming that BTM is being used.
I am new in Seam. I am using Rest services and in one of my rest service I am trying to get Instance by Component like,
GateAction gateAction = (GateAction) Component.getInstance(GateAction.class, true);
So with this I got error java.lang.IllegalStateException: No application context active
then to resolve this I call Lifecycle.beginCall() and Lifecycle.endCall() methods as below,
Lifecycle.beginCall();
GateActionIntf gateAction = (GateActionIntf) Component.getInstance(GateActionImpl.class, true);
Lifecycle.endCall();
where GateActionIntf is an Interface and GateActionImpl is seam component which implements GateActionIntf. But now I am getting ClassCastException.
Note : In my web service project I don't have any component.xml and seams based configuration, I have just added jboss-seam jar
Is that possible to get instance like that, without any component.xml and seams configuration? Again just highlighting I am getting the Instance but while type casting throws ClassCastException. how to resolve this?
Give the following a try:
GateActionIntf gateAction = (GateActionImpl) Component.getInstance(GateActionImpl.class, true);
What is the best approach for creating services that load a property set at runtime (bean is passed "xyz" and loads xyz.properties)? These properties files need to be able to be dropped into a folder outside the classpath before a command is entered to start the service (edit: this could happen at any time while the program is running).
I already have a system to do this that we've been using for over a year, but I'm migrating to spring to make the code more modular (customize services more easily through DI) and easier to maintain. My current method of creating an environment and then passing it with "this" to the dependencies just seems upside down from an IoC standpoint.
Is there a way to use a PropertyPlaceholderConfigurer without hardcoding the name of the property file? Maybe just a reference to a variable I pass into the constructor of the service that its dependencies can load? So far, it looks like I will have to create a service and inject its dependencies without any config and then call a separate load method for each to pass in the properties, but that just seems like I'm not really using spring.
USE CASE: The app will pool client connections to various servers and will forward requests from other applications to these servers. New profiles must be able to be added by non-programmers without taking down or restarting the app. The profiles will include basic things like host, port, and login info, but also more complex things like whether to use tcp/http, ssl/https (which will determine which client type to use), and timeouts and pool min/max/etc (which will need default values).
I tried with PropertyPlaceholderConfigurer and frankly, I couldn't wrap my head around it, somehow. It's easy enough to use when you use the existing options but I couldn't extend the framework.
So my approach was much more simple:
Create an annotation #InjectConfig which takes a config key as parameter.
In your beans/services, annotate fields or public setters with this annotation.
Write a BeanPostProcessor which takes options from a "config provider" and injects them into the fields / setters.
Now all you need is a config provider. Inject that into the post processor and you're done.
Note: I prefer annotating setters because that means you can easily configure your services from tests (just call the setters) without having to come up with smart names for 238576 config files.
EDIT If you have many configs, then a config factory might be a better choice:
Create a key to describe a config bundle (I usually use an enum or a new type here to prevent typos)
Put this key into the service when you create it (manually or via Spring)
Write a config factory that can return Properties or a Map for a config key.
Inject this factory into your service
In the init code of your service, use the key to lookup your config via the factory.
Using this approach, you can have a dummy factory that always returns the same thing in tests and a more complex factory for production.
The real factory can then be configured via spring so it knows where to look for configuration files. One approach is to register a java.io.File per config key. Now your concerns (configuring a service and loading configs) are completely separated.
PropertyPlaceholderConfigurer reads and initialize files on application context initialization and only once. So most probably you cannot configure it at runtime.
But you can have variables. For example, for my case I have default properties and user specific properties. So PropertyPlaceholderConfigurer loads properties from classpath first and after that is trying to find additional properties at defined location (user home folder). I user's property file exists so configurer loads it and override properties.
Here is my example:
<bean id="config" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true"/> <!-- do not throw exception if file not found -->
<property name="locations">
<list>
<value>classpath:server.properties</value>
<value>file:${user.home}/user.properties</value>
</list>
</property>
</bean>
I'm not sure that this answer is what you're exactly need. But I'm trying to guess what is your actual task. So if you need re-read properties runtime each time you access them you have to do it manually like you did before because spring application context helps you configure your application initial configuration.
It seems like the best approach may be to use a ServiceManager that contains the main ApplicationContext and then have each Service initialize its own FileSystemXmlApplicationContext with the main context as the parent like so:
public class ServiceManager {
ApplicationContext appContext;
String APP_HOME = System.getProperty("user.home") + File.separator;
public void init() {
//set main spring context
appContext = new AnnotationConfigApplicationContext(AppConfig.class);
}
public void start(String serviceName) throws Exception {
ApplicationContext serviceContext = new FileSystemXmlApplicationContext(
new String[]{APP_HOME + serviceName + ".xml"}, //path to child ctx
appContext); //reference to parent ctx to build hierarchy
Service service = (Service) serviceContext.getBean("service");
service.start();
}
}
The ApplicationContext is a bit heavy to be duplicating, but memory is pretty cheap these days and this provides total separation of concerns. I still have shared logging and an event system managed by the parent context, and each service is now simplified in its own config. I built a proof of concept using two services, and it seems to work fine so far. I'll add another comment once I finish the other services and finish testing.
reference:
http://techo-ecco.com/blog/spring-application-context-hierarchy-and-contextsingletonbeanfactorylocator/