/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * MonitorJobDescription.java * Created: 15-Mar-2004 * By: Rick Cameron */ package org.openquark.samples.bam.model; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.openquark.cal.compiler.QualifiedName; import org.openquark.samples.bam.MessageSourceFactory; import org.openquark.samples.bam.model.MessageSourceDescription.MessagePropertyDescription; import org.openquark.util.xml.BadXMLDocumentException; import org.openquark.util.xml.XMLPersistenceHelper; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * This class is used to describe a job. The description is composed of a message source and * the set of triggers and and actions that define the message processing. */ public class MonitorJobDescription { /** * This interface must be implemented by clients that wish to receive * notifications when the job description is modified. */ public static interface MonitorJobDescriptionListener { void triggerAdded (TriggerDescription triggerDescription); void triggerReplaced (TriggerDescription oldTriggerDescription, TriggerDescription triggerDescription); void triggerRemoved (TriggerDescription triggerDescription); void actionAdded (ActionDescription actionDescription); void actionReplaced (ActionDescription oldActionDescription, ActionDescription actionDescription); void actionRemoved (ActionDescription actionDescription); } private MessageSourceDescription messageSourceDescription; private List<MessagePropertyDescription> messagePropertyDescriptions; //used to cache the message property descriptions private List<TriggerDescription> triggerDescriptions = new ArrayList<TriggerDescription> (); // of TriggerDescriptions private List<ActionDescription> actionDescriptions = new ArrayList<ActionDescription> (); // of ActionDescriptions private List<MonitorJobDescriptionListener> listeners = new ArrayList<MonitorJobDescriptionListener> (); //clients that receive modify notifications public MonitorJobDescription (MessageSourceDescription messageSourceDescription) { jobId = "job" + ++jobNum; this.messageSourceDescription = messageSourceDescription; this.messagePropertyDescriptions = new ArrayList<MessagePropertyDescription> (messageSourceDescription.getMessagePropertyDescriptions()); } private static int jobNum=0; /** * A unique ID associated with this job */ private final String jobId; /** * Constructor MonitorJobDescription */ private MonitorJobDescription () { jobId = "Job" + ++jobNum; } /** * get the job id for this job * @return the unique job id */ public String getJobId() { return jobId; } public MessageSourceDescription getMessageSourceDescription () { return messageSourceDescription; } public Collection<MessagePropertyDescription> getMessagePropertyDescriptions () { return Collections.unmodifiableCollection (messagePropertyDescriptions); } public List<TriggerDescription> getTriggerDescriptions () { return Collections.unmodifiableList (triggerDescriptions); } public void addTrigger (TriggerDescription triggerDescription) { triggerDescriptions.add (triggerDescription); fireTriggerAdded (triggerDescription); } public void replaceTriggerDescription (int n, TriggerDescription triggerDescription) { if (n >= triggerDescriptions.size()) { throw new IllegalArgumentException ("Trigger index out of range: " + n); } TriggerDescription oldTriggerDescription = triggerDescriptions.get(n); triggerDescriptions.set(n, triggerDescription); fireTriggerReplaced (oldTriggerDescription, triggerDescription); } public void removeTrigger (TriggerDescription triggerDescription) { triggerDescriptions.remove(triggerDescription); fireTriggerRemoved (triggerDescription); } public List<ActionDescription> getActionDescriptions () { return Collections.unmodifiableList (actionDescriptions); } public void addAction (ActionDescription actionDescription) { actionDescriptions.add (actionDescription); fireActionAdded (actionDescription); } public void replaceActionDescription (int n, ActionDescription actionDescription) { if (n >= actionDescriptions.size()) { throw new IllegalArgumentException ("Action index out of range: " + n); } ActionDescription oldActionDescription = actionDescriptions.get(n); actionDescriptions.set(n, actionDescription); fireActionReplaced (oldActionDescription, actionDescription); } public void removeAction (ActionDescription actionDescription) { actionDescriptions.remove(actionDescription); fireActionRemoved (actionDescription); } /** * Computes the minimal set of metrics required by the job's triggers and actions * @return set of required metrics */ public Collection<MetricDescription> getMetricDescriptions () { Set<MetricDescription> metrics=new HashSet<MetricDescription>(); Collection<TriggerDescription> triggers=getTriggerDescriptions(); for (final TriggerDescription td : triggers) { for(int i=0; i < td.getBindingCount(); i++) { metrics.addAll(td.getNthBinding(i).getRequiredMetrics()); } } Collection<ActionDescription> actions=getActionDescriptions(); for (final ActionDescription td : actions) { for(int i=0; i < td.getBindingCount(); i++) { metrics.addAll(td.getNthBinding(i).getRequiredMetrics()); } } return metrics; } /** * Method makeTestInstance * */ public static MonitorJobDescription makeTestInstance () { MessageSourceDescription messageSourceDescription = new TextFileMessageSourceDescription ("Customer Sales", "Resources/testfile.txt"); MonitorJobDescription result = new MonitorJobDescription (messageSourceDescription); MessagePropertyDescription namePropertyInfo = result.messagePropertyDescriptions.get(0); MessagePropertyDescription amountPropertyInfo = result.messagePropertyDescriptions.get(1); MetricDescription metricDescription = new MetricDescription ( QualifiedName.make("Cal.Samples.BusinessActivityMonitor.BAM", "average") , amountPropertyInfo); ArrayList<InputBinding> triggerInputBindings = new ArrayList<InputBinding> (); triggerInputBindings.add (new MetricBinding (metricDescription)); triggerInputBindings.add (new ConstantBinding (new Double (4500.00))); triggerInputBindings.add (new PropertyBinding (amountPropertyInfo)); result.triggerDescriptions.add (new TriggerDescription ("Cal.Samples.BusinessActivityMonitor.BAM.outsideOfRange", triggerInputBindings)); ArrayList<InputBinding> actionInputBindings = new ArrayList<InputBinding> (); actionInputBindings.add (new ConstantBinding ("joe@bloggs.com")); actionInputBindings.add (new ConstantBinding ("Sales out of range!")); actionInputBindings.add (makeEmailBodyBinding (namePropertyInfo, amountPropertyInfo)); result.actionDescriptions.add (new ActionDescription ("Cal.Samples.BusinessActivityMonitor.BAM.sendSimulatedEmail", actionInputBindings)); return result; } /** * Method makeEmailBodyBinding * * @return Returns an InputBinding for the body of an email message */ private static InputBinding makeEmailBodyBinding (MessagePropertyDescription namePropertyInfo, MessagePropertyDescription amountPropertyInfo) { List<InputBinding> inputsList = new ArrayList<InputBinding> (); inputsList.add (new PropertyBinding (namePropertyInfo)); inputsList.add (new PropertyBinding (amountPropertyInfo)); return new TemplateStringBinding ("The sales amount for customer {0} (${1}) is out of range", inputsList); } /** * Method makeAnotherTestInstance * */ public static MonitorJobDescription makeAnotherTestInstance () { MessageSourceDescription messageSourceDescription = new TextFileMessageSourceDescription ("More Customer Sales", "Resources/testfile.txt"); MonitorJobDescription result = new MonitorJobDescription (messageSourceDescription); // outsideOfSigmas arg stdDev threshold mean ArrayList<InputBinding> triggerInputBindings = new ArrayList<InputBinding> (); triggerInputBindings.add (new PropertyBinding (result.messagePropertyDescriptions.get(1))); triggerInputBindings.add (new ConstantBinding (new Double (750.00))); triggerInputBindings.add (new ConstantBinding (new Double (2))); triggerInputBindings.add (new ConstantBinding (new Double (3000.00))); result.triggerDescriptions.add (new TriggerDescription ("Cal.Samples.BusinessActivityMonitor.BAM.outsideOfSigmas", triggerInputBindings)); ArrayList<InputBinding> actionInputBindings = new ArrayList<InputBinding> (); actionInputBindings.add (new ConstantBinding ("joe@bloggs.com")); actionInputBindings.add (new ConstantBinding ("Sales outside of sigmas!")); actionInputBindings.add (new PropertyBinding (result.messagePropertyDescriptions.get(0))); result.actionDescriptions.add (new ActionDescription ("Cal.Samples.BusinessActivityMonitor.BAM.sendSimulatedEmail", actionInputBindings)); return result; } // // Listener management // public void addJobDescriptionListener (MonitorJobDescriptionListener listener) { listeners.add (listener); } public void removeJobDescriptionListener (MonitorJobDescriptionListener listener) { listeners.remove (listener); } private void fireTriggerAdded (TriggerDescription triggerDescription) { List<MonitorJobDescriptionListener> tempList = new ArrayList<MonitorJobDescriptionListener> (listeners); for (final MonitorJobDescriptionListener listener : tempList) { listener.triggerAdded (triggerDescription); } } /** * Method fireTriggerReplaced * * @param oldTriggerDescription * @param triggerDescription */ private void fireTriggerReplaced (TriggerDescription oldTriggerDescription, TriggerDescription triggerDescription) { List<MonitorJobDescriptionListener> tempList = new ArrayList<MonitorJobDescriptionListener> (listeners); for (final MonitorJobDescriptionListener listener : tempList) { listener.triggerReplaced (oldTriggerDescription, triggerDescription); } } private void fireTriggerRemoved (TriggerDescription triggerDescription) { List<MonitorJobDescriptionListener> tempList = new ArrayList<MonitorJobDescriptionListener> (listeners); for (final MonitorJobDescriptionListener listener : tempList) { listener.triggerRemoved (triggerDescription); } } private void fireActionAdded (ActionDescription actionDescription) { List<MonitorJobDescriptionListener> tempList = new ArrayList<MonitorJobDescriptionListener> (listeners); for (final MonitorJobDescriptionListener listener : tempList) { listener.actionAdded (actionDescription); } } /** * Method fireActionReplaced * * @param oldActionDescription * @param actionDescription */ private void fireActionReplaced (ActionDescription oldActionDescription, ActionDescription actionDescription) { List<MonitorJobDescriptionListener> tempList = new ArrayList<MonitorJobDescriptionListener> (listeners); for (final MonitorJobDescriptionListener listener : tempList) { listener.actionReplaced (oldActionDescription, actionDescription); } } private void fireActionRemoved (ActionDescription actionDescription) { List<MonitorJobDescriptionListener> tempList = new ArrayList<MonitorJobDescriptionListener> (listeners); for (final MonitorJobDescriptionListener listener : tempList) { listener.actionRemoved (actionDescription); } } // // Serialisation // /** * Method store * * @param parentElement */ void store (Element parentElement) { Document document = parentElement.getOwnerDocument (); // Construct a new element for the job description. Element jobDescriptionElem = document.createElement (MonitorSaveConstants.JobDescription); parentElement.appendChild (jobDescriptionElem); storeMessageSourceDescription (jobDescriptionElem); storeTriggerDescriptions (jobDescriptionElem); storeActionDescriptions (jobDescriptionElem); } /** * Method storeMessageSourceDescription * * @param jobDescriptionElem */ private void storeMessageSourceDescription (Element jobDescriptionElem) { Document document = jobDescriptionElem.getOwnerDocument (); // Construct a new element for the job description. Element messageSourceElem = document.createElement (MonitorSaveConstants.MessageSource); jobDescriptionElem.appendChild (messageSourceElem); messageSourceDescription.store (messageSourceElem); } /** * Method storeTriggerDescriptions * * @param jobDescriptionElem */ private void storeTriggerDescriptions (Element jobDescriptionElem) { Document document = jobDescriptionElem.getOwnerDocument (); // Construct a new element for the trigger descriptions. Element triggersElem = document.createElement (MonitorSaveConstants.TriggerDescriptions); jobDescriptionElem.appendChild (triggersElem); for (final TriggerDescription triggerDescription : triggerDescriptions) { triggerDescription.store (triggersElem); } } /** * Method storeActionDescriptions * * @param jobDescriptionElem */ private void storeActionDescriptions (Element jobDescriptionElem) { Document document = jobDescriptionElem.getOwnerDocument (); // Construct a new element for the action descriptions. Element actionsElem = document.createElement (MonitorSaveConstants.ActionDescriptions); jobDescriptionElem.appendChild (actionsElem); for (final ActionDescription actionDescription : actionDescriptions) { actionDescription.store (actionsElem); } } /** * Method Load * * @param element * @return Returns a MonitorJobDescription loaded from the given XML element */ public static MonitorJobDescription Load (Element element) throws InvalidFileFormat, BadXMLDocumentException { if (element.getTagName().equals (MonitorSaveConstants.JobDescription)) { MonitorJobDescription jobDescription = new MonitorJobDescription (); jobDescription.load (element); return jobDescription; } return null; } /** * Method load * * @param jobDescriptionElem */ private void load (Element jobDescriptionElem) throws InvalidFileFormat, BadXMLDocumentException { loadMessageSource (jobDescriptionElem); loadTriggerDescriptions (jobDescriptionElem, messagePropertyDescriptions); loadActionDescriptions (jobDescriptionElem); } /** * Method loadMessageSource * * @param jobDescriptionElem * @throws InvalidFileFormat */ private void loadMessageSource (Element jobDescriptionElem) throws InvalidFileFormat { Element messageSourceElem = XMLPersistenceHelper.getChildElement(jobDescriptionElem, MonitorSaveConstants.MessageSource); if (messageSourceElem == null) { throw new InvalidFileFormat ("MessageSource element missing"); } messageSourceDescription = MessageSourceFactory.Load (messageSourceElem); messagePropertyDescriptions = new ArrayList<MessagePropertyDescription> (messageSourceDescription.getMessagePropertyDescriptions()); } /** * Method loadTriggerDescriptions * * @param jobDescriptionElem */ private void loadTriggerDescriptions (Element jobDescriptionElem, Collection<MessagePropertyDescription> messagePropertyInfos) throws InvalidFileFormat, BadXMLDocumentException { Element triggersElem = XMLPersistenceHelper.getChildElement(jobDescriptionElem, MonitorSaveConstants.TriggerDescriptions); if (triggersElem == null) { throw new InvalidFileFormat ("TriggerDescriptions element missing"); } List<Element> triggerElems = XMLPersistenceHelper.getChildElements(triggersElem); for (final Element triggerElem : triggerElems) { triggerDescriptions.add (TriggerDescription.Load (triggerElem, messagePropertyInfos)); } } /** * Method loadActionDescriptions * * @param jobDescriptionElem */ private void loadActionDescriptions (Element jobDescriptionElem) throws BadXMLDocumentException, InvalidFileFormat { Element actionsElem = XMLPersistenceHelper.getChildElement(jobDescriptionElem, MonitorSaveConstants.ActionDescriptions); if (actionsElem == null) { throw new InvalidFileFormat ("ActionDescriptions element missing"); } List<Element> actionElems = XMLPersistenceHelper.getChildElements(actionsElem); for (final Element actionElem : actionElems) { actionDescriptions.add (ActionDescription.Load (actionElem, messagePropertyDescriptions)); } } }