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); } }); } } }