/*=============================================================================*
* 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.notification.base.impl;
import org.apache.commons.id.IdentifierUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.Soap1_1Constants;
import org.apache.ws.addressing.EndpointReference;
import org.apache.ws.notification.base.NotificationProducerResource;
import org.apache.ws.notification.base.Subscription;
import org.apache.ws.notification.topics.Topic;
import org.apache.ws.notification.topics.TopicListener;
import org.apache.ws.notification.topics.TopicListenerList;
import org.apache.ws.notification.topics.TopicSpaceSet;
import org.apache.ws.notification.topics.expression.TopicExpression;
import org.apache.ws.notification.topics.expression.TopicExpressionException;
import org.apache.ws.notification.topics.impl.SubscriptionTopicListener;
import org.apache.ws.pubsub.Filter;
import org.apache.ws.pubsub.NotificationConsumer;
import org.apache.ws.pubsub.NotificationProducer;
import org.apache.ws.resource.PersistentResource;
import org.apache.ws.resource.PropertiesResource;
import org.apache.ws.resource.Resource;
import org.apache.ws.resource.ResourceException;
import org.apache.ws.resource.ResourceHome;
import org.apache.ws.resource.faults.FaultException;
import org.apache.ws.resource.lifetime.ResourceTerminationEvent;
import org.apache.ws.resource.lifetime.ResourceTerminationListener;
import org.apache.ws.resource.lifetime.impl.ResourceTerminationEventImpl;
import org.apache.ws.resource.properties.ResourcePropertySet;
import org.apache.ws.resource.properties.query.QueryExpression;
import javax.naming.InitialContext;
import java.net.URI;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
/**
* An Abstract Base class for Subscription Implementations.
*/
public abstract class AbstractSubscription
implements Subscription,
PropertiesResource
{
private static final Log LOG = LogFactory.getLog( AbstractSubscription.class );
/** DOCUMENT_ME */
protected EndpointReference m_consumerReference;
/** DOCUMENT_ME */
protected EndpointReference m_producerReference;
/** DOCUMENT_ME */
protected Object m_policy;
/** DOCUMENT_ME */
protected QueryExpression m_precondition;
/** DOCUMENT_ME */
protected QueryExpression m_selector;
/** DOCUMENT_ME */
protected String m_producerHomeLocation;
/** DOCUMENT_ME */
protected TopicExpression m_topicExpression;
/** DOCUMENT_ME */
protected boolean m_isPaused;
/** DOCUMENT_ME */
protected boolean m_useNotify = true;
/** DOCUMENT_ME */
protected Calendar m_terminationTime;
/** DOCUMENT_ME */
protected Calendar m_creationTime;
/** DOCUMENT_ME */
protected String m_id;
/** DOCUMENT_ME */
protected EndpointReference m_epr;
/** DOCUMENT_ME */
protected transient ResourcePropertySet m_propSet;
private NotificationConsumer m_notificationConsumer;
private NotificationProducer m_notificationProducer;
/**
* A list of termination listeners to be notified when the resource is terminated.
*/
private List m_terminationListeners = new ArrayList( );
private Object m_producerId;
/**
* Construct a new subscription resource.
*
* @param consumerReference The WS-Addressing endpoint reference of the consumer
* @param producerReference The WS-Addressing endpoint reference of the producer
* @param producerHomeLocation The JNDI location of the home of the producer resource
* @param topicExpression The topic expression for this subscription
*/
public AbstractSubscription( EndpointReference consumerReference,
EndpointReference producerReference,
String producerHomeLocation,
Object producerId,
TopicExpression topicExpression )
{
m_id = IdentifierUtils.UUID_VERSION_FOUR_GENERATOR.nextIdentifier( ).toString( );
m_consumerReference = consumerReference;
m_producerReference = producerReference;
m_producerHomeLocation = producerHomeLocation;
m_producerId = producerId;
m_topicExpression = topicExpression;
m_creationTime = Calendar.getInstance( );
}
/**
* Creates a new {@link AbstractSubscription} object.
*/
public AbstractSubscription( )
{
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public EndpointReference getConsumerReference( )
{
return m_consumerReference;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public Calendar getCreationTime( )
{
return m_creationTime;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public Calendar getCurrentTime( )
{
return Calendar.getInstance( );
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public URI getDeliveryMode( )
{
// TODO. *SJC* This is provided for pubsub abstraction layer
return null;
}
/**
* DOCUMENT_ME
*
* @param epr DOCUMENT_ME
*/
public void setEndpointReference( EndpointReference epr )
{
m_epr = epr;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public EndpointReference getEndpointReference( )
{
return m_epr;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public Filter getFilters( )
{
// TODO. *SJC* This is provided for pubsub abstraction layer
return null;
}
/**
* DOCUMENT_ME
*
* @param id DOCUMENT_ME
*/
public void setID( Object id )
{
m_id = (String) id;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public Object getID( )
{
return m_id;
}
/**
* DOCUMENT_ME
*
* @param notificationConsumer DOCUMENT_ME
*/
public void setNotificationConsumer( NotificationConsumer notificationConsumer )
{
m_notificationConsumer = notificationConsumer;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public NotificationConsumer getNotificationConsumer( )
{
return m_notificationConsumer;
}
/**
* DOCUMENT_ME
*
* @param notificationProducer DOCUMENT_ME
*/
public void setNotificationProducer( NotificationProducer notificationProducer )
{
m_notificationProducer = notificationProducer;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public NotificationProducer getNotificationProducer( )
{
return m_notificationProducer;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public boolean isPaused( )
{
return m_isPaused;
}
/**
* DOCUMENT_ME
*
* @param policy DOCUMENT_ME
*/
public void setPolicy( Object policy )
{
m_policy = policy;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public Object getPolicy( )
{
return m_policy;
}
/**
* DOCUMENT_ME
*
* @param precondition DOCUMENT_ME
*/
public void setPrecondition( QueryExpression precondition )
{
m_precondition = precondition;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public QueryExpression getPrecondition( )
{
return m_precondition;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public EndpointReference getProducerReference( )
{
return m_producerReference;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public NotificationProducerResource getProducerResource( )
{
try
{
ResourceHome producerHome = (ResourceHome) new InitialContext( ).lookup( m_producerHomeLocation );
return (NotificationProducerResource) producerHome.find( m_producerId );
}
catch ( Exception e )
{
throw new RuntimeException( "Failed to lookup NotificationProducer resource due to internal error: " + e,
e );
}
}
/**
* DOCUMENT_ME
*
* @param resourcePropertySet DOCUMENT_ME
*/
public void setResourcePropertySet( ResourcePropertySet resourcePropertySet )
{
m_propSet = resourcePropertySet;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public ResourcePropertySet getResourcePropertySet( )
{
return m_propSet;
}
/**
* DOCUMENT_ME
*
* @param selector DOCUMENT_ME
*/
public void setSelector( QueryExpression selector )
{
m_selector = selector;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public QueryExpression getSelector( )
{
return m_selector;
}
/**
* DOCUMENT_ME
*
* @param time DOCUMENT_ME
*/
public void setTerminationTime( Calendar time )
{
m_terminationTime = time;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public Calendar getTerminationTime( )
{
return m_terminationTime;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public TopicExpression getTopicExpression( )
{
return m_topicExpression;
}
/**
* DOCUMENT_ME
*
* @param useNotify DOCUMENT_ME
*/
public void setUseNotify( boolean useNotify )
{
m_useNotify = useNotify;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public boolean getUseNotify( )
{
return m_useNotify;
}
/**
* DOCUMENT_ME
*
* @param resourceTerminationListener DOCUMENT_ME
*/
public void addTerminationListener( ResourceTerminationListener resourceTerminationListener )
{
m_terminationListeners.add( resourceTerminationListener );
}
/**
* DOCUMENT_ME
*/
public void destroy( )
{
Resource producerResource = null;
try
{
producerResource = getProducerResource( );
}
catch ( Exception e )
{
;
}
if ( !( producerResource instanceof NotificationProducerResource ) )
{
return;
}
Topic[] topics = null;
topics = evaluateTopicExpression( );
synchronized ( producerResource )
{
//removes listeners from the topics
boolean removed = removeListener( topics );
//persists the resource
if ( removed && producerResource instanceof PersistentResource )
{
try
{
( (PersistentResource) producerResource ).store( );
}
catch ( ResourceException e )
{
LOG.debug( "Unable to persist the resource: " + producerResource + " with id: "
+ producerResource.getID( ), e );
}
}
}
//notify listeners that this subscription expired.
ResourceTerminationEvent rte = new ResourceTerminationEventImpl( getID( ),
"Subscription Destroyed" );
for ( int i = 0; i < m_terminationListeners.size( ); i++ )
{
ResourceTerminationListener resourceTerminationListener =
(ResourceTerminationListener) m_terminationListeners.get( i );
resourceTerminationListener.terminationOccurred( rte );
}
}
/**
* DOCUMENT_ME
*
* @throws Exception DOCUMENT_ME
*/
public void pause( )
throws Exception
{
m_isPaused = true;
}
/**
* DOCUMENT_ME
*
* @throws Exception DOCUMENT_ME
*/
public void resume( )
throws Exception
{
m_isPaused = false;
}
/**
* DOCUMENT_ME
*/
public void unsubscribe( )
{
destroy( );
}
private Topic[] evaluateTopicExpression( )
{
NotificationProducerResource resource = (NotificationProducerResource) getProducerResource( );
TopicSpaceSet topicSpaceSet = resource.getTopicSpaceSet( );
try
{
return topicSpaceSet.evaluateTopicExpression( m_topicExpression );
}
catch ( TopicExpressionException e )
{
LOG.debug( "Failed to evaluate TopicExpression.", e );
throw new FaultException( Soap1_1Constants.FAULT_CLIENT,
"An exception occurred evaluating the topic expression. " );
}
}
private boolean removeListener( Topic[] topics )
{
boolean removed = false;
for ( int i = 0; i < topics.length; i++ )
{
TopicListenerList topicListenerList = topics[i];
synchronized ( topicListenerList )
{
Iterator topicListenerIterator = topicListenerList.topicListenerIterator( );
while ( topicListenerIterator.hasNext( ) )
{
TopicListener listener = (TopicListener) topicListenerIterator.next( );
if ( listener instanceof SubscriptionTopicListener )
{
SubscriptionTopicListener lt = (SubscriptionTopicListener) listener;
Object subKey = lt.getSubscription( ).getID( );
if ( subKey.equals( m_id ) )
{
topicListenerIterator.remove( );
removed = true;
}
}
}
}
}
return removed;
}
}