package de.uhh.l2g.plugins.util;
/***************************************************************************
* The Lecture2Go software is based on the liferay portal 6.1.1
* <http://www.liferay.com>
*
* Lecture2Go <http://lecture2go.uni-hamburg.de> is an open source
* platform for media management and distribution. Our goal is to
* support the free access to knowledge because this is a component
* of each democratic society. The open source software is aimed at
* academic institutions and has to strengthen the blended learning.
*
* All Lecture2Go plugins are continuously being developed and improved.
* For more details please visit <http://lecture2go-open-source.rrz.uni-hamburg.de>
*
* @Autor Lecture2Go Team
* @Version 1.0
* @Contact lecture2go-open-source@uni-hamburg.de
*
* Copyright (c) 2013 University of Hamburg / Computer and Data Center (RRZ)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
***************************************************************************/
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.messaging.DestinationNames;
import com.liferay.portal.kernel.messaging.Message;
import com.liferay.portal.kernel.messaging.MessageListener;
import com.liferay.portal.kernel.messaging.MessageListenerException;
import com.liferay.portal.kernel.portlet.PortletBag;
import com.liferay.portal.kernel.portlet.PortletBagPool;
import com.liferay.portal.kernel.scheduler.CronTrigger;
import com.liferay.portal.kernel.scheduler.SchedulerEngine;
import com.liferay.portal.kernel.scheduler.SchedulerEngineHelperUtil;
import com.liferay.portal.kernel.scheduler.SchedulerEntry;
import com.liferay.portal.kernel.scheduler.SchedulerEntryImpl;
import com.liferay.portal.kernel.scheduler.SchedulerException;
import com.liferay.portal.kernel.scheduler.StorageType;
import com.liferay.portal.kernel.scheduler.Trigger;
import com.liferay.portal.kernel.scheduler.TriggerState;
import com.liferay.portal.kernel.scheduler.TriggerType;
import com.liferay.portal.kernel.scheduler.messaging.ReceiverKey;
import com.liferay.portal.kernel.scheduler.messaging.SchedulerResponse;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.model.Portlet;
import com.liferay.portal.service.PortletLocalServiceUtil;
import com.liferay.portal.service.ServiceContext;
import de.uhh.l2g.plugins.service.ScheduledThreadLocalServiceUtil;
/** There is no built-in time based scheduler in Java, though Quartz Extension is build-in for liferay 6.2
* (https://quartz-scheduler.org/)
*
* It setting work pretty much like cron and are configured in liferay-portlet.xml
* http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger
*
* Unfortunately Liferay Scheduler Configuration comes without start/stop/pause/resume functionality
* This Class uses the Liferay Quartz Scheduler as specified within <scheduler-entry>
* and adds start/stop functionality to it until server restart
*/
/**
* The Class PortletScheduler.
*/
@SuppressWarnings("serial")
public class PortletScheduler extends SchedulerResponse implements MessageListener {
// Liferay Log
protected static Log LOG;
protected String destination;
protected String receiverKey;
protected int exceptionsMaxSize;
// Assumed as Constants (requires further implementation for dynamics)
protected final String DEST = DestinationNames.SCHEDULER_DISPATCH;
protected final StorageType STOR = StorageType.MEMORY_CLUSTERED;
protected String initialCron;
// This has to be kept unique
protected SchedulerEntry schedulerEntry;
// The timing
protected Trigger generalTrigger;
protected TriggerState triggerState;
// These have to be set if invoked by general constructor
protected String schedulerClassName;
protected String portletId;
public String getSchedulerClassName() {
return schedulerClassName;
}
public void setSchedulerClassName(String schedulerClassName) {
this.schedulerClassName = schedulerClassName;
}
public String getPortletId() {
return portletId;
}
public void setPortletId(String portletId) {
this.portletId = portletId;
}
/**
* Create empty scheduler for ClassLoader
*
*/
public PortletScheduler() {
this.schedulerClassName = PortletScheduler.class.getName();
PortletScheduler.LOG = LogFactoryUtil.getLog(PortletScheduler.class.getName());
}
/**
* Init Scheduler Entry and Message by gathering information from PortletId
* and SchedulerEngine
*
*
* @param schedulerClassName
* @param portletId
*/
public PortletScheduler(String schedulerClassName, ServiceContext serviceContext) {
this.schedulerClassName = schedulerClassName;
LOG = LogFactoryUtil.getLog(schedulerClassName);
initScheduler(schedulerClassName, serviceContext);
}
/**
* Reads Scheduler entries from Portlet Preferences
*
* WARN: This will disable Multiple Quartz Jobs (Triggers) per Listener Feature
*
* @param schedulerClassName
* @param portletId
*/
public void initScheduler(String schedulerClassName, ServiceContext serviceContext) {
Portlet portlet = PortletLocalServiceUtil.getPortletById(serviceContext.getPortletId());
List<SchedulerEntry> jobs = new LinkedList<SchedulerEntry>();
List<SchedulerEntry> duplicates = new LinkedList<SchedulerEntry>();
LOG.info("Initializing schedulers for " + schedulerClassName + " " + portletId);
this.schedulerClassName = schedulerClassName;
this.portletId = serviceContext.getPortletId();
// Load Quartz Job (Unique for ClassName!)
assembleMessageFromResponses();
// Fetch List of Schedulers started on portlet initialization (maybe we
// do have a Trigger,...)
jobs = portlet.getSchedulerEntries();
for (SchedulerEntry job : jobs) {
// Grab first scheduler associated with given Class
if (job.getEventListenerClass().equalsIgnoreCase(this.schedulerClassName)) {
if (this.schedulerEntry == null) {
LOG.info(job.toString());
this.schedulerEntry = job;
// Get Trigger
try {
this.generalTrigger = job.getTrigger();
if (this.generalTrigger != null) {
// Try persisting our Trigger in DB
String currentCron = GetterUtil.getString(this.generalTrigger.getTriggerContent().toString());
this.triggerState = SchedulerEngineHelperUtil.getJobState(job.getEventListenerClass(), job.getEventListenerClass(), this.getStorageType());
String persistCron = ScheduledThreadLocalServiceUtil.getCronBySchedulerName(job.getEventListenerClass());
if (persistCron == null || persistCron.isEmpty())
ScheduledThreadLocalServiceUtil.addScheduledThread(schedulerClassName, currentCron, serviceContext);
// Overwrite if we encounter new value (assume
// PortletScheduler Names are unique)
if (!persistCron.equals(currentCron) && !currentCron.isEmpty()) ScheduledThreadLocalServiceUtil.updateScheduledThread(schedulerClassName, currentCron, serviceContext);
}
} catch (SchedulerException t) {
LOG.warn(t);
} catch (SystemException e) {
LOG.warn("Failed Loading Persitence - Recovery of Triggers will fail", e);
} catch (PortalException e) {
LOG.warn("", e);
}
} else { // Collect duplicate SchedulerEntries
LOG.warn("Multiple runnging Jobs found for same Scheduled Task! Removing ... " + job);
duplicates.add(job);
}
}
}
// remove duplicates
jobs.removeAll(duplicates);
// Check if we got what we've been looking for
if (schedulerEntry == null) {
LOG.warn("No SchedulerEntry found for this Job. Generating new Entry...");
assembleEntryFromSettings(portletId, this.triggerState);
}
}
/**
* Assembles (adds and schedules) an missing SchedulerEntry
*
* @return SchedulerEntry
*/
public SchedulerEntry assembleEntryFromSettings(String portletId, TriggerState state) {
Portlet portlet = PortletLocalServiceUtil.getPortletById(portletId);
SchedulerEntry entry = new SchedulerEntryImpl();
String cron = "";
try {
cron = GetterUtil.getString(ScheduledThreadLocalServiceUtil.getCronBySchedulerName(this.schedulerClassName));
// TODO: Persist Description String description;
this.generalTrigger = new CronTrigger(this.schedulerClassName, this.schedulerClassName, cron);
LOG.info("Building Trigger: " + cron);
entry.setDescription(this.schedulerClassName);
entry.setEventListenerClass(this.schedulerClassName);
entry.setTriggerType(TriggerType.CRON);
entry.setTriggerValue(cron);
this.schedulerEntry = entry;
} catch (Exception e) {
LOG.error("Scheduler CronText was lost. Requires server restart to recover.");
}
// Add and schedule if it is supposed to be running
if (state != TriggerState.UNSCHEDULED) {
portlet.getSchedulerEntries().add(entry);
// , description=This scheduler is used to collect Statistical Data
// from Database,
// eventListenerClass=de.uhh.l2g.plugins.util.StatisticsScheduler,
// propertyKey=, timeUnit=null, trigger={cronText=0 */1 * * * ?,
// {endDate=null,
// groupName=de.uhh.l2g.plugins.util.StatisticsScheduler,
// jobName=de.uhh.l2g.plugins.util.StatisticsScheduler,
// startDate=null, triggerType=CRON}}, triggerType=CRON,
// triggerValue=0 */1 * * * ?}
try {
SchedulerEngineHelperUtil.schedule(entry, this.STOR, portletId, 0);
} catch (SchedulerException e) {
LOG.error("Failed adding Scheduler!");
}
}
return this.schedulerEntry;
}
/**
* Crowds this Scheduler with ResponseMessage Data Unique iff (jobName ==
* schedulerClassName == groupName && storageType == STOR)
*
* @return PortletScheduler
*/
public PortletScheduler assembleMessageFromResponses() {
// These should be unique if everything is configured by liferay default
try {
List<SchedulerResponse> scheduledJobs = SchedulerEngineHelperUtil.getScheduledJobs();
for (SchedulerResponse resp : scheduledJobs) {
if (resp.getJobName().equalsIgnoreCase(this.schedulerClassName)) {
this.setJobName(resp.getJobName());
this.setGroupName(resp.getGroupName());
this.setStorageType(resp.getStorageType());
this.setDescription(resp.getDescription());
this.setMessage(resp.getMessage());
this.setTrigger(resp.getTrigger());
if (this.getMessage() == null)
this.setMessage(new Message());
LOG.debug("Job found. Copy Portlet Information: " + this.getMessage().toString());
Map<String, Object> map = this.getMessage().getValues();
// Fill this message with portlet specific data
if (map.containsKey(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME)) this.getMessage().put(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME, map.get(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME).toString());
if (map.containsKey(SchedulerEngine.PORTLET_ID)) this.getMessage().put(SchedulerEngine.PORTLET_ID, map.get(SchedulerEngine.PORTLET_ID).toString());
if (map.containsKey(SchedulerEngine.MESSAGE_LISTENER_UUID)) this.getMessage().put(SchedulerEngine.MESSAGE_LISTENER_UUID, map.get(SchedulerEngine.MESSAGE_LISTENER_UUID).toString());
LOG.debug(this.getMessage().get(SchedulerEngine.DESTINATION_NAME) + " " + this.getMessage().getDestinationName() + " " + this.getMessage().getValues().get(SchedulerEngine.DESTINATION_NAME) + " " + this.getMessage().getDestinationName());
if (map.containsKey("MESSAGE_LISTENER_CLASS_NAME") && map.get("DESTINATION_NAME") != null) {
this.destination = map.get("DESTINATION_NAME").toString();
// this.getMessage().put(SchedulerEngine.DESTINATION_NAME,
// map.get("DESTINATION_NAME").toString());
this.getMessage().getValues().put(SchedulerEngine.DESTINATION_NAME, map.get("DESTINATION_NAME").toString());
this.getMessage().setDestinationName(this.getMessage().getValues().get(SchedulerEngine.DESTINATION_NAME).toString());
} else {
LOG.debug("Destination not available yet. Setting to " + DEST);
this.destination = DEST;
// this.getMessage().put(SchedulerEngine.DESTINATION_NAME,
// DEST);
this.getMessage().getValues().put(SchedulerEngine.DESTINATION_NAME, DEST);
this.getMessage().setDestinationName(this.getMessage().getValues().get(SchedulerEngine.DESTINATION_NAME).toString());
}
// new ReceiverKey(this.getJobName(), this.getGroupName())
this.getMessage().put(SchedulerEngine.RECEIVER_KEY, GetterUtil.getString(new ReceiverKey(this.getJobName(), this.getGroupName())));
LOG.debug("ReceiverKey: " + new ReceiverKey(this.getJobName(), this.getGroupName()));
TriggerState state = SchedulerEngineHelperUtil.getJobState(this.getJobName(), this.getGroupName(), this.getStorageType());
LOG.debug(state);
}
}
} catch (SchedulerException e) {
LOG.warn(e);
}
return this;
}
@Override
public void receive(Message message) throws MessageListenerException {
String values = "No values";
// Debug Information on running job
if (message != null) {
LOG.info("Message :" + message.toString());
Thread thread = Thread.currentThread();
LOG.info("Thread :" + thread.getContextClassLoader());
LOG.info("Thread :" + thread.toString());
Map<String, Object> map = message.getValues();
LOG.info(message.get(SchedulerEngine.DESTINATION_NAME) + " " + message.getDestinationName() + " " + message.getValues().get(SchedulerEngine.DESTINATION_NAME) + " " + message.getDestinationName());
values = map.toString();
}
LOG.info("Portlet Scheduler running... " + values);
}
public void pause() throws SchedulerException {
LOG.info("Pausing... :" + GetterUtil.getString(this.schedulerClassName));
SchedulerEngineHelperUtil.pause(this.schedulerClassName, this.schedulerClassName, this.getStorageType());
}
public void resume() throws SchedulerException {
LOG.info("Resuming... :" + GetterUtil.getString(this.schedulerClassName));
SchedulerEngineHelperUtil.resume(this.schedulerClassName, this.schedulerClassName, this.getStorageType());
}
public void update() throws SchedulerException {
LOG.info("Updating... :" + GetterUtil.getString(this.schedulerClassName));
SchedulerEngineHelperUtil.update(this.getTrigger(), this.getStorageType());
}
/**
* Schedule unscheduled Scheduler (requires valid SchedulerEntry Data &&
* Message Date)
*
* There is no Issue in Liferay Tracker about this: Manually assembling.
* Message, Trigger and Job from previously "working" Job, in order to use
*
* SchedulerEngineHelperUtil.schedule(Trigger, StorageType, Description,
* Destination, Message, exceptionsMaxSize);
*
* Currently (6.2 GA 4 - GA 6) also fails to register the MessageListener
* correctly for a single consumer. This might be a configuration detail
* issue, which is not documented in liferays SchedulerEngineHelperUtil, at
* first sight source investigation does not reveal conclusive hints.
*
* Though the more complicated issue is that Quartz does persist the Job on
* UNSCHEDULE but not the Trigger.
*
* Therefore a SchedulerEntry must be available in Memory, to schedule an
* unscheduled Job Liferay SchedulerEntry however does persit the Trigger...
* but does not check for duplicates on deploy.
*
* If we keep the SchedulerEntry in the List we have the Trigger but
* unregister fails and duplicates the Scheduler If we remove the
* SchedulerEntry unregister works correctly but we lose the Trigger
*
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws SchedulerException
* @throws Exception
* @throws InstantiationException
* *
*
public void start() {
int exceptionsMaxSize = 0;
try {
String messageText = GetterUtil.getString((this.getMessage().toString()));
LOG.info("Starting :" + messageText);
Map<String, Object> map = this.getMessage().getValues();
String portletId = "";
String listenerName = "";
if (map.containsKey(SchedulerEngine.PORTLET_ID))
portletId = map.get(SchedulerEngine.PORTLET_ID).toString();
if (map.containsKey(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME))
listenerName = map.get(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME).toString();
if (map.containsKey(SchedulerEngine.EXCEPTIONS_MAX_SIZE))
exceptionsMaxSize = Integer.valueOf(map.get(SchedulerEngine.EXCEPTIONS_MAX_SIZE).toString());
LOG.info("Message :" + portletId + " " + listenerName + " " + this.destination);
if (this.getTrigger() == null) this.setTrigger(this.generalTrigger);
TriggerState state = SchedulerEngineHelperUtil.getJobState(this.getJobName(), this.getGroupName(), this.getStorageType());
LOG.info("Trigger :" + GetterUtil.getString(this.getTrigger().toString()) + state);
if (state != null && state.equals(TriggerState.UNSCHEDULED)) {
this.getMessage().put(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME, this.schedulerClassName);
this.getMessage().setDestinationName(this.DEST);
this.getMessage().put(SchedulerEngine.RECEIVER_KEY, this.getMessage().getValues().get(SchedulerEngine.RECEIVER_KEY).toString());
LOG.info("Scheduling :" + this.schedulerClassName + " ");
LOG.info("New Message " + this.getMessage().toString());
Thread thread = Thread.currentThread();
LOG.info("Thread :" + thread.getContextClassLoader() + thread.toString());
if (this.schedulerEntry != null && this.getTrigger() != null) SchedulerEngineHelperUtil.schedule(schedulerEntry, this.getStorageType(), portletId, exceptionsMaxSize);
else assembleEntryFromSettings(this.schedulerClassName, TriggerState.NORMAL);
} else {
if (state == null) LOG.error("Could not find Job with Name: " + this.schedulerClassName);
else LOG.info("Could not schedule Job with State: " + state);
}
} catch (SchedulerException e) {
LOG.warn("", e);
} catch (IllegalArgumentException e) {
LOG.warn(e);
}
} */
/**
* Schedule unscheduled Scheduler (requires valid SchedulerEntry Data &&
* Message Date)
*
* There is no Issue in Liferay Tracker about this: Manually assembling.
* Message, Trigger and Job from previously "working" Job, in order to use
*
* SchedulerEngineHelperUtil.schedule(Trigger, StorageType, Description,
* Destination, Message, exceptionsMaxSize);
*
* Currently (6.2 GA 4 - GA 6) also fails to register the MessageListener
* correctly for a single consumer. This might be a configuration detail
* issue, which is not documented in liferays SchedulerEngineHelperUtil, at
* first sight source investigation does not reveal conclusive hints.
*
* Though the more complicated issue is that Quartz does persist the Job on
* UNSCHEDULE but not the Trigger.
*
* Therefore a SchedulerEntry must be available in Memory, to schedule an
* unscheduled Job Liferay SchedulerEntry however does persit the Trigger...
* but does not check for duplicates on deploy.
*
* If we keep the SchedulerEntry in the List we have the Trigger but
* unregister fails and duplicates the Scheduler If we remove the
* SchedulerEntry unregister works correctly but we lose the Trigger
*
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws SchedulerException
* @throws Exception
* @throws InstantiationException
* *
*/
public void schedule() {
int exceptionsMaxSize = 0;
try {
String messageText = GetterUtil.getString((this.getMessage().toString()));
LOG.info("Starting :" + messageText);
Map<String, Object> map = this.getMessage().getValues();
String portletId = "";
String listenerName = "";
if (map.containsKey(SchedulerEngine.PORTLET_ID))
portletId = map.get(SchedulerEngine.PORTLET_ID).toString();
if (map.containsKey(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME))
listenerName = map.get(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME).toString();
if (map.containsKey(SchedulerEngine.EXCEPTIONS_MAX_SIZE))
exceptionsMaxSize = Integer.valueOf(map.get(SchedulerEngine.EXCEPTIONS_MAX_SIZE).toString());
LOG.info("Message :" + portletId + " " + listenerName + " " + this.destination);
if (this.getTrigger() == null) this.setTrigger(this.generalTrigger);
TriggerState state = SchedulerEngineHelperUtil.getJobState(this.getJobName(), this.getGroupName(), this.getStorageType());
LOG.info("Trigger :" + GetterUtil.getString(this.getTrigger().toString()) + state);
if (state != null && state.equals(TriggerState.UNSCHEDULED)) {
this.getMessage().put(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME, this.schedulerClassName);
this.getMessage().setDestinationName(this.DEST);
this.getMessage().put(SchedulerEngine.RECEIVER_KEY, this.getMessage().getValues().get(SchedulerEngine.RECEIVER_KEY).toString());
LOG.info("Scheduling :" + this.schedulerClassName + " ");
LOG.info("New Message " + this.getMessage().toString());
Thread thread = Thread.currentThread();
LOG.info("Thread :" + thread.getContextClassLoader() + thread.toString());
if (this.schedulerEntry != null && this.getTrigger() != null) SchedulerEngineHelperUtil.schedule(schedulerEntry, this.getStorageType(), portletId, exceptionsMaxSize);
else assembleEntryFromSettings(this.schedulerClassName, TriggerState.NORMAL);
} else {
if (state == null) LOG.error("Could not find Job with Name: " + this.schedulerClassName);
else LOG.info("Could not schedule Job with State: " + state);
}
} catch (SchedulerException e) {
LOG.warn("", e);
} catch (IllegalArgumentException e) {
LOG.warn(e);
}
}
/**
* Unschedules Quartz Job but keeps SchedulerEntry in Memory (Scheduler will
* be not correctly (re)deployed if in state UNSCHEDULED
*
*/
public void unschedule() {
try {
List<SchedulerResponse> scheduledJobs = SchedulerEngineHelperUtil.getScheduledJobs();
for (SchedulerResponse resp : scheduledJobs) {
if (resp.getJobName().equalsIgnoreCase(this.schedulerClassName)) {
LOG.info("Stopping :" + resp.toString());
Map<String, Object> map = resp.getMessage().getValues();
String portletId = "";
String listenerName = "";
if (map.containsKey(SchedulerEngine.PORTLET_ID)) portletId = map.get(SchedulerEngine.PORTLET_ID).toString();
if (map.containsKey(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME)) listenerName = map.get(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME).toString();
LOG.info("Associated to :" + portletId + " " + listenerName + " " + this.destination);
TriggerState state = SchedulerEngineHelperUtil.getJobState(resp.getJobName(), resp.getGroupName(), resp.getStorageType());
if (state != (TriggerState.UNSCHEDULED)) {
Thread thread = Thread.currentThread();
LOG.info("Thread :" + thread.getContextClassLoader() + thread.toString());
LOG.info("Unscheduling :" + this.schedulerClassName + " " + resp.getTrigger().toString());
SchedulerEngineHelperUtil.unschedule(schedulerEntry, resp.getStorageType());
// TODO: Check Workaround
// This removes the SchedulerEntry from Liferay's
// Scheduler List so it is not started aditionally on
// re-deploy
// BUT, removing this entry will also destroy our
// Trigger (as Quartz unschedule(), removes the Trigger
// from QuartzJob
this.removeFromEntries();
} else {
LOG.warn("Scheduler could not be unscheduled beacuse it was in state " + state);
}
}
}
} catch (SchedulerException e) {
LOG.warn("Failed to unschedule job" + this.schedulerClassName, e);
}
}
/**
* Deletes the Scheduler thoroughly until server restart!
*
*/
public void delete() {
try {
List<SchedulerResponse> scheduledJobs = SchedulerEngineHelperUtil.getScheduledJobs();
for (SchedulerResponse resp : scheduledJobs) {
if (resp.getJobName().equalsIgnoreCase(this.schedulerClassName)) {
LOG.info("Stopping :" + resp.toString());
Map<String, Object> map = resp.getMessage().getValues();
String portletId = "";
String listenerName = "";
if (map.containsKey(SchedulerEngine.PORTLET_ID)) portletId = map.get(SchedulerEngine.PORTLET_ID).toString();
if (map.containsKey(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME)) listenerName = map.get(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME).toString();
LOG.info("Associated to :" + portletId + " " + listenerName + " " + this.destination);
TriggerState state = SchedulerEngineHelperUtil.getJobState(resp.getJobName(), resp.getGroupName(), resp.getStorageType());
if (state.equals(TriggerState.NORMAL)) {
Thread thread = Thread.currentThread();
LOG.info("Thread :" + thread.getContextClassLoader() + thread.toString());
LOG.info("Unscheduling :" + this.schedulerClassName + " " + resp.getTrigger().toString());
SchedulerEngineHelperUtil.delete(schedulerEntry, resp.getStorageType());
// This removes the SchedulerEntry from Liferay's
// Scheduler List so it is not started aditionally on
// re-deploy
// Removing this entry will also destroy our Trigger (as
// Quartz unschedule(), removes the Trigger from
// QuartzJob
this.removeFromEntries();
} else {
LOG.warn("Scheduler could not be unscheduled beacuse it was in state " + state);
}
}
}
} catch (SchedulerException e) {
LOG.warn("Failed to unschedule job" + this.schedulerClassName, e);
}
}
/**
* Unschedules all Jobs associated with this Listener Class'
*
* Assumes Job and Group Name are equal
*/
public void stopAll() {
if (this.schedulerClassName != null && this.schedulerClassName != "") {
List<SchedulerResponse> scheduledJobs;
try {
scheduledJobs = SchedulerEngineHelperUtil.getScheduledJobs();
for (SchedulerResponse resp : scheduledJobs) {
if (resp.getJobName().equalsIgnoreCase(this.schedulerClassName)) {
SchedulerEngineHelperUtil.unschedule(resp.getJobName(), resp.getGroupName(), resp.getStorageType());
}
}
LOG.warn("Removed all Schedulers associated with " + this.schedulerClassName);
} catch (SchedulerException e) {
LOG.error("Could not retrieve ScheduledJobs");
}
} else {
LOG.info("No Scheduler set!");
}
}
/**
* Unschedules and deletes all Jobs associated with this Listener Class'
* Does not affect SchedulerEntries!
* Assumes Job and Group Name are equal
*/
public static void pauseAllJobs() {
List<SchedulerResponse> scheduledJobs;
try {
scheduledJobs = SchedulerEngineHelperUtil.getScheduledJobs();
for (SchedulerResponse resp : scheduledJobs) {
if (resp != null && resp.getJobName().contains(PortletScheduler.class.getPackage().getName())) {
SchedulerEngineHelperUtil.pause(resp.getJobName(), resp.getGroupName(), resp.getStorageType());
}
}
LOG.info("Paused all Schedulers associated with " + PortletScheduler.class.getPackage().getName());
} catch (SchedulerException e) {
LOG.error("Could not retrieve ScheduledJobs");
}
}
/**
* Unschedules and removes all Jobs associated with this Listener Class'
*
* Assumes Job and Group Name are equal
*/
public static void removeAllJobs(String portletId) {
List<SchedulerResponse> scheduledJobs;
List<SchedulerEntry> entries;
Portlet portlet = PortletLocalServiceUtil.getPortletById(portletId);
List<SchedulerEntry> toRemove = new LinkedList<SchedulerEntry>();
TriggerState state;
try {
scheduledJobs = SchedulerEngineHelperUtil.getScheduledJobs();
for (SchedulerResponse resp : scheduledJobs) {
if (resp.getJobName().startsWith(PortletScheduler.class.getPackage().getName())) {
state = SchedulerEngineHelperUtil.getJobState(resp.getJobName(), resp.getGroupName(), resp.getStorageType());
if (state != (TriggerState.UNSCHEDULED)) SchedulerEngineHelperUtil.unschedule(resp.getJobName(), resp.getGroupName(), resp.getStorageType());
entries = portlet.getSchedulerEntries();
for (SchedulerEntry entry : entries) {
if(entry.getEventListenerClass().equalsIgnoreCase(resp.getJobName())){
LOG.info("SchedulerEntry: " + entry.toString());
toRemove.add(entry);
}
}
entries.removeAll(toRemove);
}
}
LOG.warn("Removed all Schedulers associated with " + PortletScheduler.class.getPackage().getName());
} catch (SchedulerException e) {
LOG.error("Could not retrieve ScheduledJobs");
}
}
/*
* List Jobs recognized by Scheduler Engine (these are naturally unique)
*/
public static List<PortletScheduler> ListSchedulers() {
List<PortletScheduler> schedulers = new LinkedList<PortletScheduler>();
PortletScheduler psch = null;
try {
List<SchedulerResponse> scheduledJobs = SchedulerEngineHelperUtil.getScheduledJobs();
for (SchedulerResponse resp : scheduledJobs) {
if (resp != null && resp.getJobName().contains(PortletScheduler.class.getPackage().getName())) {
psch = new PortletScheduler();
LOG.info(resp.toString());
psch.setJobName(resp.getJobName());
psch.setGroupName(resp.getGroupName());
psch.setStorageType(resp.getStorageType());
psch.setDescription(resp.getDescription());
psch.setMessage(resp.getMessage());
psch.setTrigger(resp.getTrigger());
TriggerState state = SchedulerEngineHelperUtil.getJobState(resp.getJobName(), resp.getGroupName(), resp.getStorageType());
schedulers.add(psch);
LOG.info("SchedulerResponse: " + psch.getJobName());
}
}
} catch (SchedulerException e) {
LOG.error("Could not retrieve ScheduledJobs");
}
return schedulers;
}
/**
* Removes this Scheduler's SchedulerEntry from Liferay's List
*
*/
public void removeFromEntries() {
Portlet portlet = PortletLocalServiceUtil.getPortletById(this.portletId);
// List<SchedulerEntry> schedulerEntries =
// portlet.getSchedulerEntries();
portlet.getSchedulerEntries().remove(this.schedulerEntry);
}
/**
* Removes this Scheduler's SchedulerEntry from Liferay's List
*/
public void removeFromEntries(SchedulerEntry entry) {
Portlet portlet = PortletLocalServiceUtil.getPortletById(this.portletId);
// List<SchedulerEntry> schedulerEntries =
// portlet.getSchedulerEntries();
portlet.getSchedulerEntries().remove(entry);
}
/**
* From HotDeployListener (this one should do garbage collect, but fails if
* a scheduler is UNSCHEDULED allready) if (PropsValues.SCHEDULER_ENABLED) {
* List<SchedulerEntry> schedulerEntries = portlet.getSchedulerEntries();
*
* if ((schedulerEntries != null) && !schedulerEntries.isEmpty()) { for
* (SchedulerEntry schedulerEntry : schedulerEntries) {
* SchedulerEngineHelperUtil.unschedule( schedulerEntry,
* StorageType.MEMORY_CLUSTERED); } } }
*/
/**
* List SchedulerEntries associated with this Portlet These are Scheduler
* entries as persited by liferay
*
* Allows duplicates!
*
* @param portletId
* @return Liferay Portlet SchedulerEntries
*/
public static List<SchedulerEntry> ListSchedulerEntries(String portletId) {
Portlet portlet = PortletLocalServiceUtil.getPortletById(portletId);
List<SchedulerEntry> myJobs = new LinkedList<SchedulerEntry>();
List<SchedulerEntry> jobs = portlet.getSchedulerEntries();
for (SchedulerEntry job : jobs) {
LOG.info("SchedulerEntry: " + job.toString());
myJobs.add(job);
}
return myJobs;
}
}