org.opencastproject.kernel.scanner.AbstractScanner Maven / Gradle / Ivy
/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community 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://opensource.org/licenses/ecl2.txt
*
* 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.opencastproject.kernel.scanner;
import static org.opencastproject.security.util.SecurityUtil.createSystemUser;
import org.opencastproject.security.api.Organization;
import org.opencastproject.security.api.OrganizationDirectoryService;
import org.opencastproject.security.api.SecurityService;
import org.opencastproject.security.util.SecurityContext;
import org.opencastproject.security.util.SecurityUtil;
import org.opencastproject.serviceregistry.api.ServiceRegistry;
import org.opencastproject.util.NeedleEye;
import org.opencastproject.util.data.Function0;
import org.opencastproject.util.data.Option;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.osgi.service.component.ComponentContext;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
/**
* This class is designed to provide a template for sub classes that will scan
* their data and respond accordingly.
*/
public abstract class AbstractScanner {
/** The logging facility */
private static final Logger logger = LoggerFactory.getLogger(AbstractScanner.class);
public static final String JOB_PARAM_PARENT = "parent";
/** The key whose value will be used to determine if a scanner is enabled or disabled.*/
public static final String PARAM_KEY_ENABLED = "enabled";
/** The key whose value will be a cron expression to determine how often the Scanner scans.*/
public static final String PARAM_KEY_CRON_EXPR = "cron-expression";
/** The quartz scheduler */
protected Scheduler quartz;
/** Is the scanner enabled? */
private boolean enabled = false;
/** Cron schedule expression */
private String cronExpression = "0 0 2 * * ?"; // every day at 2:00 am
/** Reference to the service registry */
private ServiceRegistry serviceRegistry;
/** Reference to the security service */
private SecurityService securityService;
/** Reference to the organization directory service */
private OrganizationDirectoryService directoryService;
private String systemUserName;
/** The name of the job group to schedule this quartz job under. */
public abstract String getJobGroup();
/** The name of the job */
public abstract String getJobName();
/** The name of the group to store the quartz triggers under. */
public abstract String getTriggerGroupName();
/** The name of the triggers to use for the quartz jobs. */
public abstract String getTriggerName();
/** The name of the scanner to use in log files. */
public abstract String getScannerName();
public abstract void scan();
/** Returns a cron style statement that defines how often this scanner will run. */
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
/**
* @return Returns the current quartz scheduler used to schedule scanning jobs.
*/
protected Scheduler getQuartz() {
return quartz;
}
protected void setQuartz(Scheduler quartz) {
this.quartz = quartz;
}
/** True if this scanner should be enabled. */
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* Schedule the scanning job to execute according to the cron schedule.
*/
public void schedule() {
if (!isEnabled()) {
logger.info(getScannerName() + " is disabled");
return;
}
if (quartz == null) {
logger.warn("No quartz scheduler available to schedule scanner.");
return;
}
logger.info("Schedule " + getScannerName() + " as a cron job ({})", getCronExpression());
try {
final CronTrigger trigger = new CronTrigger();
trigger.setCronExpression(getCronExpression());
trigger.setName(getTriggerName());
trigger.setGroup(getTriggerGroupName());
trigger.setJobName(getJobName());
trigger.setJobGroup(getJobGroup());
if (getQuartz().getTriggersOfJob(getJobName(), getJobGroup()).length == 0) {
getQuartz().scheduleJob(trigger);
} else {
getQuartz().rescheduleJob(getTriggerName(), getTriggerGroupName(), trigger);
}
} catch (ParseException e) {
logger.error("Error scheduling " + getScannerName() + ", the cron expression '{}' could not be parsed: {}",
getCronExpression(), e.getMessage());
} catch (Exception e) {
logger.error("Error scheduling " + getScannerName(), e);
}
}
/**
* Unschedule the scanning job.
*/
public void unschedule() {
try {
if (quartz != null) {
quartz.unscheduleJob(getTriggerName(), getTriggerGroupName());
}
} catch (SchedulerException e) {
logger.error("Error unscheduling " + getScannerName(), e);
}
}
/** OSGi callback to set organization directory service */
protected void bindOrganizationDirectoryService(OrganizationDirectoryService directoryService) {
this.directoryService = directoryService;
}
/** OSGi callback to set security service */
protected void bindSecurityService(SecurityService securityService) {
this.securityService = securityService;
}
protected void bindServiceRegistry(ServiceRegistry serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
/** Get an organization directory service */
public OrganizationDirectoryService getOrganizationDirectoryService() {
return directoryService;
}
/**
* Get a system administrator context for the given organization id.
* @param orgId The organization's id.
* @return A SecurityContext for the admin.
*/
public SecurityContext getAdminContextFor(String orgId) {
try {
final Organization org = directoryService.getOrganization(orgId);
return new SecurityContext(securityService, org, createSystemUser(systemUserName, org));
} catch (Exception e) {
throw new Error(e);
}
}
/** Get a service registry */
public ServiceRegistry getServiceRegistry() {
return this.serviceRegistry;
}
/** The user name to run this scanner job under. */
public String getSystemUserName() {
return systemUserName;
}
/** OSGi component activate callback */
protected void activate(ComponentContext cc) {
systemUserName = cc.getBundleContext().getProperty(SecurityUtil.PROPERTY_KEY_SYS_USER);
}
/** OSGi deactivate component callback. */
public void deactivate() {
shutdown();
}
/** Shutdown the scheduler. */
public void shutdown() {
try {
if (quartz != null) {
quartz.shutdown();
}
} catch (org.quartz.SchedulerException e) {
logger.debug("Exception while shutting down quartz scheduler this will be ignored: {}",
ExceptionUtils.getStackTrace(e));
}
}
/** Trigger the scheduler once independent of it's actual schedule. */
public void trigger() {
try {
quartz.triggerJobWithVolatileTrigger(getJobName(), getJobGroup());
} catch (Exception e) {
logger.error("Error triggering Quartz job", e);
}
}
/** Just to make sure Quartz is being shut down... */
@Override
protected void finalize() throws Throwable {
super.finalize();
shutdown();
}
/**
* Please remember that derived classes need a no-arg constructor in order to work with Quartz. Sample usage:
*
*
* public class Runner extends TypedQuartzJob<Scheduler> {
* protected abstract void execute(Scheduler parameters, JobExecutionContext ctx) {
* // type safe parameter access
* parameters.getConfig();
* }
* }
*
* public class Scheduler {
* ...
* // create the job
* final JobDetail job = new JobDetail(JOB_NAME, JOB_GROUP, Runner.class);
* // set the scheduler as parameter source
* job.getJobDataMap().put(JOB_PARAM_PARENT, this);
* // add to Quartz scheduler
* quartz.addJob(job, true);
* ...
* // provide a config string
* public String getConfig() {...}
* }
*
*/
public abstract static class TypedQuartzJob implements Job {
private final Option allowParallel;
/**
* @param allowParallel
* Pass a needle eye if only one job may be run at a time. Make the needle eye static to the inheriting
* class.
*/
protected TypedQuartzJob(Option allowParallel) {
this.allowParallel = allowParallel;
}
@Override
public final void execute(final JobExecutionContext ctx) throws JobExecutionException {
for (NeedleEye eye : allowParallel) {
eye.apply(executeF(ctx));
return;
}
executeF(ctx).apply();
}
/** Typesafe replacement for {@link #execute(org.quartz.JobExecutionContext)}. */
protected abstract void execute(A parameters, JobExecutionContext ctx);
private Function0 executeF(final JobExecutionContext ctx) {
return new Function0.X() {
@Override
public Integer xapply() throws Exception {
try {
execute((A) ctx.getJobDetail().getJobDataMap().get(JOB_PARAM_PARENT), ctx);
return 0;
} catch (Exception e) {
logger.error("An error occurred while harvesting schedule", e);
throw new JobExecutionException("An error occurred while harvesting schedule", e);
}
}
};
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy