Package org.apache.ws.resource.impl

Source Code of org.apache.ws.resource.impl.AbstractResourceHome$Sweeper

/*=============================================================================*
*  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.ws.resource.impl;

import commonj.timers.Timer;
import commonj.timers.TimerManager;
import org.apache.commons.collections.map.ReferenceMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.addressing.EndpointReference;
import org.apache.ws.addressing.XmlBeansEndpointReference;
import org.apache.ws.resource.InvalidResourceKeyException;
import org.apache.ws.resource.JndiConstants;
import org.apache.ws.resource.PersistenceCallback;
import org.apache.ws.resource.Resource;
import org.apache.ws.resource.ResourceCreationEvent;
import org.apache.ws.resource.ResourceCreationListener;
import org.apache.ws.resource.ResourceDestructionEvent;
import org.apache.ws.resource.ResourceDestructionListener;
import org.apache.ws.resource.ResourceException;
import org.apache.ws.resource.ResourceHome;
import org.apache.ws.resource.ResourceKey;
import org.apache.ws.resource.ResourceUnknownException;
import org.apache.ws.resource.i18n.Keys;
import org.apache.ws.resource.i18n.MessagesImpl;
import org.apache.ws.resource.lifetime.ScheduledResourceTerminationResource;
import org.apache.ws.util.Cache;
import org.apache.ws.util.i18n.Messages;
import org.apache.ws.util.jndi.Initializable;
import org.apache.ws.util.jndi.JNDIUtils;
import org.apache.ws.util.lock.Lock;
import org.apache.ws.util.lock.LockManager;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* LOG-DONE An implementation of the <code>ResourceHome</code> interface. This implementation was designed to work with
* resources that implement the {@link PersistenceCallback PersistenceCallback} interface as well as memory resident
* resources. If the resource class implements the {@link PersistenceCallback PersistenceCallback} interface
* <code>SoftReference</code>s will be used to recycle resource objects. The resource class implementation is
* responsible for saving its state to disk. This implementation will <b>not</b> call {@link PersistenceCallback#store()
* PersistenceCallback.store()}. The resource implementation must have a default constructor. <br><br> Configuration
* options: <ul> <li> sweeperDelay - configures how often the resource sweeper runs in msec. By default the resource
* sweeper runs every minute. For example:
* <pre>
*    &lt;parameter&gt;
*     &lt;name&gt;sweeperDelay&lt;/name&gt;
*     &lt;value&gt;60000&lt;/value&gt;
*    &lt;/parameter&gt;
* </pre>
* <li> resourceClass - configures the name of the resource class. For example:
* <pre>
*    &lt;parameter&gt;
*     &lt;name&gt;resourceClass&lt;/name&gt;
*     &lt;value&gt;org.globus.wsrf.samples.counter.PersistentCounter&lt;/value&gt;
*    &lt;/parameter&gt;
* </pre>
* <li> resourceKeyType - configures the key type class. By default <code>java.lang.String</code> is used. For example:
* <pre>
*    &lt;parameter&gt;
*     &lt;name&gt;resourceKeyType&lt;/name&gt;
*     &lt;value&gt;java.lang.Integer&lt;/value&gt;
*    &lt;/parameter&gt;
* </pre>
* <li> resourceKeyName - configures the key name. For example:
* <pre>
*    &lt;parameter&gt;
*     &lt;name&gt;resourceKeyName&lt;/name&gt;
*     &lt;value&gt;{http://counter.com}CounterKey&lt;/value&gt;
*    &lt;/parameter&gt;
* </pre>
* </ul> <br> <b>Note:</b> Must be deployed with <code>org.globus.wsrf.jndi.BeanFactory</code> in JNDI or user must
* first call {@link #init() initialize()} method. Also when overriding the {@link #init() initialize()} method make
* sure to call <code>super.initialize();</code>.
*
* @author Globus, Ian Springer
*/
public abstract class AbstractResourceHome
        implements ResourceHome,
        Initializable
{
    private static final int DEFAULT_SWEEPER_DELAY = 60000;
    private static final Log LOG = LogFactory.getLog( AbstractResourceHome.class );
    public static final Messages MSG = MessagesImpl.getInstance();

    /**
     * DOCUMENT_ME
     */
    protected Map m_resources;

    /**
     * DOCUMENT_ME
     */
    protected String m_resourceClassName;
    private boolean m_resourceIsPersistent;
    private String m_resourceKeyClassName;
    private String m_resourceKeyName;
    private String m_wsdlTargetNamespace;
    private String m_serviceClassName;

    /**
     * DOCUMENT_ME
     */
    protected LockManager m_lockManager;
    private String m_cacheLocation;
    private Cache m_cache;
    private long m_sweeperDelay = DEFAULT_SWEEPER_DELAY;
    private Sweeper m_sweeper;
    private boolean m_initialized;
    private Class m_resourceClass;
    private Class m_serviceClass;
    private Class m_resourceKeyClass;
    private List m_creationListeners = new ArrayList();
    private List m_destructionListeners = new ArrayList();

    /**
     * DOCUMENT_ME
     *
     * @param jndiLocation DOCUMENT_ME
     */
    public void setCacheLocation( String jndiLocation )
    {
        m_cacheLocation = jndiLocation;
    }

    /**
     * DOCUMENT_ME
     *
     * @return DOCUMENT_ME
     */
    public String getCacheLocation()
    {
        return m_cacheLocation;
    }

    /**
     * DOCUMENT_ME
     *
     * @param resourceClass DOCUMENT_ME
     */
    public void setResourceClassName( String resourceClass )
    {
        m_resourceClassName = resourceClass;
    }

    /**
     * DOCUMENT_ME
     *
     * @return DOCUMENT_ME
     */
    public String getResourceClassName()
    {
        return m_resourceClassName;
    }

    /**
     * DOCUMENT_ME
     *
     * @param keyClass DOCUMENT_ME
     */
    public void setResourceKeyClassName( String keyClass )
    {
        m_resourceKeyClassName = keyClass;
    }

    /**
     * DOCUMENT_ME
     *
     * @return DOCUMENT_ME
     */
    public String getResourceKeyClassName()
    {
        return m_resourceKeyClassName;
    }

    /**
     * DOCUMENT_ME
     *
     * @param keyName DOCUMENT_ME
     */
    public void setResourceKeyName( String keyName )
    {
        m_resourceKeyName = keyName;
    }

    /**
     * DOCUMENT_ME
     *
     * @return DOCUMENT_ME
     */
    public String getResourceKeyName()
    {
        return m_resourceKeyName;
    }

    /**
     * DOCUMENT_ME
     *
     * @param serviceClass DOCUMENT_ME
     */
    public void setServiceClass( String serviceClass )
    {
        m_serviceClassName = serviceClass;
    }

    /**
     * DOCUMENT_ME
     *
     * @param className DOCUMENT_ME
     */
    public void setServiceClassName( String className )
    {
        m_serviceClassName = className;
    }

    /**
     * DOCUMENT_ME
     *
     * @return DOCUMENT_ME
     */
    public String getServiceClassName()
    {
        return m_serviceClassName;
    }

    /**
     * DOCUMENT_ME
     *
     * @param delay DOCUMENT_ME
     */
    public void setSweeperDelay( long delay )
    {
        m_sweeperDelay = delay;
    }

    /**
     * DOCUMENT_ME
     *
     * @return DOCUMENT_ME
     */
    public long getSweeperDelay()
    {
        return m_sweeperDelay;
    }

    /**
     * DOCUMENT_ME
     *
     * @param targetNamespace DOCUMENT_ME
     */
    public void setWsdlTargetNamespace( String targetNamespace )
    {
        m_wsdlTargetNamespace = targetNamespace;
    }

    /**
     * DOCUMENT_ME
     *
     * @return DOCUMENT_ME
     */
    public String getWsdlTargetNamespace()
    {
        return m_wsdlTargetNamespace;
    }

    /**
     * DOCUMENT_ME
     *
     * @param key DOCUMENT_ME
     *
     * @return DOCUMENT_ME
     *
     * @throws ResourceException           if
     * @throws InvalidResourceKeyException DOCUMENT_ME
     */
    public Resource find( ResourceKey key )
            throws ResourceException
    {

        LOG.debug( MSG.getMessage( Keys.FINDING_RESOURCE_WITH_KEY, String.valueOf( key ) ) );

        Resource resource = null;
        Lock lock = getLock( key );
        try
        {
            lock.acquire();
        }
        catch ( InterruptedException ie )
        {
            throw new ResourceException( ie );
        }

        try
        {
            resource = get( key );
            if ( m_cache != null )
            {
                m_cache.update( resource );
            }
        }
        finally
        {
            lock.release();
        }

        return resource;
    }

    private Lock getLock( ResourceKey key )
    {
        Lock lock;
        Object lockKey = getLookupKey( key );
        lock = m_lockManager.getLock( lockKey );
        return lock;
    }

    /**
     * DOCUMENT_ME
     *
     * @throws Exception DOCUMENT_ME
     */
    public synchronized void init()
            throws Exception
    {
        LOG.debug( MSG.getMessage( Keys.INIT_HOME ) );
        if ( m_initialized )
        {
            return;
        }

        /*if ( m_resourceKeyClassName == null )
           {
              m_resourceKeyClassName = String.class;
           }
         */


        if ( m_resourceClassName == null )
        {
            throw new Exception( MSG.getMessage( Keys.RESOURCE_CLASSNAME_NULL ) );
        }

        /*  if ( !Resource.class.isAssignableFrom( m_resourceClassName ) )
           {
              throw new Exception( "invalidResourceType: " + m_resourceClassName.getName() );
           }
           if ( PersistenceCallback.class.isAssignableFrom( m_resourceClassName ) )
           {
              m_resourceIsPersistent = true;
           }*/
        Context initialContext = new InitialContext();
        initResourceMap( initialContext );
        m_lockManager = new LockManager();
        if ( ScheduledResourceTerminationResource.class.isAssignableFrom( getResourceClass() ) )
        {
            initSweeper( initialContext );
        }

        m_initialized = true;
    }

    /**
     * DOCUMENT_ME
     *
     * @param key DOCUMENT_ME
     *
     * @throws ResourceException           DOCUMENT_ME
     * @throws InvalidResourceKeyException DOCUMENT_ME
     */
    public void remove( ResourceKey key )
            throws ResourceException
    {

        Resource resource = null;
        Lock lock = getLock( key );
        try
        {
            lock.acquire();
        }
        catch ( InterruptedException ie )
        {
            throw new ResourceException( ie );
        }

        try
        {
            resource = get( key );

            try
            {
                resource.destroy();
            }
            catch ( RuntimeException re )
            {
                throw new ResourceException( MSG.getMessage( Keys.FAILED_TO_DESTROY_RESOURCE, resource, re ) );
            }

            m_resources.remove( getLookupKey( key ) );
            notifyResourceDeletedListeners( resource.getEndpointReference() );

            LOG.debug( MSG.getMessage( Keys.REMOVED_RESOURCE_WITH_KEY, resource.getClass().getName(),
                    String.valueOf( key ) ) );
            if ( m_cache != null )
            {
                m_cache.remove( resource );
            }
        }
        finally
        {
            lock.release();
        }

    }

    /**
     * DOCUMENT_ME
     *
     * @param key      DOCUMENT_ME
     * @param resource DOCUMENT_ME
     */
    protected void add( ResourceKey key,
                        Resource resource )
    {
        // TODO: why do we need add() in addition to addResource()?
        addResource( key, resource );
        if ( m_cache != null )
        {
            m_cache.update( resource );
        }
    }

    /**
     * This method uses reflection to create an instance of a Resource which contains an empty constructor.  It will not
     * work with Resources which do not have an empty constructor.
     * <p/>
     * Note: the returned Resource will not have an EndpointReference associated with it. The caller should next call
     * getEndpointReference and then use a setter on their resource impl.
     *
     * @param key The resource key for this resource.
     *
     * @return The resource type which is associated with this home.
     *
     * @throws ResourceException
     * @throws IllegalStateException
     */
    protected Resource createInstance( ResourceKey key )
            throws ResourceException
    {
        LOG.debug( MSG.getMessage( Keys.CREATING_INSTANCE_WITH_KEY, String.valueOf( key ) ) );
        Resource resource;
        try
        {
            resource = (Resource) getResourceClass().newInstance();
        }
        catch ( Exception e )
        {
            throw new ResourceException( e );
        }

        resource.setID( key != null ? key.getValue() : null );

        try
        {
            LOG.debug( MSG.getMessage( Keys.INIT_RESOURCE_LIFECYCLE_INSTANCE, resource.getClass().getName() ) );
            resource.init();
        }
        catch ( RuntimeException re )
        {
            throw new ResourceException( MSG.getMessage( Keys.FAILED_TO_INIT_RESOURCE, resource, re ), re );
        }

        return resource;
    }

    /**
     * DOCUMENT_ME
     *
     * @param key DOCUMENT_ME
     *
     * @return DOCUMENT_ME
     *
     * @throws ResourceException DOCUMENT_ME
     */
    protected Resource createNewInstanceAndLoad( ResourceKey key )
            throws ResourceException
    {
        Resource resource = createInstance( key );
        LOG.debug( MSG.getMessage( Keys.LOADING_RESOURCE_FROM_PERSISTENCE, String.valueOf( key ) ) );
        ( (PersistenceCallback) resource ).load( key );
        if ( ResourceSweeper.isExpired( resource ) )
        {
            throw new ResourceUnknownException( getLookupKey( key ), getServicePortName() );
        }
        return resource;
    }

    private Class getResourceClass()
            throws ResourceException
    {
        if ( m_resourceClass == null )
        {
            if ( m_resourceClassName == null )
            {
                throw new IllegalStateException( MSG.getMessage( Keys.RESOURCE_CLASSNAME_NULL ) );
            }
            try
            {
                m_resourceClass = Class.forName( m_resourceClassName );
            }
            catch ( ClassNotFoundException cnfe )
            {
                throw new ResourceException( MSG.getMessage( Keys.RESOURCE_CLASS_NOT_FOUND, m_resourceClassName ) );
            }
        }
        return m_resourceClass;
    }

    private void addResource( ResourceKey key,
                              Resource resource )
    {
        LOG.debug( MSG.getMessage( Keys.ADDING_RESOURCE_FOR_KEY, String.valueOf( key ) ) );
        m_resources.put( getLookupKey( key ), resource );
        // schedule sweeper task if needed
        if ( m_sweeper != null )
        {
            m_sweeper.schedule();
        }
        notifyResourceCreatedListeners( resource.getEndpointReference() );
    }

    private Resource get( ResourceKey key )
            throws ResourceException
    {
        LOG.debug( MSG.getMessage( Keys.GET_RESOURCE_FOR_KEY, String.valueOf( key ) ) );
        Object lookupKey = getLookupKey( key );
        Resource resource = (Resource) m_resources.get( lookupKey );
        if ( resource == null )
        {
            if ( !m_resourceIsPersistent )
            {
                throw new ResourceUnknownException( lookupKey, getServicePortName() );
            }
            addResource( key, createNewInstanceAndLoad( key ) );
        }
        return resource;
    }

    private Object getLookupKey( ResourceKey key )
    {
        Object lookupKey = key != null ? key : (Object) this;
        return lookupKey;
    }

    private void initCachePolicy( Context initialContext )
            throws NamingException
    {
        if ( m_cacheLocation != null )
        {
            m_cache = (Cache) JNDIUtils.lookup( initialContext, m_cacheLocation, Cache.class );
        }
    }

    private void initResourceMap( Context initialContext )
            throws NamingException
    {
        if ( m_resourceIsPersistent )
        {
            m_resources = new ReferenceMap( ReferenceMap.HARD, ReferenceMap.SOFT, true );
            initCachePolicy( initialContext );
        }
        else
        {
            m_resources = new HashMap();
        }
        m_resources = Collections.synchronizedMap( m_resources );
    }

    private void initSweeper( Context initialContext )
            throws NamingException
    {
        LOG.debug( MSG.getMessage( Keys.TIMER_LOOKUP_WITH_JNDI_NAME, JndiConstants.KEY_NAME_DEFAULT_TIMER ) );
        TimerManager timerManager = (TimerManager) initialContext.lookup( JndiConstants.KEY_NAME_DEFAULT_TIMER );

        // TimerManager timerManager = new TimerManagerImpl();
        m_sweeper = new Sweeper( this, m_resources, timerManager, m_sweeperDelay );
    }

    /**
     * This ResourceSweeper implementation just returns the resources currently stored in the map. The reason is that
     * the sweeper doesn't have to reactivate/reload a persistent resource if the resource object was reclaimed. So
     * lifetime checks are not done on reclained resources. Lifetime checks have to be done on resource load.
     */
    private static class Sweeper
            extends ResourceSweeper
    {
        private TimerManager m_timerManager;
        private Timer m_timer;
        private long m_delay;

        /**
         * Creates a new {@link Sweeper} object.
         *
         * @param home         DOCUMENT_ME
         * @param resources    DOCUMENT_ME
         * @param timerManager DOCUMENT_ME
         * @param delay        DOCUMENT_ME
         */
        public Sweeper( ResourceHome home,
                        Map resources,
                        TimerManager timerManager,
                        long delay )
        {
            super( home, resources );
            m_timerManager = timerManager;
            m_delay = delay;
        }

        /**
         * DOCUMENT_ME
         *
         * @param timer DOCUMENT_ME
         */
        public void timerExpired( Timer timer )
        {
            super.timerExpired( timer );
            cancel();
            if ( !m_resources.isEmpty() )
            {
                schedule();
            }
        }

        /**
         * DOCUMENT_ME
         *
         * @param key DOCUMENT_ME
         *
         * @return DOCUMENT_ME
         *
         * @throws ResourceException DOCUMENT_ME
         */
        protected Resource getResource( ResourceKey key )
                throws ResourceException
        {
            LOG.debug( MSG.getMessage( Keys.GET_RESOURCE_FOR_KEY, key.getValue() ) );
            return (Resource) m_resources.get( key );
        }

        /**
         * Schedules this resource sweeper.
         */
        synchronized void schedule()
        {
            if ( m_timer == null )
            {
                LOG.debug( MSG.getMessage( Keys.SCHEDULE_RESOURCE_SWEEPER ) );
                m_timer = m_timerManager.schedule( this, m_delay );
            }
        }

        /**
         * Cancels this resource sweeper.
         */
        private synchronized void cancel()
        {
            if ( m_timer != null )
            {
                LOG.debug( MSG.getMessage( Keys.CANCEL_RESOURCE_SWEEPER ) );
                m_timer = null;
            }
        }
    }

    /**
     * Adds a listener for ResourceCreationEvents
     *
     * @param listener
     */
    public void addResourceCreationListener( ResourceCreationListener listener )
    {
        m_creationListeners.add( listener );
    }

    /**
     * Adds a listener for ResourceDestructionEvents
     *
     * @param listener
     */
    public void addResourceDestructionListener( ResourceDestructionListener listener )
    {
        m_destructionListeners.add( listener );
    }

    /**
     * Removes a listener for ResourceCreationEvents
     *
     * @param listener
     *
     * @return true if the listener was removed, else false
     */
    public boolean removeResourceCreationListener( ResourceCreationListener listener )
    {
        return m_creationListeners.remove( listener );
    }

    /**
     * Removes a listener for ResourceDestructionEvents
     *
     * @param listener
     *
     * @return true if the listener was removed, else false
     */
    public boolean removeResourceDestructionListener( ResourceDestructionListener listener )
    {
        return m_destructionListeners.remove( listener );
    }

    /**
     * This method is used to notify listeners a resource has been created.
     *
     * @param epr The EndpointReference for the Resource which was created
     */
    private void notifyResourceCreatedListeners( EndpointReference epr )
    {
        for ( int i = 0; i < m_creationListeners.size(); i++ )
        {
            ResourceCreationListener resourceCreationListener = (ResourceCreationListener) m_creationListeners.get( i );
            resourceCreationListener.creationOccurred( new ResourceCreationEvent( epr ) );
        }
    }

    /**
     * This method is used to notify listeners a resource has been deleted.
     *
     * @param epr The EndpointReference for the Resource which was created
     */
    private void notifyResourceDeletedListeners( EndpointReference epr )
    {
        for ( int i = 0; i < m_destructionListeners.size(); i++ )
        {
            ResourceDestructionListener resourceDestructionListener = (ResourceDestructionListener) m_destructionListeners.get(
                    i );
            resourceDestructionListener.destructionOccurred( new ResourceDestructionEvent( epr ) );
        }
    }

    /**
     * Returns the EndpointReference associated with this Resource. Only the required fields will be filled in (i.e.
     * Address) AND the ReferenceProperty for the ResourceKey (if not a singleton)
     * <p/>
     * If the resourceKeyis not equal to null ( not a singleton ), The reference properties will contain the key.
     *
     * @param endpointAddress The endpoint url for the service
     * @param key             The resourceKey for the Resource or null if singleton
     * @param wsAddressingURI The WS-Addressing URI
     *
     * @return The Resource's EndpointReference
     */
    public EndpointReference getEndpointReference( String endpointAddress, ResourceKey key, String wsAddressingURI )
    {
        XmlBeansEndpointReference xmlBeansEndpointReference = new XmlBeansEndpointReference( endpointAddress,
                wsAddressingURI );
        xmlBeansEndpointReference.setResourceKey( key );
        xmlBeansEndpointReference.setPortTypeQName( getPortType() );
        xmlBeansEndpointReference.setServicePortName( getServicePortName() );
        xmlBeansEndpointReference.setServiceQName( getServiceName() );
        return xmlBeansEndpointReference;
    }

    public abstract QName getServiceName();

    public abstract QName getPortType();

    public abstract String getServicePortName();

    public abstract QName getResourceKeyNameQName();

}
TOP

Related Classes of org.apache.ws.resource.impl.AbstractResourceHome$Sweeper

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.