TransactionSynchronization threw exception: no transaction is in progress - spring-boot

I am trying to integrate jbpm with my springboot application. I want to execute a few process definitions programatically. I have gone through the various documentation online and I ended up with the below code.
I was to start process instances, complete user tasks, etc on various actions done by user in the application. While I try to execute the below piece of code as a POC I am getting above error.
Can someone please suggest where I could be going wrong?
Also can you please suggest the correct way to get the data persisted with a springboot application where I will be performing the human tasks via controller requests/operations on GUI by user?
I am getting above error while I am trying to start the process.
public RuntimeEngine runtimeEngine(){
log.info("Inside runimeEngine bean creation");
RuntimeEnvironment runtimeEnvironment = RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder()
.entityManagerFactory(factory)
.knowledgeBase(createKnowledgeBase()).get();
RuntimeManager manager = RuntimeManagerFactory.Factory.get().newPerRequestRuntimeManager(runtimeEnvironment);
RuntimeEngine engine = manager.getRuntimeEngine(EmptyContext.get());
log.info("runimeEngine bean creation completed successfully");
return engine;
}
#Bean
public KieBase createKnowledgeBase() {
org.kie.internal.utils.KieHelper helper = new org.kie.internal.utils.KieHelper();
KieBase base = helper
.addResource(ResourceFactory.newClassPathResource("workflow/HumanProcessExample.bpmn"), ResourceType.BPMN2)
.addResource(ResourceFactory.newClassPathResource("workflow/all-adjustments.bpmn"), ResourceType.BPMN2)
.build();
log.info("Kie Base loaded successfully");
return base;
}
public void testMethod(){
log.info("Inside testMethod");
KieSession ksession = kiebase.newKieSession();
ksession.getWorkItemManager().registerWorkItemHandler("Jimit-Human-Task.HumanProcessExample", new HumanTaskWorkItemHandler());
Map<String, Object> variables = new HashMap<>();
variables.put("isApproved", Boolean.TRUE);
ksession.getWorkItemManager().registerWorkItemHandler("Human Task", new AllAdjustmentsWorkItemHandler());
ProcessInstance processInstance = ksession.startProcess("all-adjustments.all-adjustments");
System.out.println("The list of process ids is"+processInstance);
}

Related

Spring Integration Sftp : Sometimes taking over 15 min to complete the operation

I am using Spring integration sftp to put files on a remote server and below is configuration.
<spring-integration.version>5.2.5.RELEASE</spring-integration.version>
I have configurated #MessagingGateway.
#MessagingGateway
public interface SftpMessagingGateway {
#Gateway(requestChannel = "sftpOutputChannel")
void sendToFTP(Message<?> message);
}
I have configured the MessageHandler as below,
#Bean
#ServiceActivator(inputChannel = "sftpOutputChannel" )
public MessageHandler genericOutboundhandler() {
SftpMessageHandler handler = new SftpMessageHandler(outboundTemplate(), FileExistsMode.APPEND);
handler.setRemoteDirectoryExpressionString("headers['remote_directory']");
handler.setFileNameGenerator((Message<?> message) -> ((String) message.getHeaders().get(Constant.FILE_NAME_KEY)));
handler.setUseTemporaryFileName(false);
return handler;
}
I have configured SftpRemoteFileTemplate as below
private SftpRemoteFileTemplate outboundTemplate;
public SftpRemoteFileTemplate outboundTemplate(){
if (outboundTemplate == null) {
outboundTemplate = new SftpRemoteFileTemplate(sftpSessionFactory());
}
return outboundTemplate;
}
This is the configuration for SessionFactory
public SessionFactory<LsEntry> sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory();
factory.setHost(host);
factory.setPort(port);
factory.setUser(username);
factory.setPassword(password);
factory.setAllowUnknownKeys(true);
factory.setKnownHosts(host);
factory.setSessionConfig(configPropertiesOutbound());
CachingSessionFactory<LsEntry> csf = new CachingSessionFactory<LsEntry>(factory);
csf.setSessionWaitTimeout(1000);
csf.setPoolSize(10);
csf.setTestSession(true);
return csf;
}
I have configured all this in one of the service.
Now the problem is,
Sometimes the entire operation takes more than 15 min~ specially if the service is ideal for few hours and I am not sure what is causing this issue.
It looks like it is spending time on getting the active session from CachedSessionFactory the after operations are pretty fast below is the snap from one of the tool where I have managed to capture the time.
It usually takes few miliseconds to transfer files.
I have recently made below changes but before that as well I was getting the same issue,
I have set isShareSession to false earlier it was DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
There was no pool size I have set it to 10
I think I have configured something incorrectly and that's why I end up piling connection ? Or there is something else ?
Observation :
The time taking to complete the operation is somewhat similar all the time when issue occurs i.e 938000 milliseconds +
If I restart the application daily it works perfectly fine.

Dynamically generate Application.properties file in spring boot

I have came across a situation where I need to fetch cron expression from database and then schedule it in Spring boot. I am fetching the data using JPA. Now the problem is in spring boot when I use #Scheduled annotation it does not allow me to use the db value directly as it is taken only constant value. So, what I am planning to do is to dynamically generate properties file and read cron expression from properties file. But here also I am facing one problem.The dynamically generated properties file created in target directory.
So I cant use it the time of program loading.
So can anyone assist me to read the dynamically generated file from the resource folder or how to schedule cron expression fetching from DB in spring boot?
If I placed all the details of corn expression in properties file I can schedule the job.
Latest try with dynamically generate properties file.
#Configuration
public class CronConfiguration {
#Autowired
private JobRepository jobRepository;
#Autowired
private ResourceLoader resourceLoader;
#PostConstruct
protected void initialize() {
updateConfiguration();
}
private void updateConfiguration() {
Properties properties = new Properties();
List<Job> morningJobList=new ArrayList<Job>();
List<String> morningJobCornExp=new ArrayList<String>();
// Map<String,String> map=new HashMap<>();
int num=1;
System.out.println("started");
morningJobList= jobRepository.findByDescriptionContaining("Morning Job");
for(Job job:morningJobList) {
//morningJobURL.add(job.getJobUrl());
morningJobCornExp.add(job.getCronExp());
}
for(String cron:morningJobCornExp ) {
properties.setProperty("cron.expression"+num+"=", cron);
num++;
}
Resource propertiesResource = resourceLoader.getResource("classpath:application1.properties");
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(propertiesResource.getFile()))) {
properties.store(out, null);
} catch (Exception ex) {
// Handle error
ex.printStackTrace();
}
}
}
Still it is not able to write in properties file under resource folder.
Consider using Quartz Scheduler framework. It stores scheduler info in DB. No need to implement own DB communication, it is already provided.
Found this example: https://www.callicoder.com/spring-boot-quartz-scheduler-email-scheduling-example/

Spring Boot with CXF Client Race Condition/Connection Timeout

I have a CXF client configured in my Spring Boot app like so:
#Bean
public ConsumerSupportService consumerSupportService() {
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
jaxWsProxyFactoryBean.setServiceClass(ConsumerSupportService.class);
jaxWsProxyFactoryBean.setAddress("https://www.someservice.com/service?wsdl");
jaxWsProxyFactoryBean.setBindingId(SOAPBinding.SOAP12HTTP_BINDING);
WSAddressingFeature wsAddressingFeature = new WSAddressingFeature();
wsAddressingFeature.setAddressingRequired(true);
jaxWsProxyFactoryBean.getFeatures().add(wsAddressingFeature);
ConsumerSupportService service = (ConsumerSupportService) jaxWsProxyFactoryBean.create();
Client client = ClientProxy.getClient(service);
AddressingProperties addressingProperties = new AddressingProperties();
AttributedURIType to = new AttributedURIType();
to.setValue(applicationProperties.getWex().getServices().getConsumersupport().getTo());
addressingProperties.setTo(to);
AttributedURIType action = new AttributedURIType();
action.setValue("http://serviceaction/SearchConsumer");
addressingProperties.setAction(action);
client.getRequestContext().put("javax.xml.ws.addressing.context", addressingProperties);
setClientTimeout(client);
return service;
}
private void setClientTimeout(Client client) {
HTTPConduit conduit = (HTTPConduit) client.getConduit();
HTTPClientPolicy policy = new HTTPClientPolicy();
policy.setConnectionTimeout(applicationProperties.getWex().getServices().getClient().getConnectionTimeout());
policy.setReceiveTimeout(applicationProperties.getWex().getServices().getClient().getReceiveTimeout());
conduit.setClient(policy);
}
This same service bean is accessed by two different threads in the same application sequence. If I execute this particular sequence 10 times in a row, I will get a connection timeout from the service call at least 3 times. What I'm seeing is:
Caused by: java.io.IOException: Timed out waiting for response to operation {http://theservice.com}SearchConsumer.
at org.apache.cxf.endpoint.ClientImpl.waitResponse(ClientImpl.java:685) ~[cxf-core-3.2.0.jar:3.2.0]
at org.apache.cxf.endpoint.ClientImpl.processResult(ClientImpl.java:608) ~[cxf-core-3.2.0.jar:3.2.0]
If I change the sequence such that one of the threads does not call this service, then the error goes away. So, it seems like there's some sort of a race condition happening here. If I look at the logs in our proxy manager for this service, I can see that both of the service calls do return a response very quickly, but the second service call seems to get stuck somewhere in the code and never actually lets go of the connection until the timeout value is reached. I've been trying to track down the cause of this for quite a while, but have been unsuccessful.
I've read some mixed opinions as to whether or not CXF client proxies are thread-safe, but I was under the impression that they were. If this actually not the case, and I should be creating a new client proxy for each invocation, or use a pool of proxies?
Turns out that it is an issue with the proxy not being thread-safe. What I wound up doing was leveraging a solution kind of like one posted at the bottom of this post: Is this JAX-WS client call thread safe? - I created a pool for the proxies and I use that to access proxies from multiple threads in a thread-safe manner. This seems to work out pretty well.
public class JaxWSServiceProxyPool<T> extends GenericObjectPool<T> {
JaxWSServiceProxyPool(Supplier<T> factory, GenericObjectPoolConfig poolConfig) {
super(new BasePooledObjectFactory<T>() {
#Override
public T create() throws Exception {
return factory.get();
}
#Override
public PooledObject<T> wrap(T t) {
return new DefaultPooledObject<>(t);
}
}, poolConfig != null ? poolConfig : new GenericObjectPoolConfig());
}
}
I then created a simple "registry" class to keep references to various pools.
#Component
public class JaxWSServiceProxyPoolRegistry {
private static final Map<Class, JaxWSServiceProxyPool> registry = new HashMap<>();
public synchronized <T> void register(Class<T> serviceTypeClass, Supplier<T> factory, GenericObjectPoolConfig poolConfig) {
Assert.notNull(serviceTypeClass);
Assert.notNull(factory);
if (!registry.containsKey(serviceTypeClass)) {
registry.put(serviceTypeClass, new JaxWSServiceProxyPool<>(factory, poolConfig));
}
}
public <T> void register(Class<T> serviceTypeClass, Supplier<T> factory) {
register(serviceTypeClass, factory, null);
}
#SuppressWarnings("unchecked")
public <T> JaxWSServiceProxyPool<T> getServiceProxyPool(Class<T> serviceTypeClass) {
Assert.notNull(serviceTypeClass);
return registry.get(serviceTypeClass);
}
}
To use it, I did:
JaxWSServiceProxyPoolRegistry jaxWSServiceProxyPoolRegistry = new JaxWSServiceProxyPoolRegistry();
jaxWSServiceProxyPoolRegistry.register(ConsumerSupportService.class,
this::buildConsumerSupportServiceClient,
getConsumerSupportServicePoolConfig());
Where buildConsumerSupportServiceClient uses a JaxWsProxyFactoryBean to build up the client.
To retrieve an instance from the pool I inject my registry class and then do:
JaxWSServiceProxyPool<ConsumerSupportService> consumerSupportServiceJaxWSServiceProxyPool = jaxWSServiceProxyPoolRegistry.getServiceProxyPool(ConsumerSupportService.class);
And then borrow/return the object from/to the pool as necessary.
This seems to work well so far. I've executed some fairly heavy load tests against it and it's held up.

Removing/shutdown Firebase in Java app (for hot redepoy)

I tried to use org.springframework.boot:spring-boot-devtools to speed up development.
My project uses Firebase to authenticate some requests. Firebase initialized via:
#PostConstruct
public void instantiateFirebase() throws IOException {
FirebaseOptions options = new FirebaseOptions.Builder()
.setDatabaseUrl(String.format("https://%s.firebaseio.com", configuration.getFirebaseDatabase()))
.setServiceAccount(serviceJson.getInputStream())
.build();
FirebaseApp.initializeApp(options);
}
After context reloading on changing .class file Spring reports error:
Caused by: java.lang.IllegalStateException: FirebaseApp name [DEFAULT] already exists!
at com.google.firebase.internal.Preconditions.checkState(Preconditions.java:173)
at com.google.firebase.FirebaseApp.initializeApp(FirebaseApp.java:180)
at com.google.firebase.FirebaseApp.initializeApp(FirebaseApp.java:160)
What Firebase API allow deregister/destroy FirebaseApp that I should use in #PreDestroy?
Looks like it is not possible to disable/shutdown/reinitialize Firebase app.
In my case it is fine to keep that instance in memory without changes.
Depending on your requirements you may use as simple as:
#PostConstruct
public void instantiateFirebase() throws IOException {
// We use only FirebaseApp.DEFAULT_APP_NAME, so check is simple.
if ( ! FirebaseApp.getApps().isEmpty())
return;
Resource serviceJson = applicationContext.getResource(String.format("classpath:firebase/%s", configuration.getFirebaseServiceJson()));
FirebaseOptions options = new FirebaseOptions.Builder()
.setDatabaseUrl(String.format("https://%s.firebaseio.com", configuration.getFirebaseDatabase()))
.setServiceAccount(serviceJson.getInputStream())
.build();
FirebaseApp.initializeApp(options);
}
or filter data like:
for (FirebaseApp app : FirebaseApp.getApps()) {
if (app.getName().equals(FirebaseApp.DEFAULT_APP_NAME))
return;
}

How do I create a Quartz.NET’s job requiring injection with autofac

I am trying to get Quartz.net (2.1.2) to work with an IoC container (autofac), as I have services I need to use in the scheduled jobs. I have found similar posts on the subject, but I can't seem to find one with a specific registration example for autofac.
The following post deals with the same issue I am having:
How to schedule task using Quartz.net 2.0?
However, the part I believe I am missing is when the answer says "And don't forget to register the job in the IoC container". I am unsure how to do this exactly, as everything I have tried so far hasn't worked.
In the following example, the "HelloJob" will run, but whenever I try to inject the releaseService into the "ReleaseJob" it refuses to run.
Update:
I marked the code in the DependencyRegistration.cs section where I believe the issue is.
Update 2:
Some related links that are related to what I need to do and might help (I've already gone through them all but still cannot figure out how to get this working with autofac):
HOW TO use Quartz.NET in PRO way?
- http://blog.goyello.com/2009/09/21/how-to-use-quartz-net-in-pro-way/
Autofac and Quartz.NET
- http://blog.humann.info/post/2013/01/30/Autofac-and-QuartzNET.aspx
Constructor injection with Quartz.NET and Simple Injector
- Constructor injection with Quartz.NET and Simple Injector
ASP.Net MVC 3, Ninject and Quartz.Net - How to?
- ASP.Net MVC 3, Ninject and Quartz.Net - How to?
Here is the relevant code:
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
var dependencyRegistration = new DependencyRegistration();
dependencyRegistration.Register();
ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(new ValidatorFactory()));
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
}
DependencyRegistration.cs
public class DependencyRegistration
{
public void Register()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly());
// Validation
builder.RegisterType<ValidatorFactory>()
.As<IValidatorFactory>()
.InstancePerHttpRequest();
AssemblyScanner findValidatorsInAssembly = AssemblyScanner.FindValidatorsInAssembly(Assembly.GetExecutingAssembly());
foreach (AssemblyScanner.AssemblyScanResult item in findValidatorsInAssembly)
{
builder.RegisterType(item.ValidatorType)
.As(item.InterfaceType)
.InstancePerHttpRequest();
}
// Schedule
builder.Register(x => new StdSchedulerFactory().GetScheduler()).As<IScheduler>();
// Schedule jobs
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).Where(x => typeof(IJob).IsAssignableFrom(x));
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
//Schedule
IScheduler sched = container.Resolve<IScheduler>();
sched.JobFactory = new AutofacJobFactory(container);
sched.Start();
IJobDetail job = JobBuilder.Create<ReleaseJob>()
.WithIdentity("1Job")
.Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("1JobTrigger")
.WithSimpleSchedule(x => x
.RepeatForever()
.WithIntervalInSeconds(5)
)
.StartNow()
.Build();
sched.ScheduleJob(job, trigger);
job = JobBuilder.Create<HelloJob>()
.WithIdentity("2Job")
.Build();
trigger = TriggerBuilder.Create()
.WithIdentity("2JobTrigger")
.WithSimpleSchedule(x => x
.RepeatForever()
.WithIntervalInSeconds(5)
)
.StartNow()
.Build();
sched.ScheduleJob(job, trigger);
}
}
JobFactory.cs
public class AutofacJobFactory : IJobFactory
{
private readonly IContainer _container;
public AutofacJobFactory(IContainer container)
{
_container = container;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return (IJob)_container.Resolve(bundle.JobDetail.JobType);
}
public void ReturnJob(IJob job)
{
}
}
ReleaseJob.cs
public class ReleaseJob : IJob
{
private readonly IReleaseService _releaseService;
public ReleaseJob(IReleaseService releaseService)
{
this._releaseService = releaseService;
}
public void Execute(IJobExecutionContext context)
{
Debug.WriteLine("Release running at " + DateTime.Now.ToString());
}
}
public class HelloJob : IJob
{
public void Execute(IJobExecutionContext context)
{
Debug.WriteLine("Hello job at " + DateTime.Now.ToString());
}
}
ReleaseServiceModel.cs
public class ReleaseServiceModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ReleaseService>()
.As<IReleaseService>()
.InstancePerLifetimeScope();
}
}
I finally tracked down what the issue was.
My release service was using a data repository which was being created with a different scope.
I discovered this by creating a new test service that did nothing but return a string, and that worked being injected into a quartz job.
On discovering this, I changed the scope of the repository called upon by the release service , and then the release service started working inside the quartz job.
My apologies to anyone that looked at this question to try and help me out. Because the code of the release service was not listed, it would have been difficult to figure out what was wrong.
I have updated the code with the final working bindings I used for quartz with autofac.
The problem is that your AutofacJobFactory is not creating the ReleaseJob (you are doing this with JobBuilder.Create<ReleaseJob>() instead), so the IoC container is not aware of it's instantiation meaning dependency injection cannot occur.
The following code should work:
sched = schedFact.GetScheduler();
sched.JobFactory = new AutofacJobFactory(container);
sched.Start();
// construct job info
JobDetailImpl jobDetail = new JobDetailImpl("1Job", null, typeof(ReleaseJob ));
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("1JobTrigger")
.WithSimpleSchedule(x => x
.RepeatForever()
.WithIntervalInSeconds(5)
)
.StartNow()
.Build();
sched.ScheduleJob(jobDetail, trigger);
Note that in this example we are not using JobBuilder.Create<ReleaseJob>() anymore, instead we pass the details of the job to be created via the JobDetailImpl object and by doing this the scheduler's jobfactory (the AutofacJobFactory) is responsible for instantiating the job and Dependency injection can occur.

Resources