HASingleton fails to lookup JNDI bean - java

I am trying to deploy a HASingleton on a JBoss6.4. I have followed this tutorial to come up with the following:
I create a Service which is supposed to start a timer (own timer interface), by injecting the timer bean through JNDI.
public class HATimerService implements Service<String> {
private Logger logger = Logger.getLogger(HATimerService.class);
private final AtomicBoolean started = new AtomicBoolean(false);
private ServiceName serviceName;
private final InjectedValue<ServerEnvironment> env = new InjectedValue();
private String JNDI = "java:global/my-ear/my-module/MyTimer"
public HATimerService() {
serviceName = ServiceName.JBOSS.append(new String[]{"my", "ha", "singleton", "MyHaService"});
}
public String getValue() throws IllegalStateException, IllegalArgumentException {
return "";
}
public void start(StartContext context) throws StartException {
if(!started.compareAndSet(false, true)) {
throw new StartException("The service is still started!");
} else {
try {
InitialContext e = new InitialContext();
TimerScheduler myTimer = (TimerScheduler)e.lookup(JNDI);
timer.startTimer();
} catch (NamingException var6) {
throw new StartException("Could not initialize timer", var6);
}
}
}
public void stop(StopContext context) {
if(started.compareAndSet(true, false)) {
try {
InitialContext e = new InitialContext();
((TimerScheduler)e.lookup(JNDI)).stopTimer();
} catch (NamingException var4) {
logger.error("Could not stop timer", var4);
}
}
}
public ServiceName getServiceName() {
return serviceName;
}
public InjectedValue<ServerEnvironment> getEnvironment() {
return env;
}
}
I also have an activator which activates the service.
public class HATimerServiceActivator implements ServiceActivator {
private final Logger log = Logger.getLogger(this.getClass());
public HATimerServiceActivator() {
}
public void activate(ServiceActivatorContext context) {
HATimerService service = new HATimerService();
this.log.info(service.getServiceName() + "HATimerService will be installed");
SingletonService singleton = new SingletonService(service, service.getServiceName());
singleton.build(new DelegatingServiceContainer(context.getServiceTarget(), context.getServiceRegistry()))
.addDependency(ServerEnvironmentService.SERVICE_NAME, ServerEnvironment.class, service.getEnvironment())
.setInitialMode(Mode.ACTIVE)
.install();
}
}
The timer bean, HATimerService, and the HATimerServiceActivator are all deployed in an ear called my-ear. In the log files I can see:
JNDI bindings for session bean named MyTimer.... :
java:global/my-ear/my-module/MyTimer
However, every once in a while (approx. 1/3 of all deploys), this setup fails due to a NameNotFoundException where the JNDI lookup fails. The full exception is: Caused by: javax.naming.NameNotFoundException: Error looking up my-ear/my-module/MyTimer, service service jboss.naming.context.java.global.my-ear.my-module.MyTimer is not started
My guess is that this can be some sort of race condition where the bean isn't registered in the JNDI-tree yet. How can I make the service wait with the lookup until the bean is available?

It seems that there exists a possibility to create dependencies on deployment units. When creating the SingletonService, the following dependency can be added:
ServiceName ejbDependency = ServiceName.of("jboss", "deployment", "subunit", "my-ear.ear", "my-module.jar", "component", "MyTimerBean", "START");
singleton.build(new DelegatingServiceContainer(context.getServiceTarget(), context.getServiceRegistry()))
.addDependency(ServerEnvironmentService.SERVICE_NAME, ServerEnvironment.class, service.getEnvironment())
.setInitialMode(Mode.ACTIVE)
.addDependency(ejbDependency)
.install();
As long as ejbDependency is a correct dependency, the lookup will be performed after bean start.

Related

How can I set `backoff-time-in-millis` parameter when creating a Camunda configuration programmatically?

I have the class below in which I want to configure my Camunda process engine.
I want to make the engine deployment-aware and set the backoff-time-in-millis.
I can do the former using config.setJobExecutorDeploymentAware(true);.
How can I set the backoff-time-in-millis and other parameters of the job executor?
The obvious solution (config.getJobExecutor().setBackoffTimeInMillis(100);) is not applicable because when the method org.example.Config#processEngineConfiguration is called, config.getJobExecutor() is equal to null.
#Configuration
#Import( SpringProcessEngineServicesConfiguration.class )
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.setJobExecutorDeploymentAware(true);
config.setIdGenerator(new StrongUuidGenerator());
config.setDataSource(dataSource);
config.setTransactionManager(txManager);
config.setDatabaseSchemaUpdate("true");
config.getProcessEnginePlugins().add(new SpinProcessEnginePlugin());
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;
}
}
Add following code to the method processEngineConfiguration() above:
final ThreadPoolJobExecutor executor = new DefaultJobExecutor();
executor.setMaxJobsPerAcquisition(3);
executor.setWaitTimeInMillis(500);
executor.setLockTimeInMillis(300000);
executor.setMaxBackoff(150);
executor.setMaxWait(50);
final SpringProcessEngineConfiguration config = new SpringProcessEngineConfiguration();
config.setJobExecutor(executor);
config.setJobExecutorDeploymentAware(true);

How to see and add to logs in libraries which are referenced in java spring boot project?

I have a spring boot application that uses the libraries: SimpleMessageListenerContainer (https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp/rabbit/listener/SimpleMessageListenerContainer.html) and SimpleMessageListenerContainerFactory (https://www.javadoc.io/static/org.springframework.cloud/spring-cloud-aws-messaging/2.2.0.RELEASE/org/springframework/cloud/aws/messaging/config/SimpleMessageListenerContainerFactory.html). The application uses ASW SQS and Kafka but I'm experiencing some out of order data and trying to investigate why. Is there a way to view logging from the libraries? I know I cannot edit them directly but when I create the bean, I want to be able to see the logs from those two libraries and if possible to add to them.
Currently I'm setting up the bean in this way:
#ConditionalOnProperty(value = "application.listener-mode", havingValue = "SQS")
#Component
public class SqsConsumer {
private final static Logger logger = LoggerFactory.getLogger(SqsConsumer.class);
#Autowired
private ConsumerMessageHandler consumerMessageHandler;
#Autowired
private KafkaProducer producer;
#PostConstruct
public void init() {
logger.info("Loading SQS Listener Bean");
}
#SqsListener("${application.aws-iot.sqs-url}")
public void receiveMessage(String message) {
byte[] decodedValue = Base64.getDecoder().decode(message);
consumerMessageHandler.handle(decodedValue, message);
}
#Bean
public SimpleMessageListenerContainerFactory simpleMessageListenerContainerFactory(AmazonSQSAsync amazonSqs) {
SimpleMessageListenerContainerFactory factory = new SimpleMessageListenerContainerFactory();
factory.setAmazonSqs(amazonSqs);
factory.setMaxNumberOfMessages(10);
factory.setWaitTimeOut(20);
logger.info("Created simpleMessageListenerContainerFactory");
logger.info(factory.toString());
return factory;
}
}
For reference, this is a method in the SimpleMessageListenerContainer. It is these logs which I would like to investigate and potentially add to:
#Override
public void run() {
while (isQueueRunning()) {
try {
ReceiveMessageResult receiveMessageResult = getAmazonSqs()
.receiveMessage(
this.queueAttributes.getReceiveMessageRequest());
CountDownLatch messageBatchLatch = new CountDownLatch(
receiveMessageResult.getMessages().size());
for (Message message : receiveMessageResult.getMessages()) {
if (isQueueRunning()) {
MessageExecutor messageExecutor = new MessageExecutor(
this.logicalQueueName, message, this.queueAttributes);
getTaskExecutor().execute(new SignalExecutingRunnable(
messageBatchLatch, messageExecutor));
}
else {
messageBatchLatch.countDown();
}
}
try {
messageBatchLatch.await();
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
catch (Exception e) {
getLogger().warn(
"An Exception occurred while polling queue '{}'. The failing operation will be "
+ "retried in {} milliseconds",
this.logicalQueueName, getBackOffTime(), e);
try {
// noinspection BusyWait
Thread.sleep(getBackOffTime());
}
catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
SimpleMessageListenerContainer.this.scheduledFutureByQueue
.remove(this.logicalQueueName);
}
How would I be able to see all of that logging from where I create the bean?
Any help would be much appreciated!

Spring + Quartz, Trigger is null

I'm dwelling with Quartz from days..
I need to create, the app starts, some triggers and job details..
So, this is my Job
#DisallowConcurrentExecution
public class TimeoutJob extends QuartzJobBean{
public final String ID = "idInterruttore";
private final Logger logger = Logger.getLogger(TimeoutJob.class);
#Autowired InterruttoreService interruttoreService;
#Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
int idInterruttore = dataMap.getIntFromString(ID);
Interruttore interruttore = interruttoreService.findById(idInterruttore);
logger.debug("Job reached for " + interruttore.getNomeInterruttore());
}
}
Then i configure some bean in QuartzConfiguration.java
#Configuration
#ComponentScan("it.besmart")
public class QuartzConfiguration {
#Autowired
ApplicationContext applicationContext;
#Bean
public SchedulerFactoryBean scheduler() {
SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
schedulerFactory.setJobFactory(springBeanJobFactory());
return schedulerFactory;
}
#Bean
public SpringBeanJobFactory springBeanJobFactory() {
AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
}
Now, I have a JobManager.class which manage jobDetails and Triggers
#Service("jobManager")
public class JobManager {
private final Logger logger = Logger.getLogger(JobManager.class);
#Autowired
SchedulerFactoryBean scheduler;
#Autowired
InterruttoreService interruttoreService;
#PostConstruct
public void createInitialJobs() {
logger.debug("Start ut jobs to create");
List<Interruttore> interruttori = interruttoreService.findAllSwitches();
Date now = new Date();
for (int i = 0; i < interruttori.size(); i++) {
Interruttore interruttore = interruttori.get(i);
if (interruttore.getTimeoutDate().after(now) && interruttore.isStato()) {
// JobDetail and Trigger creation
createJob(interruttore, interruttore.getTimeoutDate());
}
}
}
public void createJob(Interruttore interruttore, Date richiesta) {
JobDetailFactoryBean jobDetail = new JobDetailFactoryBean();
jobDetail.setJobClass(TimeoutJob.class);
jobDetail.setName("Job detail for " + interruttore.getNomeInterruttore());
jobDetail.setDescription("Job Description");
jobDetail.setDurability(true);
Map<String, Integer> map = new HashMap<String,Integer>();
map.put("idInterruttore", interruttore.getIdInterruttore());
jobDetail.setJobDataAsMap(map);
long future = richiesta.getTime() - new Date().getTime();
logger.debug("next timeout is " + future / 1000 / 60 + " minuti for " + interruttore.getNomeInterruttore());
//trigger creation
SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
trigger.setName("myTrigger"+interruttore.getNomeInterruttore());
trigger.setGroup("timeoutTriggers");
trigger.setJobDetail(jobDetail.getObject());
trigger.setStartDelay(0);
trigger.setRepeatCount(1);
trigger.setRepeatInterval(future);
trigger.afterPropertiesSet();
logger.debug("Trigger for " + interruttore.getNomeInterruttore());
logger.debug("Trigger object is :" + trigger.getObject());
logger.debug("Next Trigger date " + trigger.getObject().getFinalFireTime());
try {
scheduler.getScheduler().scheduleJob(jobDetail.getObject(), trigger.getObject());
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
When launching the app, the #PostConstruct method tries to create the triggers, but i'm getting an exception when creating jobManager
Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jobManager': Invocation of init method failed; nested exception is java.lang.NullPointerException
caused by
Caused by: java.lang.NullPointerException
at org.springframework.scheduling.quartz.SimpleTriggerFactoryBean.afterPropertiesSet(SimpleTriggerFactoryBean.java:231)
at it.besmart.quartz.JobManager.createJob(JobManager.java:85)
at it.besmart.quartz.JobManager.createInitialJobs(JobManager.java:54)
which is
trigger.afterPropertiesSet();
as my triggers are not created...
There is a bug in the spring-context-support jar 4.2.5 version.
sti.setJobKey(this.jobDetail.getKey());
i.e. jobDetail can be null.
In the new versions it is fixed. I checked 4.3.2 version.
You can use 4.3.2 or later.
In 4.3.2 version
if (this.jobDetail != null) {
sti.setJobKey(this.jobDetail.getKey());
}

Trying to Understand Java Dependency Injection with Example

I'm trying to create a database connection library to be used in all my apps. I want to make sure that this library is fully unit tested and so i'm trying to use dependency injection.
I have this class which i want to ensure is tested:
public class ConnectionFactory {
private String dataSourceName;
public ConnectionFactory(String dataSourceName) {
if(dataSourceName == null) {
throw new NullPointerException("dataSourceName can't be null");
}
this.dataSourceName = dataSourceName;
}
public Connection getConnection() throws SQLException {
Connection connection = getDataSource(dataSourceName).getConnection();
if(connection != null) {
return connection;
}
...
}
// Get a datasource object
private DataSource getDataSource(String dataSourceName) {
...
try {
Context ctx = new InitialContext();
dataSource = (DataSource) ctx.lookup("java:comp/env/" + dataSourceName);
} catch (NamingException e) {
...
}
return dataSource;
}
}
I want to be able to simply call this class from all my apps with something as simple as this:
public class MyApp {
public static void main(string[] args) {
ConnectionFactory connectionFactory = new ConnectionFactory("jdbc/myDataSource");
Connection connection = connectionFactory.getConnection();
}
}
I've started writing unit tests for this ConnectionFactory, but quickly realized that with my current code I can't mock the DataSource object so it's trying to actually connect to a real data source.
#RunWith(Nested.class)
public class ConnectionFactoryTest {
public class Constructor {
#Test
public void shouldThrowNullPointerIfParamIsNull() {
assertThatExceptionOfType(NullPointerException.class)
.isThrownBy(() -> { new ConnectionFactory(null); })
.withMessage("dataSourceName can't be null");
}
}
public class GetConnection {
public class WithDataSourceAvailable {
#Test
public void shouldErrorIfParamIsNull() {
ConnectionFactory connectionFactory = new ConnectionFactory("jdbc/myDataSource"); // <-- This is going to fail b/c it's trying to actually fetch a real data source
}
}
}
}
How can I properly use Dependency Injection so that I can write unit tests that don't actually try to connect to a data source?
Take a look at Mockito I find it easy to use for this type of mocking.

Asynchronous threads not running in parallel under Spring Framework

I like to run two tasks undependent from each other. The problem is, that one of the task has a blocking part. As a result the second task is waiting for the first task. Because of that, I think both tasks are running on the same thread. But I like to run each task on a different thread with the aim, that each task don't have to wait for each other.
I have a configuration class AppConfig:
#Configuration
#EnableAsync
#EnableScheduling
public class AppConfig
{...
There I have defined two beans:
#Bean(initMethod = "watchFtp")
public FTPWatchScheduledTask ftpWatchScheduledTaskService()
{
FTPWatchScheduledTask ftpWatchScheduledTask = new FTPWatchScheduledTaskService();
return ftpWatchScheduledTask;
}
and
#Bean(initMethod = "watch")
public FileWatch fileWatchService()
{
...
return fileWatchService;
}
Further the AppConfig is registered by the context:
public class FileSyncApplicationInitializer
implements WebApplicationInitializer
{
private static final Log log = LogFactory.getLog(FileSyncApplicationInitializer.class);
private static AnnotationConfigWebApplicationContext context;
#Override
public void onStartup(ServletContext container)
{
// Create the Spring application context
log.debug("Initializing file synchronisation ...");
context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
log.debug("Contexts initialized ...");
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
Both defined init-Methods of each bean are annotated with "#Async":
#Async
public void watch() throws IOException
{
WatchService watcher = FileSystems.getDefault().newWatchService();
WatchKey key = temporaryDir.register(watcher,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);
for (; ; )
{
try
{
key = watcher.take(); // take is waiting
}
catch (InterruptedException e)
{
e.printStackTrace();
}
for (WatchEvent<?> pollEvent : key.pollEvents())
{
WatchEvent.Kind<?> kind = pollEvent.kind();
if (kind == StandardWatchEventKinds.ENTRY_CREATE)
{
WatchEvent<Path> event = (WatchEvent<Path>)pollEvent;
Path fileName = (Path)key.watchable();
Path fullPath = fileName.resolve(event.context());
orderImportService.persistOrderXml(fileName);
log.info("something was persisted");
}
}
boolean valid = key.reset();
if (!valid)
{
break;
}
}
}
Second init-method:
#Async
#Scheduled(fixedRate = 5000)
public void watchFtp()
{
log.info(String.format("test time: " + dateFormat.format(new Date())));
}

Categories

Resources