/*
* 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.
*/
/*
* MonitorJob.java
* Created: 15-Mar-2004
* By: Rick Cameron
*/
package org.openquark.samples.bam;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.logging.Logger;
import org.openquark.cal.compiler.io.EntryPointSpec;
import org.openquark.cal.runtime.CALExecutorException;
import org.openquark.cal.services.GemCompilationException;
import org.openquark.samples.bam.model.MonitorJobDescription;
import org.openquark.samples.bam.model.MessageSourceDescription.MessagePropertyDescription;
/**
* This class is used for running a single Job.
* A Job consists of a single message source and
* associated triggers and actions.
*/
class MonitorJob extends Thread {
private final Logger logger = Logger.getLogger("BAM");
/**
* This class is used to buffer messages between the CAL logic and the MessageSource
*
* The GEM code uses the Iterator interface to get messages
* The MessageSource uses the MessageListerner interface to insert messages as they arrive
*
* @author Magnus Byne
*/
private class MessageBuffer implements Iterator<List<Object>>, MessageListener, MessageSource.StatusListener {
LinkedList<Message> queue = new LinkedList<Message>();
/**
* this is called by the messageSource to add a message to the buffer.
* {@inheritDoc}
*/
public synchronized void messageReceived(Message msg) {
queue.addLast(msg);
notify();
}
/**
* This is called by the messageSource when its status changes - we notify the consumer
* in case the source has finished
* {@inheritDoc}
*/
public synchronized void statusChanged(int newStatus) {
notify();
}
/**
* Waits until a message is available in the buffer,
* or returns false if there are no more messages and the messageSource is not running
* {@inheritDoc}
*/
public synchronized boolean hasNext() {
while (queue.isEmpty()) {
try {
if (messageSource.isRunning()) {
wait();
} else {
return false;
}
} catch (InterruptedException e) {
return false;
}
}
return true;
}
/**
* gets the next message from the buffer
* throws a NoSuchElementException if no more messages are available
* {@inheritDoc}
*/
public synchronized List<Object> next () {
if (!hasNext()) {
throw new NoSuchElementException();
}
// create a list from the message properties
// this is the java representation of the CAL message tuple
// the order of the elements in the tuple must match the order expected by the GEM graph
// both are defined by the order of the message property descriptions in the job description
Collection<MessagePropertyDescription> propertyInfos = jobDescription.getMessagePropertyDescriptions();
List<Object> messageProperties = new ArrayList<Object>();
Message message=queue.removeFirst();
for (final MessagePropertyDescription propertyInfo : propertyInfos) {
messageProperties.add(message.getProperty(propertyInfo.name));
}
return messageProperties;
}
/**
* The iterator remove method is not supported.
* {@inheritDoc}
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
private final MessageBuffer messageBuffer = new MessageBuffer();
private final MonitorJobDescription jobDescription;
private final MessageSource messageSource;
private final EntryPointSpec entryPointSpec;
/**
* Construct a monitor job
* @param jobDescription this describes the job
* @param messageSource this is the message source that the job will process messages from
*/
public MonitorJob (MonitorJobDescription jobDescription, MessageSource messageSource, EntryPointSpec entryPointSpec) {
this.jobDescription = jobDescription;
this.entryPointSpec = entryPointSpec;
this.messageSource = messageSource;
//set the thread name to the job id
this.setName(jobDescription.getJobId());
//set up the message buffer so that it will receive messages and status notifications from the message source
messageSource.addMessageListener(messageBuffer);
messageSource.addStatusListener(messageBuffer);
}
/**
* this starts the job processing messages from the message buffer
* {@inheritDoc}
*/
@Override
public void run () {
try {
//this starts the CAL processing of the message buffer
Iterator<?> calResult =
(Iterator<?>) MonitorApp.getInstance().getCalServices().runFunction(entryPointSpec, new Object[] { messageBuffer });
//this retrieves the results from CAL - a Boolean value is returned for each
//message which indicates whether or not actions were performed for the message
while (calResult.hasNext()) {
logger.info (getName() + " result: " + calResult.next());
}
} catch (GemCompilationException ex) {
logger.warning(getName() + " CAL Compilation error: " + ex.getMessage());
} catch (CALExecutorException ex) {
logger.warning(getName() + " CAL Execution error: " + ex.getMessage());
}
}
/**
* Get the job description associated with the job
* @return Returns the jobDescription.
*/
MonitorJobDescription getJobDescription () {
return jobDescription;
}
/**
* Get the message source associated with the job
* @return the job's message source
*/
public MessageSource getMessageSource() {
return messageSource;
}
}