divconq.struct.CompositeStruct.java Source code

Java tutorial

Introduction

Here is the source code for divconq.struct.CompositeStruct.java

Source

/* ************************************************************************
#
#  DivConq
#
#  http://divconq.com/
#
#  Copyright:
#    Copyright 2014 eTimeline, LLC. All rights reserved.
#
#  License:
#    See the license.txt file in the project's top-level directory for details.
#
#  Authors:
#    * Andy White
#
************************************************************************ */
package divconq.struct;

import io.netty.buffer.ByteBuf;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

import divconq.hub.Hub;
import divconq.lang.Memory;
import divconq.lang.chars.Special;
import divconq.lang.op.FuncResult;
import divconq.schema.DataType;
import divconq.script.StackEntry;
import divconq.struct.builder.BuilderStateException;
import divconq.struct.builder.ICompositeOutput;
import divconq.struct.builder.JsonStreamBuilder;
import divconq.struct.builder.JsonMemoryBuilder;
import divconq.struct.serial.CompositeToBufferBuilder;
import divconq.xml.XElement;

/**
 * DivConq uses a specialized type system that provides type consistency across services 
 * (including web services), database fields and stored procedures, as well as scripting.
 * 
 * All scalars (including primitives) and composites (collections) are wrapped by some
 * subclass of Struct.  All composites are wrapped by a subclass of this class.  See
 * ListStruct and RecordStruct.
 * 
 *  TODO link to blog entries.
 * 
 * @author Andy
 *
 */
abstract public class CompositeStruct extends Struct implements ICompositeOutput {
    public CompositeStruct() {
    }

    public CompositeStruct(DataType type) {
        super(type);
    }

    /**
     * A way to select a child or sub child structure similar to XPath but lightweight.
     * Can select composites and scalars.  Use a . or / delimiter.
     * 
     * For example: "Toys.3.Name" called on "Person" Record means return the (Struct) name of the 
     * 4th toy in this person's Toys list.
     * 
     * Cannot go up levels, or back to root.  Do not start with a dot or slash as in ".People".
     * 
     * @param path string holding the path to select
     * @return selected structure if any, otherwise null
     */
    public FuncResult<Struct> select(String path) {
        FuncResult<Struct> log = new FuncResult<Struct>();
        log.setResult(this.select(PathPart.parse(log, path)));
        return log;
    }

    /**
     * A way to select a child or sub child structure similar to XPath but lightweight.
     * Can select composites and scalars.  Use a . or / delimiter.
     * 
     * For example: "Toys.3.Name" called on "Person" Record means return the (Struct) name of the 
     * 4th toy in this person's Toys list.
     * 
     * Cannot go up levels, or back to root.  Do not start with a dot or slash as in ".People".
     * 
     * @param path parts of the path holding a list index or a field name
     * @return selected structure if any, otherwise null
     */
    abstract public Struct select(PathPart... path);

    /**
     * Does this collection have any items or fields
     * 
     * @return true if no items or fields
     */
    abstract public boolean isEmpty();

    /**
     * Remove all child fields or items.
     */
    abstract public void clear();

    @Override
    public String toString() {
        try {
            JsonMemoryBuilder rb = new JsonMemoryBuilder();
            this.toBuilder(rb);
            return rb.getMemory().toString();
        } catch (Exception x) {
            //
        }

        return null;
    }

    // TODO there may be more efficient ways to do this, just a quick way for now
    @Override
    public boolean equals(Object obj) {
        if ((obj instanceof CompositeStruct) && this.toString().equals(((CompositeStruct) obj).toString()))
            return true;

        return super.equals(obj);
    }

    public String toPrettyString() {
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            PrintStream ps = new PrintStream(os);
            JsonStreamBuilder rb = new JsonStreamBuilder(ps, true);
            this.toBuilder(rb);
            return os.toString("UTF-8");
        } catch (Exception x) {
            //
        }

        return null;
    }

    @Override
    public boolean isNull() {
        return false;
    }

    /**
     * Convert the structure to Json and return in Memory (think StringBuilder in this usage).
     *  
     * @return Memory holding JSON representation of this structure and all children
     * @throws BuilderStateException if the structure is invalid then this exception arises
     */
    public Memory toMemory() throws BuilderStateException { // TODO return funcresult
        JsonMemoryBuilder rb = new JsonMemoryBuilder();
        this.toBuilder(rb);
        return rb.getMemory();
    }

    public void toSerial(ByteBuf buf) throws BuilderStateException {
        CompositeToBufferBuilder rb = new CompositeToBufferBuilder(buf);
        this.toBuilder(rb);
        rb.write(Special.End);
    }

    public void toSerialMemory(Memory res) throws BuilderStateException {
        ByteBuf buf = Hub.instance.getBufferAllocator().heapBuffer(16 * 1024, 16 * 1024 * 1024);

        CompositeToBufferBuilder rb = new CompositeToBufferBuilder(buf);
        this.toBuilder(rb);
        rb.write(Special.End);

        res.write(buf.array(), buf.arrayOffset(), buf.readableBytes());
        buf.release();
    }

    public Memory toSerialMemory() throws BuilderStateException {
        ByteBuf buf = Hub.instance.getBufferAllocator().heapBuffer(16 * 1024, 16 * 1024 * 1024);

        CompositeToBufferBuilder rb = new CompositeToBufferBuilder(buf);
        this.toBuilder(rb);
        rb.write(Special.End);

        Memory res = new Memory(buf.readableBytes());
        res.write(buf.array(), buf.arrayOffset(), buf.readableBytes());
        buf.release();

        return res;
    }

    @Override
    public void operation(StackEntry stack, XElement code) {
        if ("Clear".equals(code.getName())) {
            this.clear();
            stack.resume();
            return;
        }

        super.operation(stack, code);
    }
}