/*
* Part of the CCNx Java Library.
*
* Copyright (C) 2008, 2009 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.protocol;
import java.io.Serializable;
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.content.ContentDecodingException;
import org.ccnx.ccn.io.content.ContentEncodingException;
/**
* We wish to securely refer to a key. We do that by specifying a ContentName
* where it can be retrieved, and (optionally) information about who must
* have signed it for us to consider it valid. This can be a direct specification
* of who must have signed it -- effectively saying that a specific key, corresponding
* to an individual, most have signed the target for us to find it acceptable.
* More powerfully, this can incorporate a level of indirection -- we can say that
* an acceptable key is one signed by anyone whose own key was signed by the
* specified publisher, effectively allowing for a form of certification.
*
* For now we allow a variety of specification of publisher, including some using
* digital certificates. These may be unnecessary and elided in the future.
*/
public class KeyName extends GenericXMLEncodable implements XMLEncodable, Serializable {
private static final long serialVersionUID = -4486998061731593809L;
protected ContentName _name;
protected PublisherID _publisher;
/**
* Build a KeyName
* @param name the name at which we can find the key
* @param publisher the publisher we require to have signed the key, or to have signed
* the key that signed the key
*/
public KeyName(ContentName name,
PublisherID publisher) {
_name = name;
_publisher = publisher;
}
public KeyName(ContentName name, PublisherPublicKeyDigest publisher) {
_name = name;
_publisher = new PublisherID(publisher);
}
/**
* Build a KeyName
* @param name the name at which we can find the key
*/
public KeyName(ContentName name) {
this(name, (PublisherID)null);
}
/**
* For use by decoders
*/
public KeyName() {}
/**
* Get the name
* @return the name
*/
public ContentName name() { return _name; }
/**
* Get the required publisher information, if specified.
* @return the publisher specification
*/
public PublisherID publisher() { return _publisher; }
/**
* Thought about encoding and decoding as flat -- no wrapping
* declaration. But then couldn't use these solo.
*/
@Override
public void decode(XMLDecoder decoder) throws ContentDecodingException {
decoder.readStartElement(getElementLabel());
_name = new ContentName();
_name.decode(decoder);
if (PublisherID.peek(decoder)) {
_publisher = new PublisherID();
_publisher.decode(decoder);
}
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());
name().encode(encoder);
if (null != publisher())
publisher().encode(encoder);
encoder.writeEndElement();
}
@Override
public long getElementLabel() { return CCNProtocolDTags.KeyName; }
@Override
public boolean validate() {
// DKS -- do we do recursive validation?
// null signedInfo ok
return (null != name());
}
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + ((_publisher == null) ? 0 : _publisher.hashCode());
result = PRIME * result + ((_name == null) ? 0 : _name.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 KeyName other = (KeyName) obj;
if (_publisher == null) {
if (other._publisher != null)
return false;
} else if (!_publisher.equals(other._publisher))
return false;
if (_name == null) {
if (other._name != null)
return false;
} else if (!_name.equals(other._name))
return false;
return true;
}
@Override
public String toString() {
return ((null != name()) ? name() : "") + ((null != publisher()) ? " " + publisher() : "");
}
}