All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.quinsoft.zeidon.utils.WriteOisToJsonStreamNoIncrementals Maven / Gradle / Ivy

The newest version!
/**
    This file is part of the Zeidon Java Object Engine (Zeidon JOE).

    Zeidon JOE is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Zeidon JOE 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 Zeidon JOE.  If not, see .

    Copyright 2009-2015 QuinSoft
 */
package com.quinsoft.zeidon.utils;

import java.io.Writer;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.EnumSet;

import org.apache.commons.lang3.StringUtils;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.quinsoft.zeidon.AttributeInstance;
import com.quinsoft.zeidon.EntityInstance;
import com.quinsoft.zeidon.SerializationMapping;
import com.quinsoft.zeidon.SerializeOi;
import com.quinsoft.zeidon.StreamWriter;
import com.quinsoft.zeidon.View;
import com.quinsoft.zeidon.WriteOiFlags;
import com.quinsoft.zeidon.ZeidonException;
import com.quinsoft.zeidon.domains.BigDecimalDomain;
import com.quinsoft.zeidon.domains.BooleanDomain;
import com.quinsoft.zeidon.domains.Domain;
import com.quinsoft.zeidon.domains.DoubleDomain;
import com.quinsoft.zeidon.domains.IntegerDomain;
import com.quinsoft.zeidon.domains.LongDomain;
import com.quinsoft.zeidon.objectdefinition.AttributeDef;
import com.quinsoft.zeidon.objectdefinition.EntityDef;

/**
 * Serializes an OI by writing it as a JSON stream.  This does not write any Zeidon
 * information (e.g. incremental flags).  Zeidon can retrieve an OI written with this
 * object but it won't have any linking or incremental flags.
 *
 * @author dgc
 *
 */
public class WriteOisToJsonStreamNoIncrementals implements StreamWriter
{
    private final static String VERSION = "1";

    private Collection viewList;
    private EnumSet flags;
    private SerializeOi options;
    private JsonGenerator jg;
    private SerializationMapping mapper;

    @Override
    public void writeToStream( SerializeOi options, Writer writer )
    {
        this.viewList = options.getViewList();
        if ( options.getFlags() == null )
            flags = EnumSet.noneOf( WriteOiFlags.class );
        else
            flags = options.getFlags();
        if ( flags.contains( WriteOiFlags.INCREMENTAL ) )
            throw new ZeidonException( "This JSON stream writer not intended for writing incremental." );

        this.options = options;
        mapper = options.getSerializationMapping();

        JsonFactory jsonF = new JsonFactory();
        try
        {
            jg = jsonF.createGenerator( writer );
            if ( ! options.isCompressed() )
                jg.useDefaultPrettyPrinter();
            jg.writeStartObject();

//            jg.writeStringField( "version", VERSION );

            for ( View view : viewList )
                writeOi( view );

            jg.writeEndObject();
            jg.close();
        }
        catch ( Exception e )
        {
            throw ZeidonException.wrapException( e );
        }
    }

    private void writeOi( View view ) throws Exception
    {
        view = view.newView();  // To preserve cursor positions in the original view.
        view.setInternal( true );  // So it doesn't show up in the browser.

        Integer rootCount = view.getTotalRootCount();
        if ( rootCount != null )
            jg.writeNumberField( "totalRootCount", rootCount );

        EntityDef rootEntityDef = view.getLodDef().getRoot();
        jg.writeArrayFieldStart( objectName( rootEntityDef ) );
        if ( ! view.isEmpty() )
        {
            jg.writeStartObject();

            for ( EntityInstance ei:  view.cursor( rootEntityDef ).eachEntity() )
            {
                if ( ei.hasPrevTwin() )
                    jg.writeStartObject();

                writeEntity( ei );

                if ( ei.hasNextTwin() )
                    jg.writeEndObject();
            }

            jg.writeEndObject();
        }
        jg.writeEndArray();
    }

    /**
     * Convert the name of the EntityDef to the object name used in JSON.
     * @param entityDef
     * @return
     */
    private String objectName( EntityDef entityDef )
    {
        String objectName = mapper.entityToRecord( entityDef );
        return camelCaseName( objectName );
    }

    private String fieldName( AttributeDef attributeDef )
    {
        String fieldName = mapper.attributeToField( attributeDef );
        return camelCaseName( fieldName );
    }

    private String camelCaseName( String name )
    {
        if ( ! options.isCamelCase() )
            return name;

        char[] nameChars = name.toCharArray();
        for ( int i = 0; i < nameChars.length; i++ )
        {
            if ( ! Character.isUpperCase( nameChars[ i ] ) )
                break;

            nameChars[ i ] = Character.toLowerCase( nameChars[ i ] );
        }

        return String.valueOf( nameChars );
    }

    private EntityDef writeEntity( EntityInstance ei ) throws Exception
    {
        try
        {
            // See if we need to open or close an array field.
            final EntityDef entityDef = ei.getEntityDef();

            for ( AttributeDef attributeDef : entityDef.getAttributes() )
            {
                if ( attributeDef.isHidden() && ! options.isWriteHiddenAttributes() )
                    continue;

                if ( attributeDef.isDerived() )
                    continue;

                AttributeInstance attrib = ei.getAttribute( attributeDef );
                if ( attrib.isNull() )
                    continue;

                Domain domain = attributeDef.getDomain();
                String jsonName = fieldName( attributeDef );
                if ( domain instanceof IntegerDomain )
                    jg.writeNumberField( jsonName, attrib.getInteger() );
                else
                if ( domain instanceof DoubleDomain )
                    jg.writeNumberField( jsonName, attrib.getDouble() );
                else
                if ( domain instanceof BooleanDomain )
                    jg.writeBooleanField( jsonName, attrib.getBoolean() );
                else
                if ( domain instanceof LongDomain )
                    jg.writeNumberField( jsonName, (Long) attrib.getValue() );
                else
                if ( domain instanceof BigDecimalDomain )
                    jg.writeNumberField( jsonName, (BigDecimal) attrib.getValue() );
                else
                {
                    String value = attrib.getString( null );

                    // getAttributes will include null attributes if they have been updated
                    // (i.e. explicitly set to null).  Since we aren't writing incrementals
                    // we don't want those so check for null.
                    if ( ! StringUtils.isBlank( value ) )
                        jg.writeStringField( fieldName( attrib.getAttributeDef() ), value );
                }
            }

            // Loop through the children and add them.
            for ( EntityInstance child : ei.getDirectChildren( false, false ) )
            {
                EntityDef childEntityDef = child.getEntityDef();
                if ( ! child.hasPrevTwin() )
                {
                    if ( childEntityDef.getMaxCardinality() > 1 )
                    {
                        jg.writeArrayFieldStart( objectName( childEntityDef ) );
                        jg.writeStartObject();
                    }
                    else
                        jg.writeObjectFieldStart( objectName( childEntityDef ) );
                }
                else
                    jg.writeStartObject();

                writeEntity( child );

                jg.writeEndObject();
                if ( ! child.hasNextTwin() )
                {
                    if ( childEntityDef.getMaxCardinality() > 1 )
                        jg.writeEndArray();
                }
            }

            return entityDef;
        }

        catch ( Exception e )
        {
            throw ZeidonException.wrapException( e ).prependEntityInstance( ei );
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy