Why does Camunda generate a numeric process instance ID, instead of UUID? - java

Camunda normally uses UUIDs (e. g. 98631715-0b07-11ec-ab3b-68545a6e5055) as process instance IDs. In my project a process instance ID like 124 is being generated which looks suspicious to me.
This behavior can be reproduced as described below.
Step 1
Check out this repository and start the process engines
core-processes,
core-workflow and
domain-hello-world
so that all of them use the same shared database.
Step 2
Login to the Camunda UI at http://localhost:8080 and navigate to the tasklist.
Start the Starter process in tasklist.
Step 3
Go to the cockpit and navigate to Running process instances (http://localhost:8080/camunda/app/cockpit/default/#/processes).
Click on DomainProcess.
In column ID you will see a numeric (135 in the screenshot above) process instance ID, not a UUID.
Probable cause of the error
In core-processs engine I have the following Config class:
import org.camunda.bpm.engine.impl.history.HistoryLevel;
import org.camunda.bpm.engine.impl.history.event.HistoryEvent;
import org.camunda.bpm.engine.impl.history.handler.CompositeHistoryEventHandler;
import org.camunda.bpm.engine.impl.history.handler.HistoryEventHandler;
import org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import static org.apache.commons.lang3.ArrayUtils.addAll;
#Configuration
public class Config {
private static final Logger LOGGER = LoggerFactory.getLogger(Config.class);
#Autowired
#Qualifier("camundaBpmDataSource")
private DataSource dataSource;
#Autowired
#Qualifier("camundaTxManager")
private PlatformTransactionManager txManager;
#Autowired
private ResourcePatternResolver resourceLoader;
#Bean
public SpringProcessEngineConfiguration processEngineConfiguration() {
final SpringProcessEngineConfiguration config = new SpringProcessEngineConfiguration();
config.setDataSource(dataSource);
config.setTransactionManager(txManager);
config.setDatabaseSchemaUpdate("true");
config.setHistory(HistoryLevel.HISTORY_LEVEL_FULL.getName());
config.setJobExecutorActivate(true);
config.setMetricsEnabled(false);
final Logger logger = LoggerFactory.getLogger("History Event Handler");
final HistoryEventHandler testHistoryEventHandler = new HistoryEventHandler() {
#Override
public void handleEvent(final HistoryEvent evt) {
LOGGER.debug("handleEvent | " + evt.getProcessInstanceId() + " | "
+ evt.toString());
}
#Override
public void handleEvents(final List<HistoryEvent> events) {
for (final HistoryEvent curEvent : events) {
handleEvent(curEvent);
}
}
};
config.setHistoryEventHandler(new CompositeHistoryEventHandler(Collections.singletonList(testHistoryEventHandler)));
try {
final Resource[] bpmnResources = resourceLoader.getResources("classpath:*.bpmn");
final Resource[] dmnResources = resourceLoader.getResources("classpath:*.dmn");
config.setDeploymentResources(addAll(bpmnResources, dmnResources));
} catch (final IOException exception) {
exception.printStackTrace();
LOGGER.error("An error occurred while trying to deploy BPMN and DMN files", exception);
}
return config;
}
}
If I remove this configuration (or comment the #Configuration line), the error disappears.
Questions
Why does Camunda generate a numeric process instance ID in this case (and not a UUID as in other cases)?

After adding the line
config.setIdGenerator(new StrongUuidGenerator());
in the configuration class
#Bean
public SpringProcessEngineConfiguration processEngineConfiguration() {
final SpringProcessEngineConfiguration config = new SpringProcessEngineConfiguration();
config.setIdGenerator(new StrongUuidGenerator());
config.setDataSource(dataSource);
the process instance IDs became UUIDs again.
For details see Camunda documentation on ID generators.

Related

Moving a file from a directory to a success directory or an error directory with Spring Integration

I am trying to implement a Spring Integration class that takes a .xml file parses it and if it's valid move it to an "archived" directory and in case of invalidity move it to an error directory.
import com.nagarro.studentapi.integration.queue.StudentSender;
import com.nagarro.studentapi.util.XmlParser;
import org.aopalliance.aop.Advice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.InboundChannelAdapter;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.dsl.Pollers;
import org.springframework.integration.file.FileHeaders;
import org.springframework.integration.file.FileReadingMessageSource;
import org.springframework.integration.file.FileWritingMessageHandler;
import org.springframework.integration.file.filters.SimplePatternFileListFilter;
import org.springframework.integration.file.support.FileExistsMode;
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
import org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import java.io.File;
#Configuration
#EnableIntegration
public class IntegrationConfiguration {
private static final String XML = "*.xml";
private static final String STUDENT = "\\student.xml";
#Value("${student-api.xmlPath}")
private String inputPath;
#Value("${student-api.archivedDestination}")
private String successPath;
#Value("${student-api.errorDestination}")
private String errorPath;
#Bean
public MessageChannel messageChannel() {
return new DirectChannel();
}
#Bean
#InboundChannelAdapter(value = "messageChannel")
public MessageSource<File> messageProducer() {
FileReadingMessageSource messageSource = new FileReadingMessageSource();
messageSource.setDirectory(new File(inputPath));
messageSource.setFilter(new SimplePatternFileListFilter(XML));
return messageSource;
}
#Bean
#ServiceActivator(inputChannel = "messageChannel")
public MessageHandler handler() {
FileWritingMessageHandler handler = new FileWritingMessageHandler(new File(successPath));
handler.setFileExistsMode(FileExistsMode.REPLACE);
handler.setExpectReply(false);
return handler;
}
#Bean
public IntegrationFlow integrationFlow(XmlParser xmlParser) {
return IntegrationFlows.from(messageProducer(), spec -> spec.poller(Pollers.fixedDelay(1000)))
.enrichHeaders(h -> h.headerExpression(FileHeaders.ORIGINAL_FILE, "payload"))
.convert(String.class)
.transform((String path) -> xmlParser.parsePath(path))
.handle("xmlParser", "parsePath", e -> e.advice(errorAdvice()))
.get();
}
#Bean
public AbstractRequestHandlerAdvice errorAdvice() {
return new AbstractRequestHandlerAdvice() {
#Override
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) {
File file = message.getHeaders().get(FileHeaders.ORIGINAL_FILE, File.class);
try {
Object result = callback.execute();
file.renameTo(new File(successPath, STUDENT));
System.out.println("File renamed after success");
return result;
}
catch (Exception e) {
file.renameTo(new File(errorPath, STUDENT));
System.out.println("File renamed after failure");
throw e;
}
}
};
}
}
However whenever calback.execute() it's called I get this error and I don't quite understand why.
2022-09-06 18:20:07.971 ERROR 32152 --- [ scheduling-1] o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessageHandlingException: error occurred during processing message in 'MethodInvokingMessageProcessor' [org.springframework.integration.handler.MethodInvokingMessageProcessor#1135e3d6]; nested exception is java.lang.IllegalArgumentException: No candidate methods found for messages., failedMessage=GenericMessage [payload=Student(firstname=John, lastname=Dose, cnp=123, birthDate=2000-12-12, address=Address(street=a, number=1, city=Craiova, country=Romania), grades=[Grade(discipline=a, date=2021-12-12, grade=10), Grade(discipline=b, date=2021-12-12, grade=9)]), headers={....
Although I have a message handler I suspect the reason for this problem is that i do not override the handle method. But i am unsure of how to do it.
You have several problem:
#InboundChannelAdapter and IntegrationFlows.from(messageProducer(). This way you create two independent polling endpoints for the same source.
#ServiceActivator - the endpoint to write has just read file from one of the sources.
There is no connection between #InboundChannelAdapter, your #ServiceActivator expectations and that flow.
You have .transform((String path) -> xmlParser.parsePath(path)) and then immediately after that handle("xmlParser", "parsePath") which looks, essentially the same, but does not make sense since you are going to call the same parsePath() twice, but for different payloads, where the second one is going to be as a result of the first parsePath() call.
Please, revise your logic carefully: right now some of your configuration is misleading and really error-prone. I believe that error you got is because your parsePath() expects a String, but not Student as we see in the payload for that handle().

Cannot find cache named xxx for Builder with Ehcache

Just trying Caching in spring boot for the first time and getting the following error
Request processing failed; nested exception is java.lang.IllegalArgumentException: Cannot find cache named 'PERSON_CACHE' for Builder[public java.util.Optional com.abdulsamadsyed.person.service.PersonService.findOne(java.lang.Long) throws java.lang.InterruptedException] caches=[PERSON_CACHE] | key='#id' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'] with root cause
Can someone guide me if my configuration looks okay if not can someone suggest corrections?
Configuration Class
package com.abdulsamadsyed.person.Config;
import com.abdulsamadsyed.person.model.Person;
import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.ResourcePools;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.ehcache.CacheManager;
import java.time.Duration;
#Configuration
#EnableCaching
public class CacheConfig {
public final static String PERSON_CACHE = "PERSON_CACHE";
#Bean
CacheManager ehCacheManager() {
ResourcePools resourcePool = ResourcePoolsBuilder.heap(100).offheap(32, MemoryUnit.MB).build();
CacheConfiguration configuration = CacheConfigurationBuilder
.newCacheConfigurationBuilder(Integer.class, Person.class, resourcePool)
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(10)))
.build();
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache(PERSON_CACHE, configuration)
.build();
cacheManager.init();
return cacheManager;
}
}
Usage class
#Cacheable(value = CacheConfig.PERSON_CACHE, key = "#{id}")
public Optional<Person> findOne(Long id) throws InterruptedException {
System.out.println("Prending Remote call");
Thread.sleep(4000);
return personRepository.findById(id);
}
which is called from controller
#GetMapping("/persons/{id}")
public Optional<Person> getPersons(#PathVariable Long id) throws InterruptedException {
return personService.findOne(id);
}

Implementing Custom EhCache

We have a requirement to Cache requests to a max of upto 2 categories per userId-sessionID pair. We are planning to use EhCache for this approach. The project is a spring boot application.
#Cacheable(value="products")
ProductList getProducts(String userID, String sessionID, String categoryID) {
return getProductListForThisUserAndSessionAndCategory(userId, sessionId, categoryId;)
}
The problem is how can I set the limit to a max of 2 cache elements per userID-sessionId when there could be more than one categories per user and session id pair?
One approach:
Setting a partial key of sessionId and userID and create a custom cache which can accept a max two values per sessionID-userID key. How does EhCache support custom Caches?
Any other approaches?
If I got your question right you will change the maximum number of mappings to cache you can config like this
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.expiry.Duration;
import org.ehcache.expiry.Expirations;
import org.ehcache.jsr107.Eh107Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PreDestroy;
import java.util.concurrent.TimeUnit;
#Configuration
#EnableCaching
public class CacheConfiguration {
private final Logger log = LoggerFactory.getLogger(CacheConfiguration.class);
private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration;
#PreDestroy
public void destroy() {
log.info("Remove Cache Manager metrics");
log.info("Closing Cache Manager");
}
public CacheConfiguration(JHipsterProperties jHipsterProperties) {
jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(
CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class,
ResourcePoolsBuilder.heap(2))
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(3600, TimeUnit.SECONDS)))
.build()
);
}
#Bean
public JCacheManagerCustomizer cacheManagerCustomizer() {
log.debug("Starting Ehcache");
return cm -> {
cm.createCache("products", jcacheConfiguration);
};
}
}

Spring is not running my #Scheduled(cron = "0,30 * * * * *")

Following is code
I am using spring.boot.version 1.4.1.RELEASE now
Nothing is printed when I start the server
I am using #Scheduled annotation to run a cron job but It never starts
Same code works fine if I create new project and use following classes
Please suggest what can possibly go wrong ?
package com.equilar.bsp;
import java.util.TimeZone;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.boot.orm.jpa.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableScheduling;
import com.amazonaws.http.IdleConnectionReaper;
import com.cloudinary.Cloudinary;
import com.equilar.bsp.config.RedisConfig;
import com.equilar.bsp.config.SecurityConfig;
import com.equilar.bsp.mvc.MvcConfig;
import com.equilar.bsp.util.JwtTokenGenerator;
import com.equilar.bsp.util.Util;
#SpringBootApplication
#EnableScheduling
#Configuration
#EnableAutoConfiguration
#EnableJpaAuditing
//#ComponentScan(basePackages = "com.equilar" ,lazyInit = true)
#EnableJpaRepositories("com.equilar")
#EntityScan({"com.equilar.bsp.domain", "com.equilar.newcommon.folder.domain", "com.equilar.newcommon.pdf.domain"})
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
// set default timezone first thing!!
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
SpringApplication.run(Application.class, args);
JwtTokenGenerator.getStartTime();
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass, SecurityConfig.class, MvcConfig.class, RedisConfig.class);
}
private static Class<Application> applicationClass = Application.class;
#PreDestroy
private void cleanUp() {
/* try {
// Shutting down AWS IdleConnectionReaper thread...
IdleConnectionReaper.shutdown();
List<Thread> threadsList = getThreadByName("logback-loggly-appender");
if(!Util.isNullOrEmptyCollection(threadsList)){
for (Thread thread : threadsList) {
thread.interrupt();
}
}
} catch (Throwable t) {
// log error
t.printStackTrace();
}*/
}
/*public List<Thread> getThreadByName(String threadName) {
List<Thread> threads = new ArrayList<Thread>();
for (Thread t : Thread.getAllStackTraces().keySet()) {
if (t.getName().equals(threadName)){
threads.add(t);
}
}
return threads;
}*/
#Value("${CLOUDINARY_URL}")
private String cloudinaryUrl;
#Bean(name = "cloudinary")
public Cloudinary Instance() {
return new Cloudinary(cloudinaryUrl);
}
}
package com.equilar.bsp.calc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
#org.springframework.stereotype.Component
public class Component {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Scheduled(
cron = "0,30 * * * * *")
public void cronJob() {
logger.info("> cronJob");
logger.info("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>> In Chron Job."
);
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
}
}
Your code sample looks totally fine for me. Moreover, I've created a project with sample code you've provided and it worked( with spring.boot.version 1.2.1.RELEASE ).
There is a similar project on github you may be interested in.

How to make JHipster 'hot reload' classes

I'm using default generated jhipster application and I'm wondering how to make it 'hot reload' using spring-boot-devtools.
That's how I tried to start this application in 2 different ways:
http://prntscr.com/a4dhmu or http://prntscr.com/a4di2c
spring-boot-devtools library is included in dev profile (just simple generated pom.xml) and my Application.class is default:
package com.testnewfeatures.app;
import com.testnewfeatures.app.config.Constants;
import com.testnewfeatures.app.config.JHipsterProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.MetricRepositoryAutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.Environment;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collection;
#ComponentScan
#EnableAutoConfiguration(exclude = { MetricFilterAutoConfiguration.class, MetricRepositoryAutoConfiguration.class, HazelcastAutoConfiguration.class })
#EnableConfigurationProperties({ JHipsterProperties.class, LiquibaseProperties.class })
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
#Inject
private Environment env;
/**
* Initializes TestNewFeatures.
* <p/>
* Spring profiles can be configured with a program arguments --spring.profiles.active=your-active-profile
* <p/>
* <p>
* You can find more information on how profiles work with JHipster on http://jhipster.github.io/profiles.html.
* </p>
*/
#PostConstruct
public void initApplication() throws IOException {
if (env.getActiveProfiles().length == 0) {
log.warn("No Spring profile configured, running with default configuration");
} else {
log.info("Running with Spring profile(s) : {}", Arrays.toString(env.getActiveProfiles()));
Collection<String> activeProfiles = Arrays.asList(env.getActiveProfiles());
if (activeProfiles.contains(Constants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(Constants.SPRING_PROFILE_PRODUCTION)) {
log.error("You have misconfigured your application! " +
"It should not run with both the 'dev' and 'prod' profiles at the same time.");
}
if (activeProfiles.contains(Constants.SPRING_PROFILE_PRODUCTION) && activeProfiles.contains(Constants.SPRING_PROFILE_FAST)) {
log.error("You have misconfigured your application! " +
"It should not run with both the 'prod' and 'fast' profiles at the same time.");
}
if (activeProfiles.contains(Constants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(Constants.SPRING_PROFILE_CLOUD)) {
log.error("You have misconfigured your application! " +
"It should not run with both the 'dev' and 'cloud' profiles at the same time.");
}
}
}
/**
* Main method, used to run the application.
*/
public static void main(String[] args) throws UnknownHostException {
SpringApplication app = new SpringApplication(Application.class);
SimpleCommandLinePropertySource source = new SimpleCommandLinePropertySource(args);
addDefaultProfile(app, source);
Environment env = app.run(args).getEnvironment();
log.info("Access URLs:\n----------------------------------------------------------\n\t" +
"Local: \t\thttp://127.0.0.1:{}\n\t" +
"External: \thttp://{}:{}\n----------------------------------------------------------",
env.getProperty("server.port"),
InetAddress.getLocalHost().getHostAddress(),
env.getProperty("server.port"));
}
/**
* If no profile has been configured, set by default the "dev" profile.
*/
private static void addDefaultProfile(SpringApplication app, SimpleCommandLinePropertySource source) {
if (!source.containsProperty("spring.profiles.active") &&
!System.getenv().containsKey("SPRING_PROFILES_ACTIVE")) {
app.setAdditionalProfiles(Constants.SPRING_PROFILE_DEVELOPMENT);
}
}
}
I'm doing something wrong becaus 'Hot reload' doesn't appear when I change any class.
Thanks!
Also according to your screenshots you use IDEA which does not auto compile classes on save by default, have you tried trigerring a build manually or the tricks below?
Intellij IDEA Java classes not auto compiling on save

Categories