I have a Singleton class in Java and I have a timer using the #Schedule annotation. I wish to change the property of the Schedule at runtime. Below is the code:
#Startup
#Singleton
public class Listener {
public void setProperty() {
Method[] methods = this.getClass().getDeclaredMethods();
Method method = methods[0];
Annotation[] annotations = method.getDeclaredAnnotations();
Annotation annotation = annotations[0];
if(annotation instanceof Schedule) {
Schedule schedule = (Schedule) annotation;
System.out.println(schedule.second());
}
}
#PostConstruct
public void runAtStartUp() {
setProperty();
}
#Schedule(second = "3")
public void run() {
// do something
}
}
I wish to change the value at runtime of Schedule second based on the information from a Property file. Is this actually possibe? The Property file contains the configuration information. I tried to do #Schedule(second = SOME_VARIABLE) where private static String SOME_VARIABLE = readFromConfigFile(); This does not work. It expects a constant meaning a final and I don't want to set final.
I also saw this post: Modifying annotation attribute value at runtime in java
It shows this is not possible to do.
Any ideas?
EDIT:
#Startup
#Singleton
public class Listener {
javax.annotation.#Resource // the issue is this
private javax.ejb.TimerService timerService;
private static String SOME_VARIABLE = null;
#PostConstruct
public void runAtStartUp() {
SOME_VARIABLE = readFromFile();
timerService.createTimer(new Date(), TimeUnit.SECONDS.toMillis(Long.parse(SOME_VARIABLE)), null);
}
#Timeout
public void check(Timer timer) {
// some code runs every SOME_VARIABLE as seconds
}
}
The issue is injecting using #Resource. How can this be fixed?
The Exception is shown below:
No EJBContainer provider available The following providers: org.glassfish.ejb.embedded.EJBContainerProviderImpl Returned null from createEJBContainer call
javax.ejb.EJBException
org.glassfish.ejb.embedded.EJBContainerProviderImpl
at javax.ejb.embeddable.EJBContainer.reportError(EJBContainer.java:186)
at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:121)
at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:78)
#BeforeClass
public void setUpClass() throws Exception {
Container container = EJBContainer.createEJBContainer();
}
This occurs during unit testing using the Embeddable EJB Container. Some of the Apache Maven code is located on this post: Java EJB JNDI Beans Lookup Failed
I think the solution you are looking for was discussed here.
TomasZ is right you should use programmatic timers with TimerService for the situations when you want dynamically change schedule in run time.
Maybe you could use the TimerService. I have written some code but on my Wildfly 8 it seems to run multiple times even if its a Singleton.
Documentation http://docs.oracle.com/javaee/6/tutorial/doc/bnboy.html
Hope this helps:
#javax.ejb.Singleton
#javax.ejb.Startup
public class VariableEjbTimer {
#javax.annotation.Resource
javax.ejb.TimerService timerService;
#javax.annotation.PostConstruct
public void runAtStartUp() {
createTimer(2000L);
}
private void createTimer(long millis) {
//timerService.createSingleActionTimer(millis, new javax.ejb.TimerConfig());
timerService.createTimer(millis, millis, null);
}
#javax.ejb.Timeout
public void run(javax.ejb.Timer timer) {
long timeout = readFromConfigFile();
System.out.println("Timeout in " + timeout);
createTimer(timeout);
}
private long readFromConfigFile() {
return new java.util.Random().nextInt(5) * 1000L;
}
}
Related
I would like to retrieve the return value of this interceptor:
https://arjan-tijms.omnifaces.org/2012/01/cdi-based-asynchronous-alternative.html
#Interceptor
#Asynchronous
#Priority(PLATFORM_BEFORE)
public class AsynchronousInterceptor implements Serializable {
private static final long serialVersionUID = 1L;
#Resource
private ManagedExecutorService managedExecutorService;
private static final ThreadLocal<Boolean> asyncInvocation = new ThreadLocal<Boolean>();
#AroundInvoke
public synchronized Object submitAsync(InvocationContext ctx) throws Exception {
if (TRUE.equals(asyncInvocation.get())) {
return ctx.proceed();
}
return new FutureDelegator(managedExecutorService.submit( ()-> {
try {
asyncInvocation.set(TRUE);
return ctx.proceed();
} finally {
asyncInvocation.remove();
}
}));
}
}
here is a CdiBean of mine profiting from AsynchronousInterceptor by letting data be loaded async..
public class SomeCDI {
#Asynchronous
public void loadDataAsync() {....}
}
this is how I use the cdi bean later in code:
#Inject
SomeCDI dataLoader;
dataLoader.loadDataAsync(); // the loading starts async but I never find out when is the Future class done???
so my question is how to retrieve return value (in my example from FutureDelegator)???
You won't. Asynchronous invocations on EJB and in the model suggested by Tijms are "fire and forget": you invoke them and let them do their job. Eventually, you can make the async method fire some event when it ends to "return" the result, observing this event to give user some response (websockets, maybe?).
Ideally, the asynchronous method should be void and do some callback lift.
Note that CDI 2.0 event model has the fireAsync method, which should be used instead of your own implementation, as it already have the proper contexts and can be enriched by transaction markers and custom options (when using NotificationOptions method signature).
I am new to Spring and have only scratched the surface of what can be done with it.
I have a situation where I need to set up a recurring task using the #Scheduled annotation. The rate is specified as a member field in an object that is passed to the class encapsulating the method representing the task.
I've used the mechanism that allows for accessing the configuration or environment, e.g. #Scheduled(fixedRateString = "${some.property:default}"); this works great.
What I don't know how to do is insert the value from an object into the #Scheduled.
For example:
class MyClass {
private MyObject myObj;
public MyClass(MyObject myObj) {
this.myObj = myObj;
}
#Scheduled(fixedRateString = "${myObj.rate:5000}")
private void someTask() {
...
}
}
The code above, of course, does not work, I'm just giving an example of what I'm trying to do.
Any suggestions would be appreciated.
Yes you can use the #Scheduled annotation to do that with a SpEL expression (available on the #Scheduled annotation since Spring 4.3.x). Here's an example:
#Slf4j
#Configuration
#EnableScheduling
public class ExampleClass {
static class ScheduleCalculator {
public String calc() {
return "5000";
}
}
#Bean("scheduleCalculator")
public ScheduleCalculator createScheduleCalculator() {
return new ScheduleCalculator();
}
#Scheduled(fixedRateString = "#{scheduleCalculator.calc()}")
public void someTask() {
log.info("Hello world");
}
}
However, just because you can do it like this doesn't mean you necessarily should.
Your code may be easier to follow to folks that have to maintain it in the future if you use the spring task scheduler plus you get control of the thread pool used for scheduling instead of relying on the shared executor that all #Scheduled tasks get lumped into.
Unfortunately the spring bean creation process will not read local variables like that.
You can use the Spring TaskScheduler class.
Essentially you just have to define a thread pool that you will use to run the scheduled tasks (as a bean) and run taskScheduler.schedule(runnable, new CronTrigger("* * * * *")). There is a detailed example here:
https://www.baeldung.com/spring-task-scheduler
You can do like follow:
#Component
#ConfigurationProperties(prefix = "my.obj")
public class MyObject {
private String cronExecExpr = "*/5 * * * * *";
// getter and setter
}
class MyClass {
private MyObject myObj;
public MyClass(MyObject myObj) {
this.myObj = myObj;
}
#Scheduled(cron = "${my.obj.cron-exec-expr:*/5 * * * * *}")
private void someTask() {
...
}
}
As you can see her : https://www.baeldung.com/spring-scheduled-tasks
You can do that like follow :
A fixedDelay task:
#Scheduled(fixedDelayString = "${fixedDelay.in.milliseconds}")
A fixedRate task:
#Scheduled(fixedRateString = "${fixedRate.in.milliseconds}")
A cron expression based task:
#Scheduled(cron = "${cron.expression}")
CONTEXT:
I process reports with #Scheduled annotation and when invoke Component from Service property not getting initialized with #Value annotation even it physically exists in .properties and printed out in #PostConstruct.
DESCRIPTION:
ReportProcessor interface and InventoryReportProcessor implementation:
#FunctionalInterface
interface ReportProcessor {
public void process(OutputStream outputStream);
}
#Component
public class InventoryReportProcessor implement ReportProcessor {
#Value("${reportGenerator.path}")
private String destinationFileToSave;
/*
#PostConstruct
public void init() {
System.out.println(destinationFileToSave);
}
*/
#Override
public Map<String, Long> process(ByteArrayOutputStream outputStream) throws IOException {
System.out.println(destinationFileToSave);
// Some data processing in here
return null;
}
}
I use it from
#Service
public class ReportService {
#Value("${mws.appVersion}")
private String appVersion;
/* Other initialization and public API methods*/
#Scheduled(cron = "*/10 * * * * *")
public void processReport() {
InventoryReportProcessor reportProcessor = new InventoryReportProcessor();
Map<String, Long> skus = reportProcessor.process(new ByteArrayOutputStream());
}
}
My confusion comes from the fact that #Value in Service works fine but in #Component it returns null unless call in #PostConstruct. Also, if call #PostConstruct the value is still remains null in the rest of the class code.
I found similar Q&A and I did research in Srping docs but so far no single idea why it works this way and what can be a solution?
You need to Autowire the component to make your spring application aware of the component.
#Service
public class ReportService {
#Value("${mws.appVersion}")
private String appVersion;
/* Other initialization and public API methods*/
#Autowired
private ReportProcessor reportProcessor;
#Scheduled(cron = "*/10 * * * * *")
public void processReport() {
//InventoryReportProcessor reportProcessor = new InventoryReportProcessor();
Map<String, Long> skus = reportProcessor.process(new ByteArrayOutputStream());
}
}
Field injection is done after objects are constructed since obviously the container cannot set a property of something which doesn't exist.
at the time System.out.println(destinationFileToSave); triggers values are not being injected;
if you want to see it working try something like this
#Autowired
InventoryReportProcessor pross;
pross.process(ByteArrayOutputStream outputStream);
#PostConstruct works as it is being called after the object creation.
Spring will only parse #Value annotations on beans it knows. The code you use creates an instance of the class outside the scope of Spring and as such Spring will do nothing with it.
One thing you can do is to create the instance explictly or use Autowire:
#Autowired
private ReportProcessor reportProcessor;
tl:dr If you have configured your application context correctly then a #Value cannot be null as that will stop the correct startup of your application.
Change your Code from
#Value("${reportGenerator.path}")
private String destinationFileToSave;
to
#Value("${reportGenerator.path}")
public void setDestinationFileToSave(String destinationFileToSave) {
SendMessageController.destinationFileToSave = destinationFileToSave;
}
Is there any way to get the number and some identification information of already created entities of particular Prototype-bean in Spring application?
Addition. In our project we have more then 400 prototype-beans and I would like to trace the state what beans were created during execution and the number of entities of each type.
I have found a way to see the actual picture about created prototype-beans.
I use free VisualVM memory profiler.
In the Sampler tab you can see all instances of created classes including singleton and prototype beans.
You'll see the names of your own packages and classes. In this case:
prototype is a package with my prototype-beans.
singleton is a package with my singleton-beans.
newclasses is a package with classes that I created by new operator.
Also after the garbage collector will clean up the memory you will see the result here.
you can do it by Publish and Listen Application Events.
create you own event.
when prototype bean was created send event from it.
create count ApplicationListener , and listen to income creation event.
here is example
Spring – Publish and Listen Application Events
Spring does not manage the complete lifecycle of a prototype bean: the container instantiates, configures, decorates and otherwise assembles a prototype object, hands it to the client and then has no further knowledge of that prototype instance.
Simple variant :
public class PrototypeCreationEvent extends ApplicationEvent {
private String beanName;
public PrototypeCreationEvent(Object source , String beanName) {
super(source);
this.beanName = beanName;
}
public String getBeanName(){
return beanName;
}
}
public class PrototypeCreationListener implements ApplicationListener<PrototypeCreationEvent> {
private ConcurrentMap<String,AtomicInteger> prototypeCreationStatistic = new ConcurrentHashMap<>();
//or from guava AtomicLongMap prototypeCreationStatistic = AtomicLongMap.create();
#Override
public void onApplicationEvent(PrototypeCreationEvent event) {
prototypeCreationStatistic.computeIfAbsent(event.getBeanName() , k->new AtomicInteger(0)).incrementAndGet();
System.out.println(event);
}
public ConcurrentMap<String,AtomicInteger> getPrototypeCreationStatistic(){
return prototypeCreationStatistic;
}
}
public abstract class PrototypeCreationPublisher implements BeanNameAware , ApplicationEventPublisherAware ,InitializingBean {
private String beanName;
private ApplicationEventPublisher applicationEventPublisher;
#Override
public void setBeanName(String name) {
this.beanName = name;
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.println();
}
#Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
#PostConstruct //or use interface InitializingBean
public void sendEventAfterCreation() throws Exception {
applicationEventPublisher.publishEvent(new PrototypeCreationEvent(this , beanName));
}
}
#Component(value = BeanDefinition.SCOPE_PROTOTYPE)
public class PrototypeA extends PrototypeCreationPublisher{
}
#Component(value = BeanDefinition.SCOPE_PROTOTYPE)
public class PrototypeB extends PrototypeCreationPublisher{
}
example :
PrototypeA prototypeA1 = context.getBean(PrototypeA.class);
PrototypeA prototypeA2 = context.getBean(PrototypeA.class);
PrototypeA prototypeA3 = context.getBean(PrototypeA.class);
PrototypeB prototypeB1 = context.getBean(PrototypeB.class);
PrototypeCreationListener statistic = context.getBean(PrototypeCreationListener.class);
statistic.getPrototypeCreationStatistic().entrySet().forEach(s->{
System.out.println(s.getKey() + " count = "+s.getValue());
});
result :
PrototypeB count = 1
PrototypeA count = 3
I'm currently trying to implement injection in a Java console application using Guice. The application imports XML files in a database. Every import operation is done in an AbstractImporter, which can either be a UserImporter, a ScheduleImporter, etc.
public class ScheduleMigrator extends AbstractMigrator {
private final UserImporter userImporter;
private final ScheduleImporterFactory scheduleImporterFactory;
#Inject
public ScheduleMigrator(UserImporter userImporter,
ScheduleImporterFactory scheduleImporterFactory) {
this.userImporter = userImporter;
this.scheduleImporterFactory = scheduleImporterFactory;
}
public void migrate() {
// Migrate users
userImporter.run();
// Migrate schedules for each type
for (ScheduleType scheduleTypes : ScheduleType.values()) {
ScheduleImporter importer =
scheduleImporterFactory.create(scheduleTypes);
importer.run();
}
}
}
public class UserImporter extends AbstractImporter {
private final UserTransformer userTransformer;
private final ConfigurationService configurationService;
#Inject
public UserImporter(UserTransformer userTransformer,
ConfigurationService configurationService) {
this.userTransformer = userTransformer;
this.configurationService = configurationService;
}
public void run() {
// do stuff here
}
}
#Singleton
public class UserTransformer {
// ...code ommited...
}
#ImporterScoped
public class ConfigurationService {
// ...code ommited...
}
I have successfully created my own scope (#ImporterScoped) for classes that should only be available and instantiated only in an Importer. The scope was created by following the steps in the wiki. My problem is, how should I enter and exit the scope in ScheduleMigrator?
As you can see in ScheduleMigrator, each Importer is injected and its run() method is invoked. There are also factories (based on Guice's #AssistedInject feature). This is where I want each scope to start and end, UserImporter and ScheduleImporterFactory should run in their own scope.
This is a rough idea of what I'm trying to achieve:
importerScope.enter();
(new UserImporter()).run();
importerScope.exit();
Guice's documentation mentions the use of interceptors, but I'm a little lost on how it can be implemented.
Using AOP seems a very over-engineered approach and might introduce problems. When do I enter the scope? When do I exit? What happens if I instantiate two Importer objects?
Instead, I added a runScoped method in AbstractMigrator that takes a Runnable and executes it. Using injection I get the ImporterScope scope, enter and exit it appropriately.
protected void runScoped(Runnable function)
{
scenarioScope.enter();
try {
function.run();
}
finally {
scenarioScope.exit();
}
}
Usage:
runScoped(() -> {
ScheduleImporter importer =
scheduleImporterFactory.create(scheduleTypes);
importer.run();
});
This introduces one problem though. In ScheduleMigrator, I can't have Importers injected, because their instantiation would occur outside of a scope and Guice throws an OutOfScopeException. I had to wrap each Importer in a Provider.
private final Provider<UserImporter> userImporterProvider;
runScoped(() -> {
UserImporter importer = userImporterProvider.get();
importer.run();
});