/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.muse.ws.notification.impl;
import java.util.Date;
import javax.xml.namespace.QName;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.apache.muse.core.Environment;
import org.apache.muse.core.serializer.SerializerRegistry;
import org.apache.muse.util.LoggingUtils;
import org.apache.muse.util.messages.Messages;
import org.apache.muse.util.messages.MessagesFactory;
import org.apache.muse.util.xml.XmlUtils;
import org.apache.muse.ws.addressing.EndpointReference;
import org.apache.muse.ws.notification.Filter;
import org.apache.muse.ws.notification.NotificationMessage;
import org.apache.muse.ws.notification.Policy;
import org.apache.muse.ws.notification.SubscriptionManager;
import org.apache.muse.ws.notification.WsnConstants;
import org.apache.muse.ws.notification.remote.NotificationConsumerClient;
import org.apache.muse.ws.resource.impl.AbstractWsResourceCapability;
import org.apache.muse.ws.addressing.soap.SoapFault;
/**
*
* SimpleSubscriptionManager is Muse's default implementation of the
* WS-Notification SubscriptionManager port type. It uses the
* {@linkplain NotificationConsumerClient NotificationConsumerClient class}
* to send messages to its subscribers. It also provides an initialization
* flag, <em>trace-notifications</em> that allows users to turn on tracing
* for the outgoing notification messages (the default is 'false').
* <br><br>
* This implementation does not support subscription policies.
*
* @author Dan Jemiolo (danj)
*
*/
public class SimpleSubscriptionManager
extends AbstractWsResourceCapability implements SubscriptionManager
{
//
// Used to lookup all exception messages
//
private static Messages _MESSAGES = MessagesFactory.get(SimpleSubscriptionManager.class);
//
// init. param used to turn on SOAP tracing for notifications
//
private static final String _TRACE_PARAM = "trace-notifications";
//
// init. param used to re-try notifications that fail
//
private static final String _TRY_PARAM = "number-of-tries";
//
// init. param used to destroy subscriptions if notifications fail
//
private static final String _DESTROY_PARAM = "destroy-on-failure";
//
// The client that is used to publish messages to the consumer
//
private NotificationConsumerClient _client = null;
//
// EPR of the resource receiving our messages
//
private EndpointReference _consumer = null;
//
// When was the subscription created? Right now!
//
private Date _creationTime = new Date();
//
// The filter will approve of messages that are published
//
private Filter _filter = null;
private boolean _isDestroyedOnFailure = false;
private boolean _isPaused = false;
private boolean _isUsingTrace = false;
//
// number of times to try a notification before giving up
//
private int _numberOfTries = 1;
//
// EPR of the resource using this capability
//
private EndpointReference _producer = null;
/**
*
* Users can override this method to provide a different implementation of
* the WS-N client class without changing the implementation of subscription
* management.
*
* @return An instance of NotificationConsumerClient.
*
*/
protected NotificationConsumerClient createConsumerClient()
{
EndpointReference consumer = getConsumerReference();
EndpointReference producer = getProducerReference();
Environment env = getEnvironment();
NotificationConsumerClient client = new NotificationConsumerClient(consumer, producer, env);
client.setTrace(isUsingTrace());
return client;
}
protected synchronized NotificationConsumerClient getConsumerClient()
{
if (_client == null)
_client = createConsumerClient();
return _client;
}
public EndpointReference getConsumerReference()
{
return _consumer;
}
public Date getCreationTime()
{
return _creationTime;
}
public Filter getFilter()
{
return _filter;
}
protected int getNumberOfTries()
{
return _numberOfTries;
}
public EndpointReference getProducerReference()
{
return _producer;
}
public QName[] getPropertyNames()
{
return PROPERTIES;
}
/**
*
* This implementation always returns null.
*
*/
public Policy getSubscriptionPolicy()
{
return null;
}
public void initialize()
throws SoapFault
{
super.initialize();
//
// add filter serializer so that clients can change filters
// via WSRP SetRP if needed
//
SerializerRegistry.getInstance().registerSerializer(Filter.class, new FilterSerializer());
//
// turn on tracing for notifications, if desired
//
String traceString = getInitializationParameter(_TRACE_PARAM);
if (traceString != null)
_isUsingTrace = Boolean.valueOf(traceString).booleanValue();
//
// allow for notification re-tries, if desired
//
String retryString = getInitializationParameter(_TRY_PARAM);
if (retryString != null)
_numberOfTries = Integer.valueOf(retryString).intValue();
if (_numberOfTries <= 0)
throw new RuntimeException(_MESSAGES.get("InvalidNumberOfTries"));
//
// allow for subscription destruction on failure, if desired
//
String destroyString = getInitializationParameter(_DESTROY_PARAM);
if (destroyString != null)
_isDestroyedOnFailure = Boolean.valueOf(destroyString).booleanValue();
}
protected synchronized boolean isDestroyedOnFailure()
{
return _isDestroyedOnFailure;
}
public synchronized boolean isPaused()
{
return _isPaused;
}
protected boolean isUsingTrace()
{
return _isUsingTrace;
}
public synchronized void pauseSubscription()
{
_isPaused = true;
}
public void publish(NotificationMessage message)
{
if (isPaused() || !getFilter().accepts(message))
return;
//
// set EPRs for this publication
//
message.setProducerReference(getProducerReference());
message.setSubscriptionReference(getResource().getEndpointReference());
boolean success = false;
int tries = getNumberOfTries();
for (int n = 0; n < tries && !success; ++n)
{
try
{
NotificationConsumerClient client = getConsumerClient();
client.notify(new NotificationMessage[]{ message });
success = true;
}
catch (SoapFault error)
{
LoggingUtils.logError(getLog(), error);
Object[] filler = { error.getMessage() };
getLog().info(_MESSAGES.get("LastPublishFailed", filler));
}
}
try
{
if (!success && isDestroyedOnFailure())
getResource().shutdown();
}
catch (SoapFault error)
{
LoggingUtils.logError(getLog(), error);
}
}
public synchronized void resumeSubscription()
{
_isPaused = false;
}
public void setConsumerReference(EndpointReference consumer)
{
if (consumer == null)
throw new NullPointerException(_MESSAGES.get("NullConsumerEPR"));
_consumer = consumer;
}
public void setFilter(Filter filter)
{
_filter = filter;
}
public void setProducerReference(EndpointReference producer)
{
if (producer == null)
throw new NullPointerException(_MESSAGES.get("NullProducerEPR"));
_producer = producer;
}
/**
*
* Logs a warning message that this feature is not supported.
*
*/
public void setSubscriptionPolicy(Policy policy)
{
Object[] filler = { policy };
getLog().warning(_MESSAGES.get("PolicyNotSupported", filler));
}
public Element toXML()
{
return toXML(XmlUtils.EMPTY_DOC);
}
public Element toXML(Document doc)
{
Element root = XmlUtils.createElement(doc, WsnConstants.SUBSCRIBE_QNAME);
EndpointReference sub = getWsResource().getEndpointReference();
EndpointReference consumer = getConsumerReference();
EndpointReference producer = getProducerReference();
Filter filter = getFilter();
XmlUtils.setElement(root, WsnConstants.SUBSCRIPTION_EPR_QNAME, sub);
XmlUtils.setElement(root, WsnConstants.CONSUMER_QNAME, consumer);
XmlUtils.setElement(root, WsnConstants.PRODUCER_QNAME, producer);
XmlUtils.setElement(root, WsnConstants.FILTER_QNAME, filter);
return root;
}
}