/*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ package de.cismet.cids.servermessage; import Sirius.navigator.connection.SessionManager; import Sirius.navigator.exception.ConnectionException; import org.jdom.Attribute; import org.jdom.Element; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import de.cismet.cids.server.actions.CheckCidsServerMessageAction; import de.cismet.cids.server.actions.ServerActionParameter; import de.cismet.cids.server.messages.CidsServerMessage; import de.cismet.tools.configuration.Configurable; import de.cismet.tools.configuration.NoWriteError; /** * DOCUMENT ME! * * @author jruiz * @version $Revision$, $Date$ */ public class CidsServerMessageNotifier implements Configurable { //~ Static fields/initializers --------------------------------------------- private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger( CidsServerMessageNotifier.class); private static final String CONFIGURATION = "CidsServerMessages"; private static final String CONF_ELEM_INTERVALL = "intervall"; private static final String CONF_ELEM_LAST_MESSAGE_IDS = "last_message_ids"; private static final String CONF_ELEM_LAST_MESSAGE_ID = "last_message_id"; private static final String CONF_ATTR_LAST_MESSAGE_ID_CATEGORY = "category"; private static CidsServerMessageNotifier INSTANCE = null; public static final int DEFAULT_SCHEDULE_INTERVAL = 10000; //~ Instance fields -------------------------------------------------------- private final Map<String, Integer> lastMessageIds = new HashMap<String, Integer>(); private final Timer timer = new Timer(); private boolean running; private final Map<String, Collection> subscribers = new HashMap<String, Collection>(); private int scheduleIntervall = DEFAULT_SCHEDULE_INTERVAL; //~ Constructors ----------------------------------------------------------- /** * Creates a new CidsServerMessageNotifier object. */ private CidsServerMessageNotifier() { } //~ Methods ---------------------------------------------------------------- /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public static CidsServerMessageNotifier getInstance() { if (INSTANCE == null) { INSTANCE = new CidsServerMessageNotifier(); } return INSTANCE; } /** * DOCUMENT ME! */ public void start() { try { if (SessionManager.getSession().getConnection().hasConfigAttr( SessionManager.getSession().getUser(), "csa://" + CheckCidsServerMessageAction.TASK_NAME)) { synchronized (timer) { if (!running) { startTimer(true); } } } } catch (ConnectionException ex) { LOG.info("error checking csa://" + CheckCidsServerMessageAction.TASK_NAME + ". no cids server messages", ex); } } /** * DOCUMENT ME! * * @param scheduleIntervall DOCUMENT ME! */ public void setScheduleIntervall(final int scheduleIntervall) { this.scheduleIntervall = scheduleIntervall; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public int getScheduleIntervall() { return scheduleIntervall; } /** * DOCUMENT ME! * * @param listener DOCUMENT ME! * @param category DOCUMENT ME! */ public void subscribe(final CidsServerMessageNotifierListener listener, final String category) { if (!subscribers.containsKey(category)) { subscribers.put(category, new LinkedList<CidsServerMessageNotifierListener>()); } subscribers.get(category).add(listener); } /** * DOCUMENT ME! * * @param listener DOCUMENT ME! * @param category DOCUMENT ME! */ public void unsubscribe(final CidsServerMessageNotifierListener listener, final String category) { if (subscribers.containsKey(category)) { subscribers.get(category).remove(listener); } } /** * DOCUMENT ME! * * @param message DOCUMENT ME! * @param category DOCUMENT ME! */ private void publish(final CidsServerMessage message, final String category) { final Collection<CidsServerMessageNotifierListener> listeners = subscribers.containsKey(category) ? new ArrayList(subscribers.get(category)) : new ArrayList(); // add allcat (cat == null) listeners ? if ((category != null) && (subscribers.containsKey(null))) { listeners.addAll(subscribers.get(null)); } for (final CidsServerMessageNotifierListener listener : listeners) { new Thread(new Runnable() { @Override public void run() { try { listener.messageRetrieved( new CidsServerMessageNotifierListenerEvent(CidsServerMessageNotifier.this, message)); } catch (final Exception ex) { LOG.warn("error while invoking listener.messageRetrieved(...)", ex); } } }).start(); } } /** * DOCUMENT ME! * * @param firstStart DOCUMENT ME! */ private void startTimer(final boolean firstStart) { running = true; synchronized (timer) { timer.schedule(new RetrieveTimerTask(), firstStart ? 1000 : getScheduleIntervall()); } } @Override public void configure(final Element parent) { try { String elementIntervall = ""; if (parent != null) { final Element conf = parent.getChild(CONFIGURATION); if (conf != null) { elementIntervall = conf.getChildText(CONF_ELEM_INTERVALL); lastMessageIds.clear(); for (final Object child : conf.getChild(CONF_ELEM_LAST_MESSAGE_IDS).getChildren()) { final Element lastMessageIdElement = (Element)child; final String category = lastMessageIdElement.getAttributeValue( CONF_ATTR_LAST_MESSAGE_ID_CATEGORY); final Integer lastMessageId = Integer.valueOf(lastMessageIdElement.getText()); lastMessageIds.put(category, lastMessageId); } } } setScheduleIntervall(Integer.valueOf(elementIntervall)); } catch (final Exception ex) { LOG.warn("Fehler beim Konfigurieren des CidsServerMessagesNotifier", ex); } } @Override public Element getConfiguration() throws NoWriteError { final Element conf = new Element(CONFIGURATION); final Element intervallElement = new Element(CONF_ELEM_INTERVALL); intervallElement.addContent(Long.toString(getScheduleIntervall())); conf.addContent(intervallElement); final Element lastMessageIdsElement = new Element(CONF_ELEM_LAST_MESSAGE_IDS); for (final String category : lastMessageIds.keySet()) { final Integer lastMessageId = lastMessageIds.get(category); if (lastMessageId != null) { final Element lastMessageIdElement = new Element(CONF_ELEM_LAST_MESSAGE_ID); lastMessageIdElement.setAttribute(new Attribute(CONF_ATTR_LAST_MESSAGE_ID_CATEGORY, category)); lastMessageIdElement.setText(Integer.toString(lastMessageId)); lastMessageIdsElement.addContent(lastMessageIdElement); } } conf.addContent(lastMessageIdsElement); return conf; } @Override public void masterConfigure(final Element parent) { configure(parent); } //~ Inner Classes ---------------------------------------------------------- /** * DOCUMENT ME! * * @version $Revision$, $Date$ */ class RetrieveTimerTask extends TimerTask { //~ Constructors ------------------------------------------------------- /** * Creates a new RetrieveTimerTask object. */ public RetrieveTimerTask() { } //~ Methods ------------------------------------------------------------ @Override public void run() { boolean errorWhileCheck = false; try { if (SessionManager.getSession().getConnection().hasConfigAttr( SessionManager.getSession().getUser(), "csa://" + CheckCidsServerMessageAction.TASK_NAME)) { final ServerActionParameter<Map> lastMessageIdParam = new ServerActionParameter<Map>( CheckCidsServerMessageAction.Parameter.LAST_MESSAGE_IDS.toString(), lastMessageIds); final ServerActionParameter<Integer> intervallParam = new ServerActionParameter<Integer>( CheckCidsServerMessageAction.Parameter.INTERVALL.toString(), scheduleIntervall); final Object ret = SessionManager.getSession() .getConnection() .executeTask( SessionManager.getSession().getUser(), CheckCidsServerMessageAction.TASK_NAME, SessionManager.getSession().getUser().getDomain(), null, lastMessageIdParam, intervallParam); if (ret instanceof List) { final List<CidsServerMessage> cidsServerMessages = (List<CidsServerMessage>)ret; Collections.sort(cidsServerMessages, new Comparator<CidsServerMessage>() { @Override public int compare(final CidsServerMessage o1, final CidsServerMessage o2) { final Integer id1 = (o1 == null) ? null : o1.getId(); final Integer id2 = (o2 == null) ? null : o2.getId(); if ((id1 == null) && (id2 == null)) { return 0; } else if (id2 == null) { return 1; } else if (id1 == null) { return -1; } else { return Integer.compare(id1, id2); } } }); for (final CidsServerMessage cidsServerMessage : cidsServerMessages) { final int messageId = cidsServerMessage.getId(); final String category = cidsServerMessage.getCategory(); final Integer lastMessageId = lastMessageIds.get(category); if ((lastMessageId == null) || (messageId > lastMessageId)) { lastMessageIds.put(category, messageId); } publish(cidsServerMessage, cidsServerMessage.getCategory()); } } } } catch (final Exception ex) { LOG.error("error while checking message. abort retrieving new messages.", ex); errorWhileCheck = true; } finally { if (!errorWhileCheck) { synchronized (timer) { startTimer(false); } } } } } }