Package org.apache.tapestry.vlib.ejb.impl

Source Code of org.apache.tapestry.vlib.ejb.impl.KeyAllocatorBean

//  Copyright 2004 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.apache.tapestry.vlib.ejb.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;

import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.tapestry.contrib.ejb.XEJBException;

/**
*  Implementation of the {@link org.apache.tapestry.vlib.ejb.IKeyAllocator}
*  stateless session bean.
*
<p>We're cheating a little; they KeyAllocator does have
*  state, it just doesn't get persisted ever.  Since the
*  operation on it is atomic ("gimme a key") it doesn't
*  need to have conversational state with its clients.
*
<p>The KeyAllocator records in the database the "next key
*  to allocate".  When it needs a key, it allocates a block
*  of keys (by advancing the next key by a some number).
*
<p>If the KeyAllocator instance is purged from the pool,
*  then some number of keys that it has allocated will
*  be lost.  Big deal.
*
@version $Id: KeyAllocatorBean.java,v 1.3 2004/02/19 17:38:07 hlship Exp $
@author Howard Lewis Ship
*
**/

public class KeyAllocatorBean implements SessionBean
{
    private static final String PROPERTY_NAME = "next-key";

    private SessionContext context;

    /**
     *  List of Integer instances; these are keys
     *  acquired from the database.
     *
     **/

    private LinkedList keys;

    /**
     *  Number of keys to allocate from the database
     *  at a time.  Set from the ENC property "blockSize".
     *
     **/

    private int blockSize = 0;

    /**
     *  Data source, retrieved from the ENC property
     *  "jdbc/dataSource".
     *
     **/

    private DataSource dataSource;

    /**
     *  Activates the bean.  Gets the block size
     *  and DataSource from the environment.
     *
     **/

    public void ejbCreate()
    {
        Context initial;
        Context environment;
        Integer blockSizeProperty;

        try
        {
            initial = new InitialContext();
            environment = (Context) initial.lookup("java:comp/env");
        }
        catch (NamingException ex)
        {
            throw new XEJBException("Could not lookup environment.", ex);
        }

        try
        {
            blockSizeProperty = (Integer) environment.lookup("blockSize");
        }
        catch (NamingException ex)
        {
            throw new XEJBException("Could not lookup blockSize property.", ex);
        }

        blockSize = blockSizeProperty.intValue();

        try
        {
            dataSource = (DataSource) environment.lookup("jdbc/dataSource");
        }
        catch (NamingException ex)
        {
            throw new XEJBException("Could not lookup data source.", ex);
        }

        if (keys == null)
            keys = new LinkedList();
    }

    /**
     *  Does nothing, not invoked in stateless session beans.
     **/

    public void ejbPassivate()
    {
    }

    public void setSessionContext(SessionContext value)
    {
        context = value;
    }

    /**
     *  Does nothing, not invoked in stateless session beans.
     *
     **/

    public void ejbActivate()
    {
    }

    /**
     *  Does nothing.  This is invoked when the bean moves from
     *  the method ready pool to the "does not exist" state.
     *  The EJB container will lost its reference to the
     *  bean, and the garbage collector will take it
     *  (including any keys it has cached from the database).
     *
     **/

    public void ejbRemove()
    {
        // Does nothing.
    }

    /**
     *  Allocates a single key, going to the database
     *  only if it has no keys in its internal cache.
     *
     **/

    public Integer allocateKey()
    {
        if (keys.isEmpty())
            allocateBlock(1);

        return (Integer) keys.removeFirst();
    }

    /**
     *  Allocates a block of keys, going to the database
     *  if there are insufficient keys in its internal
     *  cache.
     *
     **/

    public Integer[] allocateKeys(int count)
    {
        Integer[] result;
        int i;

        if (keys.size() < count)
            allocateBlock(count);

        result = new Integer[count];

        for (i = 0; i < count; i++)
        {
            result[i] = (Integer) keys.removeFirst();
        }

        return result;
    }

    /**
     *  Allocates a block of keys from the database.
     *  Allocates count keys, or the configured block size,
     *  whichever is greater.
     *
     *  <p>It is assumed that this operation takes place
     *  within a transaction.
     *
     **/

    protected void allocateBlock(int count)
    {
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet set = null;
        int nextKey;
        int allocationCount;
        int i;

        allocationCount = Math.max(count, blockSize);

        try
        {
            connection = getConnection();

            statement = connection.prepareStatement("select PROP_VALUE from PROP where NAME = ?");
            statement.setString(1, PROPERTY_NAME);

            set = statement.executeQuery();

            // Advance to the first row.

            set.next();

            nextKey = set.getInt(1);

            set.close();
            set = null;

            statement.close();
            statement = null;

            // Now, take those keys and advance nextKey

            for (i = 0; i < allocationCount; i++)
                keys.add(new Integer(nextKey++));

            // Update nextKey back to the database.

            statement =
                connection.prepareStatement("update PROP\n" + "set PROP_VALUE = ?\n" + "where NAME   = ?");
            statement.setInt(1, nextKey);
            statement.setString(2, PROPERTY_NAME);

            statement.executeUpdate();
        }
        catch (SQLException ex)
        {
            ex.printStackTrace();

            throw new XEJBException("Unable to allocate keys from the database.", ex);
        }
        finally
        {
            if (set != null)
            {
                try
                {
                    set.close();
                }
                catch (SQLException ex)
                {
                }
            }

            if (statement != null)
            {
                try
                {
                    statement.close();
                }
                catch (SQLException ex)
                {
                }
            }

            if (connection != null)
            {
                try
                {
                    connection.close();
                }
                catch (SQLException ex)
                {
                }
            }
        }

    }

    /**
     *  Gets a database connection from the pool.
     *
     *  @throws EJBException if a {@link SQLException}
     *  is thrown.
     *
     **/

    protected Connection getConnection()
    {
        try
        {
            return dataSource.getConnection();
        }
        catch (SQLException ex)
        {
            throw new XEJBException("Unable to get database connection from pool.", ex);
        }
    }
}
TOP

Related Classes of org.apache.tapestry.vlib.ejb.impl.KeyAllocatorBean

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.