package xdi2.messaging;
import java.io.Serializable;
import java.util.Iterator;
import xdi2.core.ContextNode;
import xdi2.core.Graph;
import xdi2.core.features.nodetypes.XdiEntity;
import xdi2.core.features.nodetypes.XdiEntityCollection;
import xdi2.core.features.nodetypes.XdiEntityInstanceOrdered;
import xdi2.core.features.nodetypes.XdiEntityInstanceUnordered;
import xdi2.core.features.nodetypes.XdiInnerRoot;
import xdi2.core.syntax.XDIAddress;
import xdi2.core.util.XDIAddressUtil;
import xdi2.core.util.iterators.DescendingIterator;
import xdi2.core.util.iterators.IteratorCounter;
import xdi2.core.util.iterators.IteratorListMaker;
import xdi2.core.util.iterators.MappingIterator;
import xdi2.core.util.iterators.NotNullIterator;
import xdi2.core.util.iterators.ReadOnlyIterator;
import xdi2.messaging.constants.XDIMessagingConstants;
import xdi2.messaging.operations.Operation;
/**
* An XDI message collection, represented as a context node.
*
* @author markus
*/
public final class MessageCollection implements Serializable, Comparable<MessageCollection> {
private static final long serialVersionUID = -7493408194946194153L;
private MessageEnvelope messageEnvelope;
private XdiEntityCollection xdiEntityCollection;
protected MessageCollection(MessageEnvelope messageEnvelope, XdiEntityCollection xdiEntityCollection) {
if (messageEnvelope == null || xdiEntityCollection == null) throw new NullPointerException();
this.messageEnvelope = messageEnvelope;
this.xdiEntityCollection = xdiEntityCollection;
}
/*
* Static methods
*/
/**
* Checks if an XDI entity class is a valid XDI message collection.
* @param xdiEntityCollection The XDI entity class to check.
* @return True if the XDI entity class is a valid XDI message collection.
*/
public static boolean isValid(XdiEntityCollection xdiEntityCollection) {
if (! xdiEntityCollection.getContextNode().getXDIArc().equals(XdiEntityCollection.createXDIArc(XDIMessagingConstants.XDI_ARC_MSG))) return false;
if (XDIAddressUtil.extractXDIAddress(xdiEntityCollection.getContextNode().getXDIAddress(), XdiInnerRoot.class, false, false, true, false, false) != null) return false;
return true;
}
/**
* Factory method that creates an XDI message collection bound to a given XDI entity collection.
* @param messageEnvelope The XDI message envelope to which this XDI message collection belongs.
* @param xdiEntityCollection The XDI entity class that is an XDI message collection.
* @return The XDI message collection.
*/
public static MessageCollection fromMessageEnvelopeAndXdiEntityCollection(MessageEnvelope messageEnvelope, XdiEntityCollection xdiEntityCollection) {
if (! isValid(xdiEntityCollection)) return null;
return new MessageCollection(messageEnvelope, xdiEntityCollection);
}
/**
* Factory method that creates an XDI message collection bound to a given XDI entity collection.
* @param xdiEntityCollection The XDI entity collection that is an XDI message collection.
* @return The XDI message collection.
*/
public static MessageCollection fromXdiEntityCollection(XdiEntityCollection xdiEntityCollection) {
Graph graph = xdiEntityCollection.getGraph();
MessageEnvelope messageEnvelope = graph == null ? null : MessageEnvelope.fromGraph(graph);
if (messageEnvelope == null) return null;
return fromMessageEnvelopeAndXdiEntityCollection(messageEnvelope, xdiEntityCollection);
}
/**
* Factory method that creates an XDI message collection bound to a given context node.
* @param contextNode The context node that is an XDI message collection.
* @return The XDI message collection.
*/
public static MessageCollection fromContextNode(ContextNode contextNode) {
return MessageCollection.fromXdiEntityCollection(XdiEntityCollection.fromContextNode(contextNode));
}
/*
* Instance methods
*/
/**
* Returns the XDI message envelope to which this XDI message collection belongs.
* @return An XDI message envelope.
*/
public MessageEnvelope getMessageEnvelope() {
return this.messageEnvelope;
}
/**
* Returns the underlying XDI entity class to which this XDI message collection is bound.
* @return An XDI entity class that represents the XDI message collection.
*/
public XdiEntityCollection getXdiEntityCollection() {
return this.xdiEntityCollection;
}
/**
* Returns the underlying context node to which this XDI message collection is bound.
* @return A context node that represents the XDI message collection.
*/
public ContextNode getContextNode() {
return this.getXdiEntityCollection().getContextNode();
}
/**
* Returns the sender of the message collection.
* @return The sender of the message collection.
*/
public ContextNode getSender() {
return this.getContextNode().getContextNode();
}
/**
* Returns the sender address of the message collection.
* @return The sender adddress of the message collection.
*/
public XDIAddress getSenderXDIAddress() {
return this.getSender().getXDIAddress();
}
/**
* Creates a new XDI message in this XDI message collection.
* @return The newly created XDI message.
*/
public Message createMessage() {
XdiEntityInstanceUnordered xdiEntityMember = this.xdiEntityCollection.setXdiInstanceUnordered(true, false);
xdiEntityMember.getXdiEntitySingleton(XDIMessagingConstants.XDI_ARC_DO, true);
return new Message(this, xdiEntityMember);
}
/**
* Creates a new XDI message in this XDI message collection.
* @param index Index in an ordered collection.
* @return The newly created XDI message.
*/
public Message createMessage(long index) {
XdiEntityInstanceOrdered xdiEntityMember = this.xdiEntityCollection.setXdiInstanceOrdered(index);
xdiEntityMember.getXdiEntitySingleton(XDIMessagingConstants.XDI_ARC_DO, true);
return new Message(this, xdiEntityMember);
}
/**
* Returns all messages in this message collection.
* @return All messages contained in the collection.
*/
public ReadOnlyIterator<Message> getMessages() {
return new MappingXdiEntityMessageIterator(this, this.getXdiEntityCollection().getXdiInstancesDeref());
}
/**
* Deletes all messages from this message collection.
*/
public void deleteMessages() {
for (Message message : new IteratorListMaker<Message> (this.getMessages()).list()) {
message.getContextNode().delIncomingRelations();
message.getContextNode().delete();
}
}
/**
* Returns all operations in this message collection.
* @return All operations contained in the collection.
*/
public ReadOnlyIterator<Operation> getOperations() {
return new DescendingIterator<Message, Operation> (this.getMessages()) {
@Override
public Iterator<Operation> descend(Message message) {
return message.getOperations();
}
};
}
/**
* Returns the number of messages in the message collection.
*/
public long getMessageCount() {
return new IteratorCounter(this.getMessages()).count();
}
/**
* Returns the number of operations in all messages of the message envelope.
*/
public long getOperationCount() {
return new IteratorCounter(this.getOperations()).count();
}
/*
* Object methods
*/
@Override
public String toString() {
return this.getContextNode().toString();
}
@Override
public boolean equals(Object object) {
if (object == null || ! (object instanceof MessageCollection)) return false;
if (object == this) return true;
MessageCollection other = (MessageCollection) object;
return this.getContextNode().equals(other.getContextNode());
}
@Override
public int hashCode() {
int hashCode = 1;
hashCode = (hashCode * 31) + this.getContextNode().hashCode();
return hashCode;
}
@Override
public int compareTo(MessageCollection other) {
if (other == this || other == null) return(0);
return this.getContextNode().compareTo(other.getContextNode());
}
/*
* Helper classes
*/
public static class MappingXdiEntityMessageIterator extends NotNullIterator<Message> {
public MappingXdiEntityMessageIterator(final MessageCollection messageCollection, Iterator<? extends XdiEntity> xdiEntities) {
super(new MappingIterator<XdiEntity, Message> (xdiEntities) {
@Override
public Message map(XdiEntity xdiEntity) {
return Message.fromMessageCollectionAndXdiEntity(messageCollection, xdiEntity);
}
});
}
}
}