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

org.openscada.opc.lib.da.AccessBase Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of the openSCADA project
 * Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
 * Copyright (C) 2014 IBH SYSTEMS GmbH (http://ibh-systems.com)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */

package org.openscada.opc.lib.da;

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import org.jinterop.dcom.common.JIException;
import org.openscada.opc.lib.common.NotConnectedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AccessBase implements ServerConnectionStateListener
{
    private static Logger logger = LoggerFactory.getLogger ( AccessBase.class );

    protected Server server;

    protected Group group;

    protected boolean active;

    private final List stateListeners = new CopyOnWriteArrayList ();

    private boolean bound;

    /**
     * Holds the item to callback assignment
     */
    protected Map items = new HashMap ();

    protected Map itemMap = new HashMap ();

    protected Map itemCache = new HashMap ();

    private final int period;

    protected Map itemSet = new HashMap ();

    protected String logTag;

    protected Logger dataLogger;

    public AccessBase ( final Server server, final int period ) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException
    {
        this.server = server;
        this.period = period;
    }

    public AccessBase ( final Server server, final int period, final String logTag )
    {
        this.server = server;
        this.period = period;
        this.logTag = logTag;
        if ( this.logTag != null )
        {
            this.dataLogger = LoggerFactory.getLogger ( "opc.data." + logTag );
        }
    }

    public boolean isBound ()
    {
        return this.bound;
    }

    public synchronized void bind ()
    {
        if ( isBound () )
        {
            return;
        }

        this.server.addStateListener ( this );
        this.bound = true;
    }

    public synchronized void unbind () throws JIException
    {
        if ( !isBound () )
        {
            return;
        }

        this.server.removeStateListener ( this );
        this.bound = false;

        stop ();
    }

    public boolean isActive ()
    {
        return this.active;
    }

    public void addStateListener ( final AccessStateListener listener )
    {
        this.stateListeners.add ( listener );
        listener.stateChanged ( isActive () );
    }

    public void removeStateListener ( final AccessStateListener listener )
    {
        this.stateListeners.remove ( listener );
    }

    protected void notifyStateListenersState ( final boolean state )
    {
        final List list = new ArrayList ( this.stateListeners );

        for ( final AccessStateListener listener : list )
        {
            listener.stateChanged ( state );
        }
    }

    protected void notifyStateListenersError ( final Throwable t )
    {
        final List list = new ArrayList ( this.stateListeners );

        for ( final AccessStateListener listener : list )
        {
            listener.errorOccured ( t );
        }
    }

    public int getPeriod ()
    {
        return this.period;
    }

    public synchronized void addItem ( final String itemId, final DataCallback dataCallback ) throws JIException, AddFailedException
    {
        if ( this.itemSet.containsKey ( itemId ) )
        {
            return;
        }

        this.itemSet.put ( itemId, dataCallback );

        if ( isActive () )
        {
            realizeItem ( itemId );
        }
    }

    public synchronized void removeItem ( final String itemId )
    {
        if ( !this.itemSet.containsKey ( itemId ) )
        {
            return;
        }

        this.itemSet.remove ( itemId );

        if ( isActive () )
        {
            unrealizeItem ( itemId );
        }
    }

    @Override
    public void connectionStateChanged ( final boolean connected )
    {
        try
        {
            if ( connected )
            {
                start ();
            }
            else
            {
                stop ();
            }
        }
        catch ( final Exception e )
        {
            logger.error ( String.format ( "Failed to change state (%s)", connected ), e );
        }
    }

    protected synchronized void start () throws JIException, IllegalArgumentException, UnknownHostException, NotConnectedException, DuplicateGroupException
    {
        if ( isActive () )
        {
            return;
        }

        logger.debug ( "Create a new group" );
        this.group = this.server.addGroup ();
        this.group.setActive ( true, this.period );
        this.active = true;

        notifyStateListenersState ( true );

        realizeAll ();
    }

    protected void realizeItem ( final String itemId ) throws JIException, AddFailedException
    {
        logger.debug ( "Realizing item: {}", itemId );

        final DataCallback dataCallback = this.itemSet.get ( itemId );
        if ( dataCallback == null )
        {
            return;
        }

        final Item item = this.group.addItem ( itemId );
        this.items.put ( item, dataCallback );
        this.itemMap.put ( itemId, item );
    }

    protected void unrealizeItem ( final String itemId )
    {
        final Item item = this.itemMap.remove ( itemId );
        this.items.remove ( item );
        this.itemCache.remove ( item );

        try
        {
            this.group.removeItem ( itemId );
        }
        catch ( final Throwable e )
        {
            logger.error ( String.format ( "Failed to unrealize item '%s'", itemId ), e );
        }
    }

    /*
     * FIXME: need some perfomance boost: subscribe all in one call
     */
    protected void realizeAll ()
    {
        for ( final String itemId : this.itemSet.keySet () )
        {
            try
            {
                realizeItem ( itemId );
            }
            catch ( final AddFailedException e )
            {
                Integer rc = e.getErrors ().get ( itemId );
                if ( rc == null )
                {
                    rc = -1;
                }
                logger.warn ( String.format ( "Failed to add item: %s (%08X)", itemId, rc ) );

            }
            catch ( final Exception e )
            {
                logger.warn ( "Failed to realize item: " + itemId, e );
            }
        }
    }

    protected void unrealizeAll ()
    {
        this.items.clear ();
        this.itemCache.clear ();
        try
        {
            this.group.clear ();
        }
        catch ( final JIException e )
        {
            logger.info ( "Failed to clear group. No problem if we already lost the connection", e );
        }
    }

    protected synchronized void stop () throws JIException
    {
        if ( !isActive () )
        {
            return;
        }

        unrealizeAll ();

        this.active = false;
        notifyStateListenersState ( false );

        try
        {
            this.group.remove ();
        }
        catch ( final Throwable t )
        {
            logger.warn ( "Failed to disable group. No problem if we already lost connection" );
        }
        this.group = null;
    }

    public synchronized void clear ()
    {
        this.itemSet.clear ();
        this.items.clear ();
        this.itemMap.clear ();
        this.itemCache.clear ();
    }

    protected void updateItem ( final Item item, final ItemState itemState )
    {
        if ( this.dataLogger != null )
        {
            this.dataLogger.debug ( "Update item: {}, {}", item.getId (), itemState );
        }

        final DataCallback dataCallback = this.items.get ( item );
        if ( dataCallback == null )
        {
            return;
        }

        final ItemState cachedState = this.itemCache.get ( item );
        if ( cachedState == null )
        {
            this.itemCache.put ( item, itemState );
            dataCallback.changed ( item, itemState );
        }
        else
        {
            if ( !cachedState.equals ( itemState ) )
            {
                this.itemCache.put ( item, itemState );
                dataCallback.changed ( item, itemState );
            }
        }
    }

    protected void handleError ( final Throwable e )
    {
        notifyStateListenersError ( e );
        this.server.dispose ();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy