dnet-core/dnet-information-service/src/main/java/eu/dnetlib/enabling/is/registry/RegistryBlackboardManagerIm...

258 lines
7.7 KiB
Java

package eu.dnetlib.enabling.is.registry;
import javax.xml.transform.dom.DOMResult;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Required;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
import eu.dnetlib.enabling.tools.OpaqueResource;
import eu.dnetlib.enabling.tools.StringOpaqueResource;
import eu.dnetlib.enabling.tools.blackboard.BlackboardMessage;
import eu.dnetlib.miscutils.datetime.DateUtils;
import eu.dnetlib.miscutils.jaxb.JaxbFactory;
/**
* Simple registry blackboard manager implementation.
*
* @author marko
*
*/
public class RegistryBlackboardManagerImpl implements RegistryBlackboardManager { // NOPMD
/**
* logger.
*/
private static final Log log = LogFactory.getLog(RegistryBlackboardManagerImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
/**
* timestamp padding.
*/
private static final String PADDING = "000";
/**
* milliseconds in a second.
*/
private static final int MILLIS = 1000;
/**
* IS Lookup
*/
private ISLookUpService isLookup;
/**
* the registry which is bound with this registry blackboard manager implementation.
*/
private ISRegistryService registryService;
/**
* blackboard message factory.
*/
private JaxbFactory<BlackboardMessage> messageFactory;
/**
* provides the current date. Testers can override.
*/
private MessageDater messageDater = new MessageDater();
/**
* Testers can override.
*
* @author marko
*
*/
public static class MessageDater {
public String getCurrentDate() {
return DateUtils.now_ISO8601();
}
public String getNumericStamp() {
return Long.toString(System.currentTimeMillis() / MILLIS) + "." + System.currentTimeMillis() % MILLIS + PADDING;
}
}
/**
* LAST_REQUEST or LAST_RESPONSE blackboard time stamp holders.
*
* @author marko
*
*/
public enum LastStamp {
/**
* LAST_REQUEST, used when the blackboard message flows from the client to the server.
*/
REQUEST,
/**
* LAST_RESPONSE, used when the blackboard message flows from the server to the client, signaling the completion/progress of the
* action..
*/
RESPONSE
}
/**
* {@inheritDoc}
*
* @see eu.dnetlib.enabling.is.registry.RegistryBlackboardManager#addMessage(java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public void addMessage(final String profId, final String messageId, final String message) { // NOPMD
try {
final BlackboardMessage bbm = messageFactory.parse(message);
bbm.setDate(messageDater.getCurrentDate()); // preserve compatibility.
if (bbm.getId() == null || !bbm.getId().equals(messageId)) { throw new IllegalArgumentException("invalid blackboard message id"); }
synchronized (this) {
final OpaqueResource serviceProfile = new StringOpaqueResource(isLookup.getResourceProfile(profId));
final Document doc = serviceProfile.asDom();
final Node bboard = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD", doc, XPathConstants.NODE);
// delete current element if exists
final Node messageElement = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[@id='" + messageId + "']", doc,
XPathConstants.NODE);
if (messageElement != null) {
bboard.removeChild(messageElement);
}
// append the serialized node to the blackboard node
messageFactory.serialize(bbm, new DOMResult(bboard));
updateLastStamps(doc, LastStamp.REQUEST, messageId);
registryService.updateProfile(profId, serviceProfile.asString(), serviceProfile.getResourceType());
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
/**
* Helper method which updates the LAST_* stamps in the blackboard header.
*
* @param doc
* profile DOM document
* @param stamp
* which stamp to modify
* @param messageId
* message id to point the stamp to
* @throws XPathExpressionException
* could happen
*/
protected void updateLastStamps(final Document doc, final LastStamp stamp, final String messageId) throws XPathExpressionException {
final Element lastRequest = (Element) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/LAST_" + stamp, doc, XPathConstants.NODE);
lastRequest.setTextContent(messageId);
lastRequest.setAttribute("date", messageDater.getNumericStamp());
}
/**
* {@inheritDoc}
*
* @see eu.dnetlib.enabling.is.registry.RegistryBlackboardManager#deleteMessage(java.lang.String, java.lang.String)
*/
@Override
public void deleteMessage(final String profId, final String messageId) {
try {
synchronized (this) {
final OpaqueResource serviceProfile = new StringOpaqueResource(isLookup.getResourceProfile(profId));
final Document doc = serviceProfile.asDom();
final Node message = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[@id='" + messageId + "']", doc,
XPathConstants.NODE);
message.getParentNode().removeChild(message);
registryService.updateProfile(profId, serviceProfile.asString(), serviceProfile.getResourceType());
}
log.debug("Deleted bb message " + messageId + " from profile " + profId);
} catch (Exception e) {
log.error("Error deleting bb message " + messageId + " from profile " + profId, e);
throw new IllegalStateException(e);
}
}
/**
* {@inheritDoc}
*
* @see eu.dnetlib.enabling.is.registry.RegistryBlackboardManager#replyMessage(java.lang.String, java.lang.String)
*/
@Override
public void replyMessage(final String profId, final String message) {
try {
final BlackboardMessage bbm = messageFactory.parse(message);
bbm.setDate(messageDater.getCurrentDate()); // preserve compatibility.
final String messageId = bbm.getId();
synchronized (this) {
final OpaqueResource serviceProfile = new StringOpaqueResource(isLookup.getResourceProfile(profId));
final Document doc = serviceProfile.asDom();
final Node messageElement = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[@id='" + messageId + "']", doc,
XPathConstants.NODE);
if (messageElement == null) { throw new IllegalArgumentException("no such blackboard message " + messageId + ". Unably to reply"); }
final Node bboard = messageElement.getParentNode();
bboard.removeChild(messageElement);
// append the serialized node to the blackboard node
messageFactory.serialize(bbm, new DOMResult(bboard));
updateLastStamps(doc, LastStamp.RESPONSE, messageId);
registryService.updateProfile(profId, serviceProfile.asString(), serviceProfile.getResourceType());
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
public ISRegistryService getRegistryService() {
return registryService;
}
@Required
public void setRegistryService(final ISRegistryService registryService) {
this.registryService = registryService;
}
public JaxbFactory<BlackboardMessage> getMessageFactory() {
return messageFactory;
}
@Required
public void setMessageFactory(final JaxbFactory<BlackboardMessage> messageFactory) {
this.messageFactory = messageFactory;
}
public MessageDater getMessageDater() {
return messageDater;
}
public void setMessageDater(final MessageDater messageDater) {
this.messageDater = messageDater;
}
public ISLookUpService getIsLookup() {
return isLookup;
}
@Required
public void setIsLookup(final ISLookUpService isLookup) {
this.isLookup = isLookup;
}
}