/* * Part of the CCNx Java Library. * * Copyright (C) 2008, 2009, 2013 Palo Alto Research Center, Inc. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. You should have received * a copy of the GNU Lesser General Public License along with this library; * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, * Fifth Floor, Boston, MA 02110-1301 USA. */ package org.ccnx.ccn.io.content; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import org.ccnx.ccn.CCNHandle; import org.ccnx.ccn.impl.CCNFlowControl; import org.ccnx.ccn.impl.CCNFlowControl.SaveType; import org.ccnx.ccn.impl.encoding.CCNProtocolDTags; import org.ccnx.ccn.impl.encoding.GenericXMLEncodable; import org.ccnx.ccn.impl.encoding.XMLDecoder; import org.ccnx.ccn.impl.encoding.XMLEncodable; import org.ccnx.ccn.impl.encoding.XMLEncoder; import org.ccnx.ccn.io.ErrorStateException; import org.ccnx.ccn.protocol.ContentName; import org.ccnx.ccn.protocol.ContentObject; import org.ccnx.ccn.protocol.KeyLocator; import org.ccnx.ccn.protocol.PublisherPublicKeyDigest; /** * A representation of a collection of CCN objects, represented as a list of Link s. * See Link for a discussion of what such links can refer to and their security. * A Collection is the easiest way in CCN of representing extensional containment -- a fixed * list of items that form a group, where it is possible to say that an item is either * in or out of the group. Containment in CCN can also be represented intentionally -- * by looking at the set of children a given name currently has. In that latter case, * it is impossible to say in general whether something is not in the set, as there * might exist a child with that name, but it is not accessible to your network at * the moment. * * By tailoring the meaning of and labels attached to the Links in a Collection, * one can generate special-purpose Collection subclasses with particular semantics, * useful in particular applications. See ACL and the Name Enumeration protocol * for examples of this. */ public class Collection extends GenericXMLEncodable implements XMLEncodable, Iterable<Link>, Cloneable { /** * A CCNNetworkObject wrapper around Collection, used for easily saving and retrieving * versioned Collections to CCN. A typical pattern for using network objects to save * objects that happen to be encodable or serializable is to incorporate such a static * member wrapper class subclassing CCNEncodableObject, CCNSerializableObject, or * CCNNetworkObject itself inside the main class definition. */ public static class CollectionObject extends CCNEncodableObject<Collection> { public CollectionObject(ContentName name, Collection data, SaveType saveType, CCNHandle handle) throws IOException { super(Collection.class, true, name, data,saveType, handle); } public CollectionObject(ContentName name, java.util.Collection<Link> contents, SaveType saveType, CCNHandle handle) throws IOException { this(name, new Collection(contents), saveType, handle); } public CollectionObject(ContentName name, Link [] contents, SaveType saveType, CCNHandle handle) throws IOException { this(name, new Collection(contents),saveType, handle); } public CollectionObject(ContentName name, Collection data, SaveType saveType, PublisherPublicKeyDigest publisher, KeyLocator keyLocator, CCNHandle handle) throws IOException { super(Collection.class, true, name, data, saveType, publisher, keyLocator, handle); } public CollectionObject(ContentName name, java.util.Collection<Link> contents, SaveType saveType, PublisherPublicKeyDigest publisher, KeyLocator keyLocator, CCNHandle handle) throws IOException { this(name, new Collection(contents), saveType, publisher, keyLocator, handle); } public CollectionObject(ContentName name, Link [] contents, SaveType saveType, PublisherPublicKeyDigest publisher, KeyLocator keyLocator, CCNHandle handle) throws IOException { this(name, new Collection(contents), saveType, publisher, keyLocator, handle); } public CollectionObject(ContentName name, PublisherPublicKeyDigest publisher, CCNHandle handle) throws ContentDecodingException, IOException { super(Collection.class, true, name, publisher, handle); } public CollectionObject(ContentObject firstBlock, CCNHandle handle) throws ContentDecodingException, IOException { super(Collection.class, true, firstBlock, handle); } public CollectionObject(ContentName name, CCNHandle handle) throws ContentDecodingException, IOException { super(Collection.class, true, name, (PublisherPublicKeyDigest)null, handle); } public CollectionObject(ContentName name, Collection data, PublisherPublicKeyDigest publisher, KeyLocator keyLocator, CCNFlowControl flowControl) throws IOException { super(Collection.class, true, name, data, publisher, keyLocator, flowControl); } public CollectionObject(ContentName name, PublisherPublicKeyDigest publisher, CCNFlowControl flowControl) throws ContentDecodingException, IOException { super(Collection.class, true, name, publisher, flowControl); } public CollectionObject(ContentObject firstBlock, CCNFlowControl flowControl) throws ContentDecodingException, IOException { super(Collection.class, true, firstBlock, flowControl); } public Collection collection() throws ContentNotReadyException, ContentGoneException, ErrorStateException { return data(); } public LinkedList<Link> contents() throws ContentNotReadyException, ContentGoneException, ErrorStateException { if (null == data()) return null; return data().contents(); } } protected LinkedList<Link> _contents = new LinkedList<Link>(); public Collection() { } @SuppressWarnings("unchecked") public Collection clone() { try { Collection c = (Collection)super.clone(); c._contents = (LinkedList<Link>)_contents.clone(); return c; } catch (CloneNotSupportedException e) { throw new AssertionError(e); } } public Collection(java.util.Collection<Link> contents) { _contents.addAll(contents); // should we clone each? } public Collection(Link [] contents) { if (contents != null) { for (int i=0; i < contents.length; ++i) { _contents.add(contents[i]); } } } /** * Make a Collection containing Links which only specify names. * @param nameContents The list of names to link to. */ public Collection(ArrayList<ContentName> nameContents) { if (null != nameContents) { for (ContentName name : nameContents) { _contents.add(new Link(name)); } } } /** * Make a Collection containing Links which only specify names and a single label. * @param nameContents The list of names to link to. */ public Collection(String label, ArrayList<ContentName> nameContents) { if (null != nameContents) { for (ContentName name : nameContents) { _contents.add(new Link(name, label, null)); } } } public LinkedList<Link> contents() { return _contents; } public Link get(int i) { return contents().get(i); } /** * Return the first Link with matching label, if any. * @param label * @return */ public Link get(String label) { if (null == label) return null; for (Link link : _contents) { if (label.equals(link.targetLabel())) { return link; } } return null; } public void add(Link content) { _contents.add(content); } public void add(ArrayList<Link> contents) { _contents.addAll(contents); } public void add(String label, ArrayList<ContentName> nameContents) { if (null != nameContents) { for (ContentName name : nameContents) { _contents.add(new Link(name, label, null)); } } } public void add(String label, ContentName target) { _contents.add(new Link(target, label, null)); } public Link remove(int i) { return _contents.remove(i); } public boolean remove(Link content) { return _contents.remove(content); } public void removeAll() { _contents.clear(); } public int size() { return _contents.size(); } /** * Find all the elements in this Collection that match target on any of the * parameters it has set, and return them. */ public ArrayList<Link> find(Link target) { ArrayList<Link> results = new ArrayList<Link>(); for (Link link : _contents) { if (target.approximates(link)) { results.add(link); } } return results; } public ArrayList<Link> find(ContentName targetName) { return find(new Link(targetName)); } public ArrayList<Link> find(String targetLabel) { return find(new Link(null, targetLabel, null)); } @Override public void decode(XMLDecoder decoder) throws ContentDecodingException { _contents.clear(); decoder.readStartElement(getElementLabel()); Link link = null; while (decoder.peekStartElement(CCNProtocolDTags.Link)) { link = new Link(); link.decode(decoder); add(link); } decoder.readEndElement(); } @Override public void encode(XMLEncoder encoder) throws ContentEncodingException { if (!validate()) { throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing."); } encoder.writeStartElement(getElementLabel()); Iterator<Link> linkIt = contents().iterator(); while (linkIt.hasNext()) { Link link = linkIt.next(); link.encode(encoder); } encoder.writeEndElement(); } @Override public boolean validate() { return (null != contents()); } @Override public long getElementLabel() { return CCNProtocolDTags.Collection; } @Override public int hashCode() { final int PRIME = 31; int result = 1; result = PRIME * result + ((_contents == null) ? 0 : _contents.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final Collection other = (Collection) obj; if (_contents == null) { if (other._contents != null) return false; } else if (!_contents.equals(other._contents)) return false; return true; } /** * More concise toString. */ public String toString() { StringBuffer sbuf = new StringBuffer(getElementLabel() + ":\n"); for (Link link : _contents) { sbuf.append(" " + link.toString() + "\n"); } sbuf.append("\n"); return sbuf.toString(); } /* (non-Javadoc) * @see java.lang.Iterable#iterator() */ public Iterator<Link> iterator() { return _contents.iterator(); } }