/* * Copyright 2009 NCHOVY * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.krakenapps.cron.impl; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.krakenapps.cron.CronService; import org.krakenapps.cron.DailyJob; import org.krakenapps.cron.DuplicatedScheduleException; import org.krakenapps.cron.HourlyJob; import org.krakenapps.cron.MinutelyJob; import org.krakenapps.cron.MonthlyJob; import org.krakenapps.cron.PeriodicJob; import org.krakenapps.cron.Schedule; import org.krakenapps.cron.WeeklyJob; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Inspects new or removed Runnable services and manages schedules * automatically. * * @author xeraph * */ public class JobServiceTracker extends ServiceTracker { private final Logger logger = LoggerFactory.getLogger(JobServiceTracker.class.getName()); private CronService cronService; private ConcurrentMap<String, List<Integer>> scheduleMap; public JobServiceTracker(BundleContext bundleContext, CronService cronService) { super(bundleContext, Runnable.class.getName(), null); this.cronService = cronService; this.scheduleMap = new ConcurrentHashMap<String, List<Integer>>(); } /** * inspects cron annotations of runnable instance and registers schedule * automatically. */ @Override public Object addingService(ServiceReference reference) { Object service = super.addingService(reference); String instanceName = (String) reference.getProperty("instance.name"); List<Integer> schedules = new ArrayList<Integer>(); Annotation[] annotations = service.getClass().getAnnotations(); for (Annotation annotation : annotations) { Class<?> clazz = annotation.annotationType(); if (clazz.equals(MinutelyJob.class)) addSchedule(schedules, new Schedule.Builder(instanceName).build()); if (clazz.equals(HourlyJob.class)) addSchedule(schedules, new Schedule.Builder(instanceName).buildHourly()); if (clazz.equals(DailyJob.class)) addSchedule(schedules, new Schedule.Builder(instanceName).buildDaily()); if (clazz.equals(WeeklyJob.class)) addSchedule(schedules, new Schedule.Builder(instanceName).buildWeekly()); if (clazz.equals(MonthlyJob.class)) addSchedule(schedules, new Schedule.Builder(instanceName).buildMonthly()); if (clazz.equals(PeriodicJob.class)) { try { PeriodicJob periodicJob = (PeriodicJob) annotation; Schedule schedule = new Schedule.Builder(instanceName).build(periodicJob.value()); addSchedule(schedules, schedule); } catch (Exception e) { logger.error("cron: periodic schedule syntax error", e); } } if (schedules.size() != 0) scheduleMap.put(instanceName, schedules); } return service; } private void addSchedule(List<Integer> schedules, Schedule schedule) { try { int id = cronService.registerSchedule(schedule); schedules.add(id); logger.trace("cron: adding schedule {}", id); } catch (DuplicatedScheduleException e) { // annotated class will cause duplicated schedule exception. since // schedule persist in db and loaded when bundle is restarted, // dynamically loaded OSGi service annotation will conflict with // pre-loaded oneself. you may ignore this here. } catch (Exception e) { logger.error("cron: add schedule error", e); } } /** * removes schedules that registered automatically when service is removed. */ @Override public void removedService(ServiceReference reference, Object service) { String instanceName = (String) reference.getProperty("instance.name"); if (instanceName != null) { List<Integer> schedules = scheduleMap.get(instanceName); if (schedules != null) { for (Integer id : schedules) { logger.trace("cron: removing schedule {}", id); cronService.unregisterSchedule(id); } } } super.removedService(reference, service); } }