/*
* Part of the CCNx Java Library.
*
* Copyright (C) 2008-2012 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.impl.encoding;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.io.content.ContentDecodingException;
import org.ccnx.ccn.io.content.ContentEncodingException;
/**
* Implementation of generic XML encode/decode functionality for objects.
* Subclasses will be capable of being encoded to and decoded from both normal
* text-based XML and the ccnb compact binary encoding. (Though a subclass could
* mandate only one be used, or a caller can choose to specify. It is useful,
* for example, to use this approach to write classes that can be encoded &
* decoded to & from user-editable text XML only. See GenericXMLEncodable#toString()
* for an example.)
*
* This class handles most of the generic methods required by XMLEncodable, leaving
* only a very small number that subclasses need to actually implement.
*
* @see XMLEncodable
*/
public abstract class GenericXMLEncodable implements XMLEncodable {
/**
* All subclasses should provide a public no-argument constructor to be used
* by decoding methods.
*
* Don't provide a constructor that takes a byte[]. A class with no subclasses
* will decode fine, but its subclasses won't have their members
* set up to accept the data yet and so bad things will happen. (And even if you
* don't see why anyone would need to subclass your type, someone else might.)
* Clients wishing to decode content will call the no-argument constructor
* first, and then call decode(InputStream) or decode(ByteBuffer).
*/
protected GenericXMLEncodable() {}
public void decode(InputStream istream) throws ContentDecodingException {
decode(istream, null);
}
public void decode(InputStream istream, String codec) throws ContentDecodingException {
XMLDecoder decoder = XMLCodecFactory.getDecoder(codec);
decoder.beginDecoding(istream);
decode(decoder);
decoder.endDecoding();
}
public void decode(byte [] content) throws ContentDecodingException {
decode(content, (String)null);
}
public void decode(byte [] content, String codec) throws ContentDecodingException {
ByteArrayInputStream bais = new ByteArrayInputStream(content);
decode(bais, codec);
}
public void decode(byte [] content, XMLDecoder decoder) throws ContentDecodingException {
ByteArrayInputStream bais = new ByteArrayInputStream(content);
decoder.beginDecoding(bais);
decode(decoder);
decoder.endDecoding();
}
public void encode(OutputStream ostream) throws ContentEncodingException {
encode(ostream, null);
}
public void encode(OutputStream ostream, String codec) throws ContentEncodingException {
XMLEncoder encoder = XMLCodecFactory.getEncoder(codec);
encoder.beginEncoding(ostream);
encode(encoder);
encoder.endEncoding();
}
public byte [] encode() throws ContentEncodingException {
return encode((String)null);
}
public byte [] encode(String codec) throws ContentEncodingException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
encode(baos, codec);
return baos.toByteArray();
}
/**
* Default toString() implementation simply prints the text encoding of the
* object. This demonstrates how to force use of the text encoding.
*/
@Override
public String toString() {
byte[] encoded;
try {
encoded = encode(TextXMLCodec.codecName());
} catch (ContentEncodingException e) {
Log.info(Log.FAC_ENCODING, "GenericXMLEncodable.toString(): cannot encode: " + e.getMessage());
return new String();
}
return new String(encoded);
}
/*
* These are the methods that a subclass really does need to implement.
*/
public abstract void decode(XMLDecoder decoder) throws ContentDecodingException;
public abstract void encode(XMLEncoder encoder) throws ContentEncodingException;
public abstract long getElementLabel();
public abstract boolean validate();
}