package xdi2.messaging.container.contributor; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import xdi2.core.syntax.XDIAddress; import xdi2.core.util.iterators.DescendingIterator; import xdi2.core.util.iterators.IteratorCounter; import xdi2.core.util.iterators.ReadOnlyIterator; import xdi2.messaging.Message; import xdi2.messaging.MessageEnvelope; import xdi2.messaging.container.Prototype; import xdi2.messaging.container.exceptions.Xdi2MessagingException; import xdi2.messaging.operations.Operation; public class ContributorMap implements Iterable<Contributor>, Prototype<ContributorMap>, Serializable { private static final long serialVersionUID = 1645889897751813459L; private static final Logger log = LoggerFactory.getLogger(ContributorMap.class); private Map<XDIAddress, List<Contributor>> contributors; public ContributorMap(ContributorMap contributorMap) { this.contributors = new LinkedHashMap<XDIAddress, List<Contributor>> (contributorMap.contributors); } public ContributorMap(Map<XDIAddress, List<Contributor>> contributors) { this.contributors = new LinkedHashMap<XDIAddress, List<Contributor>> (contributors); } public ContributorMap() { this.contributors = new LinkedHashMap<XDIAddress, List<Contributor>> (); } public void addContributors(ContributorMap contributorMap) { this.contributors.putAll(contributorMap.contributors); } public void addContributors(Map<XDIAddress, List<Contributor>> contributors) { this.contributors.putAll(contributors); } public void addContributor(XDIAddress contextNodeXDIAddress, Contributor contributor) { if (log.isDebugEnabled()) log.debug("Adding contributor " + contributor.getClass().getSimpleName() + " under " + contextNodeXDIAddress); List<Contributor> contributors = this.contributors.get(contextNodeXDIAddress); if (contributors == null) { contributors = new ArrayList<Contributor> (); this.contributors.put(contextNodeXDIAddress, contributors); } contributors.add(contributor); } public void addContributor(Contributor contributor) { String[] contributorXDIAddresses = contributor.getContributorMount().contributorXDIAddresses(); for (String contributorXDIAddress : contributorXDIAddresses) { this.addContributor(XDIAddress.create(contributorXDIAddress), contributor); } } @SuppressWarnings("unchecked") public <T extends Contributor> T getContributor(Class<T> clazz) { for (Contributor contributor : this) { if (clazz.isAssignableFrom(contributor.getClass())) return (T) contributor; } return null; } public void removeContributor(XDIAddress contributorXDIAddress, Contributor contributor) { if (log.isDebugEnabled()) log.debug("Removing contributor " + contributor.getClass().getSimpleName() + " from " + contributorXDIAddress); List<Contributor> contributors = this.contributors.get(contributorXDIAddress); if (contributors == null) return; contributors.remove(contributor); if (contributors.isEmpty()) { this.contributors.remove(contributorXDIAddress); } } public void removeContributor(Contributor contributor) { for (Iterator<Map.Entry<XDIAddress, List<Contributor>>> entries = this.contributors.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<XDIAddress, List<Contributor>> entry = entries.next(); if (entry.getValue().contains(contributor)) entry.getValue().remove(contributor); if (entry.getValue().isEmpty()) entries.remove(); } } public boolean isEmpty() { return this.contributors.isEmpty(); } public int size() { return (int) new IteratorCounter(this.iterator()).count(); } public Set<Entry<XDIAddress, List<Contributor>>> entrySet() { return this.contributors.entrySet(); } @Override public ReadOnlyIterator<Contributor> iterator() { return new DescendingIterator<List<Contributor>, Contributor> (this.contributors.values().iterator()) { @Override public Iterator<Contributor> descend(List<Contributor> item) { return item.iterator(); } }; } public String stringList() { StringBuffer buffer = new StringBuffer(); for (Contributor contributor : this) { if (buffer.length() > 0) buffer.append(","); buffer.append(contributor.getClass().getSimpleName()); } return buffer.toString(); } public void clearDisabledForOperation(Operation operation) { for (Contributor contributor : this.iterator()) { contributor.clearDisabledForOperation(operation); } } public void clearDisabledForMessage(Message message) { for (Contributor contributor : this.iterator()) { contributor.clearDisabledForMessage(message); } } public void clearDisabledForMessageEnvelope(MessageEnvelope messageEnvelope) { for (Contributor contributor : this.iterator()) { contributor.clearDisabledForMessageEnvelope(messageEnvelope); } } /* * Prototype */ @SuppressWarnings("unchecked") @Override public ContributorMap instanceFor(PrototypingContext prototypingContext) throws Xdi2MessagingException { // create new contributor map ContributorMap contributorMap = new ContributorMap(); // add contributors for (Map.Entry<XDIAddress, List<Contributor>> entry : this.contributors.entrySet()) { XDIAddress contributorXDIAddress = entry.getKey(); List<Contributor> contributors = entry.getValue(); for (Contributor contributor : contributors) { if (! (contributor instanceof Prototype<?>)) { throw new Xdi2MessagingException("Cannot use contributor " + contributor.getClass().getSimpleName() + " as prototype.", null, null); } try { Prototype<? extends Contributor> contributorPrototype = (Prototype<? extends Contributor>) contributor; Contributor prototypedContributor = prototypingContext.instanceFor(contributorPrototype); contributorMap.addContributor(contributorXDIAddress, prototypedContributor); } catch (Xdi2MessagingException ex) { throw new Xdi2MessagingException("Cannot instantiate interceptor for prototype " + contributor.getClass().getSimpleName() + ": " + ex.getMessage(), ex, null); } } } // done return contributorMap; } /* * Helper classes */ public static class ContributorFound { private XDIAddress contributorXDIAddress; private Contributor contributor; public ContributorFound(XDIAddress contributorXDIAddress, Contributor contributor) { this.contributorXDIAddress = contributorXDIAddress; this.contributor = contributor; } public XDIAddress getContributorXDIAddress() { return this.contributorXDIAddress; } public Contributor getContributor() { return this.contributor; } @Override public String toString() { return this.contributorXDIAddress.toString() + ":" + this.contributor.getClass().getSimpleName(); } } }