/* * Part of the CCNx Java Library. * * Copyright (C) 2008, 2009, 2011 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; import java.io.IOException; import java.util.EnumSet; import java.util.logging.Level; import org.ccnx.ccn.CCNHandle; import org.ccnx.ccn.impl.security.crypto.ContentKeys; import org.ccnx.ccn.impl.support.Log; import org.ccnx.ccn.profiles.SegmentationProfile; import org.ccnx.ccn.profiles.VersionMissingException; import org.ccnx.ccn.profiles.VersioningProfile; import org.ccnx.ccn.protocol.CCNTime; import org.ccnx.ccn.protocol.ContentName; import org.ccnx.ccn.protocol.ContentObject; import org.ccnx.ccn.protocol.PublisherPublicKeyDigest; /** * A CCNInputStream that reads and writes versioned streams. * Names are versioned using the VersioningProfile. If you * ask to open a name that is already versioned, it opens that * version for you. If you ask to open a name without a version, * it attempts to open the latest version of that name. If you * attempt to open a name with a segment marker on it as well, * it opens that version of that content at that segment. * * The only behavior we have to change from superclass is that * involved in getting the first segment -- header or regular segment. * We need to make an interest that gets the latest version, and * then fills in the version information on the name we * are working with, to make sure we continue to get blocks * from the same version (even if, say someone writes another * version on top of us). */ public class CCNVersionedInputStream extends CCNInputStream { /** * Set up an input stream to read segmented CCN content under a given versioned name. * Content is assumed to be unencrypted, or keys will be retrieved automatically via another * process. * Will use the default handle given by CCNHandle#getHandle(). * Note that this constructor does not currently retrieve any * data; data is not retrieved until read() is called. This will change in the future, and * this constructor will retrieve the first block. * * @param baseName Name to read from. If it ends with a version, will retrieve that * specific version. If not, will find the latest version available. If it ends with * both a version and a segment number, will start to read from that segment of that version. * @throws IOException Not currently thrown, will be thrown when constructors retrieve first block. */ public CCNVersionedInputStream(ContentName baseName) throws IOException { super(baseName); } /** * Set up an input stream to read segmented CCN content under a given versioned name. * Content is assumed to be unencrypted, or keys will be retrieved automatically via another * process. * Will use the default handle given by CCNHandle#getHandle(). * Note that this constructor does not currently retrieve any * data; data is not retrieved until read() is called. This will change in the future, and * this constructor will retrieve the first block. * * @param baseName Name to read from. If it ends with a version, will retrieve that * specific version. If not, will find the latest version available. If it ends with * both a version and a segment number, will start to read from that segment of that version. * @param handle The CCN handle to use for data retrieval. If null, the default handle * given by CCNHandle#getHandle() will be used. * @throws IOException Not currently thrown, will be thrown when constructors retrieve first block. */ public CCNVersionedInputStream(ContentName baseName, CCNHandle handle) throws IOException { super(baseName, handle); } /** * Set up an input stream to read segmented CCN content under a given versioned name. * Content is assumed to be unencrypted, or keys will be retrieved automatically via another * process. * Will use the default handle given by CCNHandle#getHandle(). * Note that this constructor does not currently retrieve any * data; data is not retrieved until read() is called. This will change in the future, and * this constructor will retrieve the first block. * * @param baseName Name to read from. If it ends with a version, will retrieve that * specific version. If not, will find the latest version available. If it ends with * both a version and a segment number, will start to read from that segment of that version. * @param publisher The key we require to have signed this content. If null, will accept any publisher * (subject to higher-level verification). * @param handle The CCN handle to use for data retrieval. If null, the default handle * given by CCNHandle#getHandle() will be used. * @throws IOException Not currently thrown, will be thrown when constructors retrieve first block. */ public CCNVersionedInputStream(ContentName baseName, PublisherPublicKeyDigest publisher, CCNHandle handle) throws IOException { super(baseName, publisher, handle); } /** * Set up an input stream to read segmented CCN content under a given versioned name. * Content is assumed to be unencrypted, or keys will be retrieved automatically via another * process. * Will use the default handle given by CCNHandle#getHandle(). * Note that this constructor does not currently retrieve any * data; data is not retrieved until read() is called. This will change in the future, and * this constructor will retrieve the first block. * * @param baseName Name to read from. If it ends with a version, will retrieve that * specific version. If not, will find the latest version available. If it ends with * both a version and a segment number, will start to read from that segment of that version. * @param startingSegmentNumber Alternative specification of starting segment number. If * null, will be SegmentationProfile#baseSegment(). * @param handle The CCN handle to use for data retrieval. If null, the default handle * given by CCNHandle#getHandle() will be used. * @throws IOException Not currently thrown, will be thrown when constructors retrieve first block. */ public CCNVersionedInputStream(ContentName baseName, Long startingSegmentNumber, CCNHandle handle) throws IOException { super(baseName, startingSegmentNumber, handle); } /** * Set up an input stream to read segmented CCN content under a given versioned name. * Content is assumed to be unencrypted, or keys will be retrieved automatically via another * process. * Will use the default handle given by CCNHandle#getHandle(). * Note that this constructor does not currently retrieve any * data; data is not retrieved until read() is called. This will change in the future, and * this constructor will retrieve the first block. * * @param baseName Name to read from. If it ends with a version, will retrieve that * specific version. If not, will find the latest version available. If it ends with * both a version and a segment number, will start to read from that segment of that version. * @param startingSegmentNumber Alternative specification of starting segment number. If * null, will beSegmentationProfile#baseSegment(). * @param publisher The key we require to have signed this content. If null, will accept any publisher * (subject to higher-level verification). * @param handle The CCN handle to use for data retrieval. If null, the default handle * given by CCNHandle#getHandle() will be used. * @throws IOException Not currently thrown, will be thrown when constructors retrieve first block. */ public CCNVersionedInputStream(ContentName baseName, Long startingSegmentNumber, PublisherPublicKeyDigest publisher, CCNHandle handle) throws IOException { super(baseName, startingSegmentNumber, publisher, handle); } /** * Set up an input stream to read segmented CCN content under a given versioned name. * Will use the default handle given by CCNHandle#getHandle(). * Note that this constructor does not currently retrieve any * data; data is not retrieved until read() is called. This will change in the future, and * this constructor will retrieve the first block. * * @param baseName Name to read from. If it ends with a version, will retrieve that * specific version. If not, will find the latest version available. If it ends with * both a version and a segment number, will start to read from that segment of that version. * @param startingSegmentNumber Alternative specification of starting segment number. If * null, will be SegmentationProfile#baseSegment(). * @param publisher The key we require to have signed this content. If null, will accept any publisher * (subject to higher-level verification). * @param keys The keys to use to decrypt this content. If null, assumes content unencrypted, or another * process will be used to retrieve the keys. * @param handle The CCN handle to use for data retrieval. If null, the default handle * given by CCNHandle#getHandle() will be used. * @throws IOException Not currently thrown, will be thrown when constructors retrieve first block. */ public CCNVersionedInputStream(ContentName baseName, Long startingSegmentNumber, PublisherPublicKeyDigest publisher, ContentKeys keys, CCNHandle handle) throws IOException { super(baseName, startingSegmentNumber, publisher, keys, handle); } /** * Set up an input stream to read segmented CCN content starting with a given * ContentObject that has already been retrieved. Content is assumed * to be unencrypted, or keys will be retrieved automatically via another * process. * @param startingSegment The first segment to read from. If this is not the * first segment of the stream, reading will begin from this point. * We assume that the signature on this segment was verified by our caller. * @param flags any stream flags that must be set to handle even this first block (otherwise * they can be set with setFlags prior to read). Can be null. * @param handle The CCN handle to use for data retrieval. If null, the default handle * given by CCNHandle#getHandle() will be used. * @throws IOException if startingSegment does not contain a valid segment ID */ public CCNVersionedInputStream(ContentObject startingSegment, EnumSet<FlagTypes> flags, CCNHandle handle) throws IOException { super(startingSegment, flags, handle); } /** * Set up an input stream to read segmented CCN content starting with a given * ContentObject that has already been retrieved. * @param startingSegment The first segment to read from. If this is not the * first segment of the stream, reading will begin from this point. * We assume that the signature on this segment was verified by our caller. * @param keys The keys to use to decrypt this content. Null if content unencrypted, or another * process will be used to retrieve the keys. * @param flags any stream flags that must be set to handle even this first block (otherwise * they can be set with setFlags prior to read). Can be null. * @param handle The CCN handle to use for data retrieval. If null, the default handle * given by CCNHandle#getHandle() will be used. * @throws IOException if startingSegment does not contain a valid segment ID */ public CCNVersionedInputStream(ContentObject startingSegment, ContentKeys keys, EnumSet<FlagTypes> flags, CCNHandle handle) throws IOException { super(startingSegment, keys, flags, handle); } /** * Implementation of getFirstSegment() that expects segments to be versioned. If a version * (and optionally a segment) is specified in the name, gets that specific version (and segment). Otherwise, * gets the latest version available. Uses VersioningProfile#getFirstBlockOfLatestVersion(ContentName, Long, PublisherPublicKeyDigest, long, org.ccnx.ccn.ContentVerifier, CCNHandle). * @throws IOException If no block found (NoMatchingContentFoundException}), or there is * an error retrieving the block. */ @Override public ContentObject getFirstSegment() throws IOException { if (VersioningProfile.hasTerminalVersion(_baseName)) { // Get exactly this version return super.getFirstSegment(); } Log.info(Log.FAC_IO, "getFirstSegment: getting latest version of {0}", _baseName); ContentObject result = VersioningProfile.getFirstBlockOfLatestVersion(_baseName, _startingSegmentNumber, _publisher, _timeout, _handle.defaultVerifier(), _handle); if (null != result){ if (Log.isLoggable(Log.FAC_IO, Level.INFO)) Log.info(Log.FAC_IO, "getFirstSegment: retrieved latest version object {0} type: {1}", result.name(), result.signedInfo().getTypeName()); _baseName = SegmentationProfile.segmentRoot(result.name()); } else { Log.info(Log.FAC_IO, "getFirstSegment: no segment available for latest version of {0}", _baseName); } return result; } /** * Determines whether a given content object is the first block of the versioned stream specified. */ @Override protected boolean isFirstSegment(ContentName desiredName, ContentObject potentialFirstSegment) { return VersioningProfile.isVersionedFirstSegment(desiredName, potentialFirstSegment, _startingSegmentNumber); } /** * Convenience method. * @return The version of this content as a CCNTime. * @throws VersionMissingException If we do not yet have a versioned content name. */ public CCNTime getVersionAsTimestamp() throws VersionMissingException { if (null == _baseName) throw new VersionMissingException("Have not yet retrieved content name!"); return VersioningProfile.getLastVersionAsTimestamp(_baseName); } }