I am developing one task scheduler which triggers the tasks in parallel using executor service. I want to make my task scheduler as generic and no code change/less code change in scheduler code base whenever any new type of task is added.
My tasks (mostly client package) can be of any type which basically just accepts particular request and execute the tasks.
To do this I am exposing interface (say ITask) which must be implemented by tasks (which will be on some other app/package) and that will be having one implementation method say example
doTask(IRequest request);
So the use case is if any clients who wants to trigger their job using my scheduler framework/API, just need to add my package in their dependency and rest (those are, getting the list of task classes which implements ITask > schedule it using executor service > retry failed tasks > finally provide the entire tasks status) should be taken care by my schedular API.
What is the optimal way to do this. I am thinking of solution how Junit gets its #Test methods (based on annotation) of client whoever adds Junit dependency in his package, similarly I want get classes based on interface.
You have tagged this question with Spring, but you don't mention anywhere in the question that you are using the Spring framework. This answer makes a few assumptions:
You are using Spring Framework
The implementations of your desired interface have been configured as Spring Beans
If you get access to the ApplicationContext (see the interface ApplicationContextAware), you can use it to look up Spring beans of a certain type. It would look something like this:
Map<String, ITask> beans = appContext.getBeansOfType(ITask.class);
This method returns a map with the key being the bean identifier and the value being the instance of the bean itself. From there, you could loop through the values and add them to your job scheduler.
Alternatively
If you do not want the requirement of having to configure each ITask implementation as a Spring bean, you could use Spring's ClassPathScanningCandidateComponentProvider (a mouthful, I know).
This is a nifty tool that allows you to scan base packages to find bean "candidates". However, in your case, you could use it to find ITask candidates. Clients to your library could configure the base scan packages which you would use to scan:
private String configuredListOfBasePackages;
public void someMethod () {
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AssignableTypeFilter(ITask.class));
Set<BeanDefinition> iTaskCandidates = scanner.findCandidateComponents(configuredListOfBasePackages);
// do stuff with the bean definitions
}
This method is obviously a bit more dangerous as it require you to be able to construct a new instance of every candidate you find. As such, this is not the ideal solution.
Related
I am integrating Spring Batch into an existing Spring webapp and have created three simple jobs as a learning process. Then I created a set of ancestor classes for jobs/readers/writers that can be used to migrate our old batch jobs easily.
We intend to run the jobs asynchronously from within Tomcat as separate threads. I have created a UI to manage and start/stop them.
I have a class annotated with #Configuration and #EnableBatchProcessing which does the job of setting up all the global classes for batch mode; it also then scans the base package for all our jobs for specific ancestor class. Then it suffixes each class name for the corresponding *Factory class, does a getBean for that class and uses it to register each job:
Job job = jobFactory.createInstanceForRegistration();
jobRegistry.register(new ReferenceJobFactory(job));
The createInstanceForRegistration method uses applicationContext.getBean to get the instances of the job/read/writer classes to put the job and steps together and then finally:
((SimpleJob)job).setSteps(steps);
return job;
In the UI, the jobs are listed and I should be able to start them. But when I do:
batchAuditId = jobOperator.start(jobName, parameters);
Suddenly, a NPE is thrown from w/i AbstractJob/execute # line 298:
jobParametersValidator.validate(execution.getJobParameters());
because jobParametersValidator is null - despite the fact that it is initialized with a default in the class itself:
private JobParametersValidator jobParametersValidator =
new DefaultJobParametersValidator();
More to the point, the job class constructor has code that sets several items, including the override of the validator:
super(BATCH_NAME, BATCH_TYPE_CODE, BATCH_FUNCTION, BATCH_PROCESS_AREA);
setLogger(LoggerFactory.getLogger(CustomJob.class));
getLogger().debug("constructed: {}", this.toString());
setParametersRequired(Boolean.TRUE); // this job requires parameters
setRestartable(Boolean.TRUE);
setJobParametersValidator(new CustomJobParametersValidatorImpl());
During deployment, when Spring creates all the classes, I can step through the code and the override validator is created and set for that job.
Yet when jobOperator.start executes, the NPE is thrown.
I can find no reason for this. It is almost like jobOperator.start somehow creates a new instance of the job class in a way that doesn't use the existing instance or my custom constructor.
Can anyone explain what is going on?
I am integrating Hystrix into SilverWare microservices platform and I want to use hystrix-javanica annotations. These annotations are meant to be applied on the actual implementation of the methods that need to be executed using Hystrix. The problem is that I need to implement a generic solution where you only have a service interface. It has to be done this way in order to let developers use annotated references to other microservices (when they implement their own service) without any need to deal with the implementation of those services.
I came up with a solution where you annotate your microservice reference with something like this:
#Inject
#MicroserviceReference
#HystrixConfiguration(MyServiceHystrix.class)
private MyService myService;
And then you implement (or extend) the service interface and put Hystrix annotations on its methods:
public interface HystrixedMyService extends MyService {
#HystrixCommand
doSomething();
}
When there is #HystrixConfiguration annotation on a field in your microservice referencing another service, SilverWare will scan the class given as a parameter of this annotation and prepare a Hystrix command for every method of the service. The command will also receive a callable with an actual method invocation which will be executed in its run() method.
My question is: Is it possible to reuse some (internal) parts of hystrix-javanica so I do not need to scan all the annotations and create those Hystrix commands myself? I can see that most of the classes are designed to be used only with AOP.
I have a spring application that uses rabbitmq-based RPCs. on the client side, I would like to generate a proxy object that delegates to the RPC based on annotated interfaces available on the classpath of the client. in a similar way, I want to be able to register exchanges, queues and consumers on the server side, based on annotated concrete classes.
the annotations i have are #RpcInterface and #RpcEndpoint, and I created a java proxy from the interfaces implemented by the RpcEndpoint.
My problem now is that I want to be able to scan the classpath for classes with these annotations and add beans for client- and server side to the application context based on that. The problem is that FactoryBean only allows instantiation of a single object, and BeanDefinitionRegistryPostProcessor requires me to add bean definitions, which isn't really possible, because on the client side, I might only have interface that cannot be instantiated.
Right now, I'm adding #Configuration classes with one #Beans method for each interface next to where the interfaces are defined, so if I add a dependency on the interface, i would also pull in the #Configuration. This feels like unnecessary code, if I could just have something that returns a bunch of instantiated beans rather than one single bean.
so, instead of:
#Bean
public Object createBlahBean() {
createProxyFor(MyInterface.class);
}
I would like to be able to do:
#Beans
public List<Object> createBlahBeans() {
List<Object> out = new ArrayList<>();
for(Class c : findAnnotatedInterfacesFromClasspath()) {
out.add(createProxyFor(c));
}
return out;
}
or similar. any pointers?
I'm currently converting a piece of code from plain Java code to OSGi Declarative Services.
Original plain Java code
new AggregateServiceImpl(
new ChildServiceImpl1(),
new ChildServiceImpl2(),
new ChildServiceImpl3()
);
The classes are declared as so:
class AggregateServiceImpl implements Service
class ChildServiceImpl1 implements Service
class ChildServiceImpl2 implements Service
class ChildServiceImpl3 implements Service
So all classes implement Service, but the Aggregate implementation is capable of deferring to child Services when called upon.
AggregateServiceImpl itself does not know of the other implementations' existence. Its constructor is originally declared as:
public class AggregateServiceImpl(Service... children)
Clarification: the interface name 'Service' is intended generically and is not meant to represent an OSGi DS or Service concept.
Converting to OSGi
First I move each implementation into its own bundle. Then I declare my components (service implementations). I happen to be using bnd, so I use service annotations. For example:
#Component
class ChildServiceImpl1 implements Service
In the client class, we can look up the Service using the low level OSGi API or use DS in that bundle to create the object for us.
Problem
What's the best way of looking up a 'Service'? I want the AggregateServiceImpl but I might receive one of the ChildServiceImpls.
Is it best to use a separate service type or add a property to one of the components (e.g. "isRootService") to use as a filter when looking up ServiceReferences?
The best way is to use service registration properties
#Component
#Service
#Property(name = "service.id", value = "<some service unique ID")
class ChildServiceImpl1 implements Service{...}
When you look for some specific services you can use service filter:
bc.getServiceReferences(Service.class.getName(), "(service.id=<some value>)");
or if you like to use it in DS component as service reference:
#Reference(target = "(service.id=<some value>)", cardinality = ...)
private Service service;
If the AggregateServiceImpl is the only Service being used by other bundles, then it should be the only one you register.
From the code you have currently shown, we cannot tell if the AggregateServiceImpl class has dependencies on Service or the actual implementations.
If it has dependencies directly on other implementations, not the Service interface (as you have currently described it) the aggregate bundle should create the other implementation classes it requires directly and then register the AggregateServiceImpl as a Service.
If the other implementations need to be used elsewhere as well, then you should use properties (as you suggested) so consumers can distinguish between them. In this case, you still cannot use DS to construct your aggregate, since it doesn't have a dependencies on Service
I'm looking for a lib that allow me to do
define a worker that will be invoked once on a specific time in the future (not need the re-schedule / cron like featrure) i.e. a Timer
The worker should accept a context which withe some parameters / inputs
all should be persistent in the DB (or file) the worker
worker should be managed by spring -- spring should instantiate the worker so it can be injected with dependencies
be able to create timers dynamically via API and not just statically via spring XML beans
nice to have:
support a cluster i.e. have several nodes that can host a worker. each store jobn in the DB will cause invokaction of ONE work on one of the nods
I've examined several alternatives none meets the requirements:
Quartz
when using org.springframework.scheduling.quartz.JobDetailBean makes quartz create your worker instance (and not by spring) so you can't get dependecy ijection, (which will lead me to use Service Locator which I want to avoid)
while using org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean you can't get a context. your Worker expose one public method that accepts no arguments.In addition when using MethodInvokingJobDetailFactoryBean you can't use persistence (form the Javadoc)
Note: JobDetails created via this FactoryBean are not serializable and thus not suitable for persistent job stores. You need to implement your own Quartz Job as a thin wrapper for each case where you want a persistent job to delegate to a specific service method.
Spring's Timer and simple JDK Timers does not support the persistence / cluster feature
I know I can impl thing myself using a DB and Spring (or even JDK) Timers but I prefer to use an a 3r party lib for that.
Any suggestions?
If you want to create the job details to generate triggers/job-details at runtime and still be able to use Spring DI on your beans you can refer to this blog post, it shows how to use SpringBeanJobFactory in conjunction with ObjectFactoryCreatingFactoryBean to create Quartz triggering objects at runtime with Spring injected beans.
For those interested in an alternative to Quartz, have a look at db-scheduler (https://github.com/kagkarlsson/db-scheduler). A persistent task/execution-schedule is kept in a single database table. It is guaranteed to be executed only once by a scheduler in the cluster.
Yes, see code example below.
Currently limited to a single string identifier for no format restriction. The scheduler will likely be extended in the future with better support for job-details/parameters.
The execution-time and context is persistent in the database. Binding a task-name to a worker is done when the Scheduler starts. The worker may be instantiated by Spring as long as it implements the ExecutionHandler interface.
See 3).
Yes, see code example below.
Code example:
private static void springWorkerExample(DataSource dataSource, MySpringWorker mySpringWorker) {
// instantiate and start the scheduler somewhere in your application
final Scheduler scheduler = Scheduler
.create(dataSource)
.threads(2)
.build();
scheduler.start();
// define a task and a handler that named task, MySpringWorker implements the ExecutionHandler interface
final OneTimeTask oneTimeTask = ComposableTask.onetimeTask("my-onetime-task", mySpringWorker);
// schedule a future execution for the task with a custom id (currently the only form for context supported)
scheduler.scheduleForExecution(LocalDateTime.now().plusDays(1), oneTimeTask.instance("1001"));
}
public static class MySpringWorker implements ExecutionHandler {
public MySpringWorker() {
// could be instantiated by Spring
}
#Override
public void execute(TaskInstance taskInstance, ExecutionContext executionContext) {
// called when the execution-time is reached
System.out.println("Executed task with id="+taskInstance.getId());
}
}
Your requirements 3 and 4 do not really make sense to me: how can you have the whole package (worker + work) serialized and have it wake up magically and do its work? Shouldn't something in your running system do this at the proper time? Shouldn't this be the worker in the first place?
My approach would be this: create a Timer that Spring can instantiate and inject dependencies to. This Timer would then load its work / tasks from persistent storage, schedule them for execution and execute them. Your class can be a wrapper around java.util.Timer and not deal with the scheduling stuff at all. You must implement the clustering-related logic yourself, so that only one Timer / Worker gets to execute the work / task.