package water;
import java.io.*;
/**
* H2O uses Iced classes as the primary means of moving Java Objects around
* the cluster.
* <p>
* Auto-serializer base-class using a delegator pattern (the faster option is
* to byte-code gen directly in all Iced classes, but this requires all Iced
* classes go through a ClassLoader).
* <p>
* Iced is a marker class, and {@link Freezable} is the companion marker
* interface. Marked classes have 2-byte integer type associated with them,
* and an auto-genned delegate class created to actually do byte-stream and
* JSON serialization and deserialization. Byte-stream serialization is
* extremely dense (includes various compressions), and typically memory-bandwidth
* bound to generate.
* <p>
* During startup time the Weaver creates a parallel set of classes called
* (classname)$Icer. These provide bytestream and JSON serializers
* and deserializers which get called by AutoBuffer.write* and AutoBuffer.read*.
* <p>
* To debug the automagic serialization code create a transient field in your Iced
* class called DEBUG_WEAVER. The generated source code will get written to STDOUT:
* <p>
* {@code
* transient int DEBUG_WEAVER = 1;
* }
* @see Freezable
* @see water.Weaver
* @see water.AutoBuffer
*/
abstract public class Iced<D extends Iced> implements Freezable<D>, Externalizable {
// The serialization flavor / delegate. Lazily set on first use.
transient private volatile short _ice_id = 0;
@Override
public byte [] asBytes(){
return write(new AutoBuffer()).buf();
}
@Override
public D reloadFromBytes(byte [] ary){
return read(new AutoBuffer(ary));
}
// Return the icer for this instance+class. Will set on 1st use.
private Icer<D> icer() {
int id = _ice_id;
int tyid;
if(id != 0) assert id == (tyid =TypeMap.onIce(this)):"incorrectly cashed id " + id + ", typemap has " + tyid + ", type = " + getClass().getName();
return TypeMap.getIcer(id!=0 ? id : (_ice_id=(short)TypeMap.onIce(this)),this);
}
/** Standard "write thyself into the AutoBuffer" call, using the fast Iced
* protocol. Real work is in the delegate {@link Icer} classes.
* @return Returns the original {@link AutoBuffer} for flow-coding. */
@Override final public AutoBuffer write (AutoBuffer ab) { return icer().write (ab,(D)this); }
/** Standard "write thyself into the AutoBuffer" call, using JSON. Real work
* is in the delegate {@link Icer} classes.
* @return Returns the original {@link AutoBuffer} for flow-coding. */
@Override public AutoBuffer writeJSON(AutoBuffer ab) { return icer().writeJSON(ab,(D)this); }
/** Standard "read thyself from the AutoBuffer" call, using the fast Iced protocol. Real work
* is in the delegate {@link Icer} classes.
* @return Returns the original {@link AutoBuffer} for flow-coding. */
@Override final public D read (AutoBuffer ab) { return icer().read (ab,(D)this); }
/** Standard "read thyself from the AutoBuffer" call, using JSON. Real work
* is in the delegate {@link Icer} classes.
* @return Returns the original {@link AutoBuffer} for flow-coding. */
@Override final public D readJSON(AutoBuffer ab) { return icer().readJSON(ab,(D)this); }
/** Helper for folks that want a JSON String for this object. */
final public String toJsonString() {
return new String(this.writeJSON(new AutoBuffer()).buf());
}
/** Returns a small dense integer, which is cluster-wide unique per-class.
* Useful as an array index.
* @return Small integer, unique per-type */
@Override final public int frozenType() { return icer().frozenType(); }
/** Clone, without the annoying exception */
@Override public final D clone() {
try { return (D)super.clone(); }
catch( CloneNotSupportedException e ) { throw water.util.Log.throwErr(e); }
}
/** Copy over cloned instance 'src' over 'this', field by field. */
protected void copyOver( D src ) { icer().copyOver((D)this,src); }
///////////////////////////////////
// TODO: make all of these protected!
///////////////////////////////////
/** Implementation of the {@link Iced} serialization protocol, only called by
* auto-genned code. Not intended to be called by user code. Override only
* for custom Iced serializers. */
//noninspection UnusedDeclaration
// @Override public AutoBuffer write_impl( AutoBuffer ab ) { return ab; }
/** Implementation of the {@link Iced} serialization protocol, only called by
* auto-genned code. Not intended to be called by user code. Override only
* for custom Iced serializers. */
//noninspection UnusedDeclaration
// @Override public D read_impl( AutoBuffer ab ) { return (D)this; }
/** Implementation of the {@link Iced} serialization protocol, only called by
* auto-genned code. Not intended to be called by user code. Override only
* for custom Iced serializers. */
//noninspection UnusedDeclaration
// public AutoBuffer writeJSON_impl( AutoBuffer ab ) { return ab; }
/** Implementation of the {@link Iced} serialization protocol, only called by
* auto-genned code. Not intended to be called by user code. Override only
* for custom Iced serializers. */
//noninspection UnusedDeclaration
// @Override public D readJSON_impl( AutoBuffer ab ) { return (D)this; }
// Java serializers use H2Os Icing
@Override public void readExternal( ObjectInput ois ) throws IOException, ClassNotFoundException {
int x = ois.readInt();
byte[] buf = MemoryManager.malloc1(x);
ois.readFully(buf);
read(new AutoBuffer(buf));
}
@Override public void writeExternal( ObjectOutput oos ) throws IOException {
byte[] buf = write(new AutoBuffer()).buf();
oos.writeInt(buf.length);
oos.write(buf);
}
}