Hi guys, I am porting multiple existing production backend/middlware systems from Tomcat/JBoss to Karaf.
At first I had issues with JPA+Hibernate, seems to be work now. Now I have task to migrate existing Quartz 1.8.x code to 2.2.x. At first look I thought all is done in Karaf, also Quartz was a dependency - and example looked really simple. Here I do not know what is a common guideline in Karaf : Is it good to support "native" API or is more in favor to implement "common" API. My decision was, to move to support native Quartz API , as it is really "well done" and has all and more any one should need. So here I will explain why I've decided to update Scheduler service and how ( in general ) I did it. I am working on last few changes, before I push to forked github repository. Repository & branch is already online and anyone can check it out, but it is not final - I have few more errors needed to be fixed. Repository&branch location is: https://github.com/mibesis/karaf/tree/karaf-4.2.2-scheduler-quartz-api What I've changed: 1.) in existing scheduler/pom.xml I've changed so no Quartz package is private package - stored inside a Scheduler bundle, but all Quartz dependencies are pulled from existing ServiceMix Quartz bundle: mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.quartz/2.2.4-SNAPSHOT 2.) I extracted interfaces for QuartzScheduler ( Karaf's Scheduler Quartz wrapper ) so it can be exposed, also for other exposed classes. 3.) Exporting all the packages inside Scheduler bundle. This is not something I am really happy about, but when I was trying to go around this, I had more problems than benefits. 4.) Made all data passed to "datamap" as Serializable, as Quartz as RAM Storage most of the time only for fun, I guess most of the real usage is using some kind of persistence - SQL DB - as this is also my case, I had to support this. 5.) I bypass almost all existing "wrapping" code as this introduced complexity at only additional cost -- when I talk about support for "native Quartz API". So now I can write Quartz producer as : @Component public class KarafSchedulerQuartzJobProducer { private final Logger log = LoggerFactory.getLogger(getClass()); @Reference private Scheduler scheduler; @Activate public void start() { JobDataMap data = new JobDataMap(); data.put("message", "Hello Karaf user from Quartz Job."); final QuartzScheduler quartzScheduler = (QuartzScheduler)this.scheduler; JobDetail job = JobBuilder.newJob(KarafSchedulerComplexJobService.class) .withIdentity("KarafSchedulerComplexJobService", "NativeQuartz") .usingJobData(data) .build(); Date runTime = DateBuilder.evenMinuteDate(new Date()); // Trigger the job to run on the next round minute Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("KarafSchedulerComplexJobServiceTrigger", "NativeQuartz") .startAt(runTime) .withSchedule(sb.withIntervalInMilliseconds(period * 1000)) .build(); try { quartzScheduler.scheduleJob(job, trigger); } catch (Exception e) { log.warn(e.getLocalizedMessage(), e); } } } and Quartz job as any already existing Quartz job -- without any change to existing code: import org.quartz.Job; public class KarafSchedulerComplexJobService implements Job { private final Logger log = LoggerFactory.getLogger(getClass()); public KarafSchedulerComplexJobService() { super(); } @Override public void execute(final JobExecutionContext context) { final JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); message = jobDataMap.getString("message"); log.info(message); } } So to me this is great solution , as I can now quite easy migrate existing source. What I am asking now is: how good solution would this be for Karaf - as this makes Scheduler service "bound" to Quartz API, but this is only if you need it -- all existing API is still working and was not changes - API not, but in the section where data is passed to Quartz any non-serializable data was moved to temporary storage and than before calling Runnable task re-attached back again, so producer and consumer do not really know for any change. But all is not all that good, at it might seem. To me this perfect solution, but I know it can be made better - more robust/general. What are the problems: 1.) Quartz is loading classes - so it needs to know where they are. I needed quite some time, knocks at the wall and coffee cups to figure this out. ( I am not OSGi expert ). So my solution was, to agree on a common package, where all Quartz Jobs must be. To me this is issue, but issue I can handle - for now. Package I've decided for is: org.apache.karaf.scheduler.quartz.job a.) To make this work, I have to update ServiceMix Quartz bundle: mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.quartz/2.2.4-SNAPSHOT was updated to import package org.apache.karaf.scheduler.quartz.job b.) Karaf Scheduler Core imports package org.apache.karaf.scheduler.quartz.job c.) Quartz producer exports org.apache.karaf.scheduler.quartz.job - but I also scan for sub-packages, so I guess jobs should be in sub-packages, to avoid conflicts. This is one part of my changes, I would really like better one, but for what I need, this is ok -- and after all the headaches I am quite happy with this. Example code is located at: https://github.com/mibesis/karaf/tree/karaf-4.2.2-scheduler-quartz-api/examples/karaf-scheduler-example/karaf-scheduler-example-quartz but ( again ) this is not yet final commit, as I have few more errors to fix, but I think not a show stoppers ( I hope ). So my final thoughts/questions: 1.) Is such a change welcome at Karaf - is this something that would benefit Karaf? 2.) Is there any other existing solution, I should know of? 3.) How can I implement "dynamic" package - so that Quartz job can be in any package, but just pre-defined ones. Kind regards, Miroslav -- Miroslav Beranič MIBESIS +386(0)40/814-843 [email protected] http://www.mibesis.si
