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

com.quinsoft.zeidon.standardoe.ActivateOiFromPorStream 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.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;

import com.quinsoft.zeidon.ActivateFlags;
import com.quinsoft.zeidon.Application;
import com.quinsoft.zeidon.Blob;
import com.quinsoft.zeidon.CreateEntityFlags;
import com.quinsoft.zeidon.CursorPosition;
import com.quinsoft.zeidon.DeserializeOi;
import com.quinsoft.zeidon.StreamReader;
import com.quinsoft.zeidon.Task;
import com.quinsoft.zeidon.View;
import com.quinsoft.zeidon.ZeidonException;
import com.quinsoft.zeidon.objectdefinition.AttributeDef;
import com.quinsoft.zeidon.objectdefinition.EntityDef;
import com.quinsoft.zeidon.objectdefinition.InternalType;
import com.quinsoft.zeidon.objectdefinition.LodDef;
import com.quinsoft.zeidon.utils.BufferedBinaryStreamReader;
import com.quinsoft.zeidon.utils.PortableFileReader;
import com.quinsoft.zeidon.utils.PortableFileReader.PortableFileAttributeHandler;
import com.quinsoft.zeidon.utils.PortableFileReader.PortableFileEntityHandler;

/**
 * Activates an OI from a POR stream.
 *
 * @author DG
 *
 */
class ActivateOiFromPorStream implements PortableFileEntityHandler, StreamReader
{
    private static final EnumSet CREATE_FLAGS = EnumSet.of( CreateEntityFlags.fNO_SPAWNING,
                                                                               CreateEntityFlags.fIGNORE_MAX_CARDINALITY,
                                                                               CreateEntityFlags.fDONT_UPDATE_OI,
                                                                               CreateEntityFlags.fDONT_INITIALIZE_ATTRIBUTES,
                                                                               CreateEntityFlags.fIGNORE_PERMISSIONS );

    private Task    task;
    private Application application;
    private LodDef            lodDef;
    private ViewImpl          view;
    private Set       control;
    private List entities;
    private EntityInstanceImpl       lastInstance;
    private BufferedBinaryStreamReader streamReader;
    private InputStream        inputStream;
    private boolean            ignoreInvalidEntityNames;
    private boolean            ignoreInvalidAttributeNames;

    ActivateOiFromPorStream()
    {
        super();
    }

    ViewImpl read()
    {
        PortableFileReader reader = new PortableFileReader( task.log(), inputStream, this );
        if ( streamReader != null )
            reader.setStreamReader( streamReader );

        reader.readEntities();

        // If user wanted just one root remove others if we have more than one.
        // We don't want to abort the loading of entities in the middle of the stream
        // because that could throw off the link cards.
        EntityCursorImpl rootCursor = view.getViewCursor().getEntityCursor( lodDef.getRoot() );
        if ( control.contains( ActivateFlags.fSINGLE ) && rootCursor.getEntityCount() > 1  )
        {
            rootCursor.setFirst();
            while ( rootCursor.setNext().isSet() )
                rootCursor.dropEntity();
            rootCursor.setFirst();
        }

        view.reset();
        return view;
    }

    void setLodDef( LodDef lodDef )
    {
        this.lodDef = lodDef;
    }

    @Override
    public PortableFileAttributeHandler createEntity(PortableFileReader reader,
                                                     int level,
                                                     long flags)
    {
        String entityName = reader.getAttributeName();
        EntityDef entityDef = lodDef.getEntityDef( entityName, ! ignoreInvalidEntityNames );

        // If the entityDef is null then the entity name doesn't exist in the LodDef and
        // the user wants us to ignore unknown entities.
        if ( entityDef == null )
        {
            entities.add( null );  // Needed so that link indexes in stream still point to valid entities.
            return new PortableFileAttributeHandler.NullAttributeHandler();
        }

        int entityDefLevel = entityDef.getDepth() + view.getViewCursor().getRecursiveDiff();
        if ( entityDefLevel < level )
        {
            // If the entityDef level is < level than the last entity we created must
            // be the parent of the one we're about to create and we need to set the
            // cursor to the subobject.
            view.cursor( lastInstance.getEntityDef() ).setToSubobject();
        }
        else
        {
            while ( entityDefLevel > level )
            {
                view.resetSubobject();
                entityDefLevel = entityDef.getDepth() + view.getViewCursor().getRecursiveDiff();
            }
        }

        // Create the new instance and add it to the list of entities.
        EntityCursorImpl cursor = view.cursor( entityDef );
        lastInstance = cursor.createEntity( CursorPosition.LAST, CREATE_FLAGS );
        entities.add( lastInstance );

        return new AttributeSetter( lastInstance );
    }

    private class AttributeSetter implements PortableFileAttributeHandler
    {
        // Flags used when reading from a stream.
        final static long FLAGS_ACTIVATED = 0x00000001;
        final static long FLAGS_UPDATED   = 0x00000002;

        private final EntityInstanceImpl entityInstance;
        private final EntityDef         entityDef;

        public AttributeSetter(EntityInstanceImpl entityInstance)
        {
            this.entityInstance = entityInstance;
            entityDef = entityInstance.getEntityDef();
        }

        @Override
        public void setAttribute(PortableFileReader reader)
        {
            AttributeDef attributeDef = entityDef.getAttribute( reader.getAttributeName(), ! ignoreInvalidAttributeNames );
            if ( attributeDef != null )
            {
                if ( attributeDef.getType() == InternalType.BLOB )
                {
                    int length = Integer.parseInt( reader.getAttributeValue() );
                    byte[] buffer = new byte[ length ];
                    int read;
                    try
                    {
                        read = reader.getStreamReader().read( buffer, length );
                    }
                    catch ( IOException e )
                    {
                        throw ZeidonException.wrapException( e );
                    }
                    assert read == length;
                    entityInstance.getAttribute( attributeDef).setInternalValue( new Blob( buffer ), true ) ;
                }
                else
                    entityInstance.getAttribute( attributeDef).setInternalValue( reader.getAttributeValue(), true ) ;

                if ( reader.isIncremental() )
                {
                    AttributeValue attrib = entityInstance.getInternalAttribute( attributeDef );
                    attrib.setUpdated( ( reader.getAttributeFlags() & FLAGS_UPDATED ) != 0 );
                }
            }
        }
    }

    @Override
    public void endEntity(PortableFileReader reader,
                          PortableFileAttributeHandler handler,
                          int currentLevel)
    {
    }

    @Override
    public void endFile()
    {
        view.setAllowHiddenEntities( false );
    }

    @Override
    public void link(PortableFileReader reader, int target, int source)
    {
        EntityInstanceImpl targetInstance = entities.get( target );
        EntityInstanceImpl sourceInstance = entities.get( source );
        reader.getLogger().trace( "Linking %s (%d) with %s (%d)",
                                  targetInstance.getEntityDef().getName(), target,
                                  sourceInstance.getEntityDef().getName(), source );
        targetInstance.linkInternalInstances( sourceInstance );
    }

    @Override
    public void endEntityAttributes(PortableFileReader reader, String entityName, int currentLevel)
    {
        if ( reader.isIncremental() )
        {
            assert lastInstance.getEntityDef().getName().equals( entityName );
            lastInstance.setIncrementalFlags( reader.getEntityFlags() );
        }
    }

    @Override
    public void startFile(PortableFileReader reader, String lodDefName)
    {
        // LodDef may have already been given to us.
        if ( lodDef == null )
            lodDef = application.getLodDef( task, lodDefName );

        if ( view == null )
            view = ((InternalView) task.activateEmptyObjectInstance( lodDef )).getViewImpl();
        else
        if ( view.getLodDef() != lodDef )
            throw new ZeidonException( "LodDef of empty view (%s) does not match LodDef from OI stream (%s)",
                                       view.getLodDef().getName(), lodDef.getName() );

        view.setAllowHiddenEntities( true );
    }

    /**
     * This sets the initial empty view.  If not set then it will be created automatically.
     * Setting this allows a caller to create and access the view before processing starts.
     *
     * @param view
     */
    void setEmptyView( ViewImpl view )
    {
        this.view = view;
    }

    LodDef getLodDef()
    {
        return lodDef;
    }

    /**
     * Explicitly set the stream reader.  This allows a client to read multiple OIs
     * from a single stream because this won't be automatically closed.
     *
     * @param reader
     */
    public void setStreamReader( BufferedBinaryStreamReader reader )
    {
        this.streamReader = reader;
    }

    @Override
    public List readFromStream( DeserializeOi options )
    {
        task = options.getTask();
        application = options.getApplication();
        control = options.getFlags();
        entities = new ArrayList();
        inputStream = options.getInputStream();
        lodDef = options.getLodDef();
        ignoreInvalidEntityNames = control.contains( ActivateFlags.fIGNORE_ENTITY_ERRORS );
        ignoreInvalidAttributeNames = control.contains( ActivateFlags.fIGNORE_ATTRIB_ERRORS );

        read();
        return Arrays.asList( (View) view );
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy