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

com.quinsoft.zeidon.standardoe.WriteOisToXmlStream Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show 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.standardoe;

import java.io.IOException;
import java.io.Writer;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;

import com.quinsoft.zeidon.EntityCursor.CursorStatus;
import com.quinsoft.zeidon.SelectSet;
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.objectdefinition.AttributeDef;
import com.quinsoft.zeidon.objectdefinition.EntityDef;

/**
 * @author DG
 *
 */
public class WriteOisToXmlStream implements StreamWriter
{
    private ViewImpl currentView;
    private Writer writer;
    private EnumSet control;
    private boolean incremental;
    private final Set ois = new HashSet();

    private int currentIndent;
    private SerializeOi options;

    @Override
    public void writeToStream( SerializeOi options, Writer writer )
    {
        List viewList = options.getViewList();

        // Create a set of all the OIs and turn off the record owner flag.  The record owner
        // flag will be used to determine if a linked EI has been written to the stream.
        for ( View view : viewList )
        {
            ObjectInstance oi = ((InternalView) view).getViewImpl().getObjectInstance();
            ois.add( oi );
            for ( EntityInstanceImpl ei = oi.getRootEntityInstance(); ei != null; ei = ei.getNextTwin() )
                ei.setRecordOwner( false );
        }

        currentView = ((InternalView) viewList.get( 0 ) ).getViewImpl();
        this.options = options;
        this.writer = writer;
        control = options.getFlags();
        incremental = this.control.contains( WriteOiFlags.INCREMENTAL );

        if ( viewList.size() > 1 )
        {
            startElement( "zOIs" );
            currentIndent++;
        }

        for ( View view : viewList )
        {
            currentView = ((InternalView) view ).getViewImpl();
            writeViewToStream();
        }

        if ( viewList.size() > 1 )
        {
            currentIndent--;
            endElement( "zOIs" );
        }
    }

    private void write( String string )
    {
        try
        {
            writer.write( string );
        }
        catch ( IOException e )
        {
            throw ZeidonException.wrapException( e )
                                 .appendMessage( "Attempting to write: %s", StringUtils.substring( string, 0, 100 ) );
        }
    }

    private void write( String format, Object...strings )
    {
        if ( strings == null || strings.length == 0 )
        {
            write( format );
        }
        else
        {
            write( String.format( format, strings ) );
        }
    }

    private void writeIndent()
    {
        if ( options.isCompressed() )
            return;

        for ( int i = 0; i < currentIndent; i++ )
            write( "  " );
    }

    private void startElement( final String elementName, final Object...attributes )
    {
        startElement( elementName, null, false, attributes );
    }

    private void startElement( final String elementName, final String value, final boolean close, final Object...attributes )
    {
        assert attributes.length % 2 == 0 : "Illegal number of attributes; should be an even number.";
        writeIndent();
        write( "<" );
        write( elementName );

        if ( attributes != null && attributes.length > 0 )
        {
            for ( int i = 0; i < attributes.length; i += 2 )
            {
                // Don't bother printing null attributes.
                if ( attributes[ i + 1 ] == null )
                    continue;

                String esc = StringEscapeUtils.escapeXml( attributes[ i + 1 ].toString() );
                // Don't bother printing if it's empty.
                if ( ! StringUtils.isBlank( esc ) )
                    write( " %s=\"%s\"", attributes[ i ], esc );
            }
        }

        if ( value != null )
        {
            String esc = StringEscapeUtils.escapeXml( value );
            write(">%s", esc, elementName );
            if ( ! options.isCompressed() )
                write( "\n" );
        }
        else
        {
            if ( close )
                write( "/>" );
            else
                write( ">" );

            if ( ! options.isCompressed() )
                write( "\n" );
        }
    }

    private void endElement( final String elementName )
    {
        writeIndent();
        write( "", elementName );
        if ( ! options.isCompressed() )
            write( "\n" );
    }

    /**
     * If this EI is linked with another EI in the OI set then this returns the record owner.
     * If no record owner, returns EI.
     *
     * @param ei
     * @return
     */
    private EntityInstanceImpl findLinkedRecordOwner( EntityInstanceImpl ei )
    {
        // Keep track of whether we found another EI linked with this one.
        boolean foundLinked = false;

        // Run through the list of the other linked instances.
        for ( EntityInstanceImpl linked : ei.getLinkedInstances() )
        {
            if ( ois.contains( linked.getObjectInstance() ) )
            {
                foundLinked = true;
                if ( linked.isRecordOwner() )
                    return linked;
            }
        }

        // If we get here then we didn't find a record owner.  if foundLinked is true
        // then we did find a linked EI.
        if ( foundLinked )
            return ei;

        // Didn't find any EI's that are linked with ei.
        return null;
    }

    private void writeEntity( final EntityInstanceImpl ei )
    {
        final EntityDef entityDef = ei.getEntityDef();

        currentIndent = entityDef.getDepth();

        boolean writeAttributes = true;
        if ( incremental )
        {
            EntityCursorImpl cursor = currentView.cursor( entityDef );

            // Check to see if the current ei is the selected EI.  We first check the status because
            // calling getEntityInstance() could potentially trigger a lazy-load.
            boolean selected = options.isWithCursors() &&
                               cursor.getStatus() == CursorStatus.SET &&
                               cursor.getEntityInstance() == ei;

            EntityInstanceImpl recordOwner = findLinkedRecordOwner( ei );
            String entityKey = null;
            String isLinkedSource = null;
            if ( recordOwner != null )
            {
                if ( recordOwner == ei )
                {
                    // TODO: validate that ei.entityDef has all the attributes in the shared
                    // attribute hash.
                    ei.setRecordOwner( true );
                    isLinkedSource = "Y";
                    entityKey = Long.toString( ei.getEntityKey() );
                }
                else
                {
                    // Write the entity key of the record owner.
                    entityKey = Long.toString( ei.getEntityKey() );
                    writeAttributes = false;
                }
            }

            StringBuilder lazyLoaded = new StringBuilder();
            if ( ei.hasLoadedLazyChildren() )
            {
                for ( EntityDef def : ei.getEntitiesLoadedLazily() )
                    lazyLoaded.append( "," ).append( def.getName() );
                lazyLoaded.deleteCharAt( 0 );
            }

            startElement( entityDef.getName(),
                          "created",    yesNull( ei.isCreated() ),
                          "deleted",    yesNull( ei.isDeleted() ),
                          "updated",    yesNull( ei.isUpdated() ),
                          "included",   yesNull( ei.isIncluded() ),
                          "excluded",   yesNull( ei.isExcluded() ),
                          "incomplete", yesNull( ei.isIncomplete() ),
                          "selected",   yesNull( selected ),
                          "readonly",   yesNull( currentView.isReadOnly() ),
                          "isLinkedSource", isLinkedSource,
                          "entityKey",  entityKey,
                          "lazyLoaded", lazyLoaded.toString() );
        }
        else
            startElement( entityDef.getName() );

        currentIndent++;
        Object[] attrIncr = new Object[] { "updated", null };
        if ( writeAttributes )
        {
            for ( AttributeDef attributeDef : ei.getNonNullAttributeList() )
            {
                AttributeValue attrib = ei.getInternalAttribute( attributeDef );
                String value;
                value = attrib.getString( currentView.getTask(), attributeDef );

                if ( incremental )
                {
                    attrIncr[ 1 ] = yesNull( attrib.isUpdated() );
                    startElement( attributeDef.getName(), value, true, attrIncr );
                }
                else
                    startElement( attributeDef.getName(), value, true, (Object[]) null );
            }
        }

        // Loop through the children and add them.  If 'incremental' is true then
        // we want hidden entities.
        boolean first = true;
        for ( EntityInstanceImpl child : ei.getDirectChildren( incremental, false ) )
        {
            if ( first )
            {
                if ( ! options.isCompressed() )
                    write( "\n" );
                first = false;
            }

            writeEntity( child );
        }

        currentIndent--;
        endElement( entityDef.getName() );
    }

    private void writeViewToStream()
    {
        SelectSet rootSelectSet = null;
        Map sets = options.getRootSelectSets();
        if ( sets != null )
            rootSelectSet = sets.get( currentView.getOiId() );

//        write( "\n" );
        startElement( "zOI", "objectName", currentView.getLodDef().getName(),
                             "appName", currentView.getApplication().getName(),
                             "increFlags", yesNo( incremental ),
                             "locked", yesNo( currentView.getObjectInstance().isLocked() ),
                             "totalRootCount", currentView.getTotalRootCount() );

        currentIndent++;

        for ( EntityInstanceImpl ei = currentView.getObjectInstance().getRootEntityInstance();
              ei != null;
              ei = ei.getNextTwin() )
        {
            // If we have a root select set and the EI is not selected then skip it.
            if ( rootSelectSet != null && rootSelectSet.isSelected( ei ) )
                continue;

            if ( incremental || ! ei.isHidden() )
                writeEntity( ei );
        }

        currentIndent--;
        endElement( "zOI" );
    }

    private String yesNull( boolean b )
    {
        return b ? "Y" : "";
    }

    private String yesNo( boolean b )
    {
        return b ? "Y" : "N";
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy