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

com.quinsoft.zeidon.standardoe.WriteOisToXmlStream 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.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.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.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;
    private SerializationMapping mapper;

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

        // 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( mapper.entityToRecord( entityDef ),
                          "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( mapper.entityToRecord( entityDef ) );

        currentIndent++;
        Object[] attrIncr = new Object[] { "updated", null };
        if ( writeAttributes )
        {
            for ( AttributeDef attributeDef : ei.getNonNullAttributeList() )
            {
                if ( attributeDef.isDerived() && ! options.isWriteDerivedAttributes() )
                    continue;

                if ( attributeDef.isHidden() && ! options.isWriteHiddenAttributes() )
                    continue;

                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", "recordName", 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