/*
* Copyright 2003,2004 Colin Crist
*
* 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 hermes.ext;
import hermes.Domain;
import hermes.Hermes;
import hermes.HermesAdminListener;
import hermes.HermesException;
import hermes.JNDIConnectionFactory;
import hermes.browser.HermesBrowser;
import hermes.browser.MessageRenderer;
import hermes.config.DestinationConfig;
import hermes.impl.TopicBrowser;
import hermes.util.JMSUtils;
import hermes.util.TextUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.QueueBrowser;
import javax.jms.Topic;
import javax.naming.Context;
import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.OperationNotSupportedException;
import javax.swing.ProgressMonitor;
import org.apache.log4j.Logger;
/**
* @author colincrist@hermesjms.com last changed by: $Author: colincrist $
* @version $Id: HermesAdminSupport.java,v 1.1 2004/07/21 19:46:16 colincrist
* Exp $
*/
public abstract class HermesAdminSupport {
private static final Logger log = Logger.getLogger(HermesAdminSupport.class);
private static final Map<String, Object> defaultStatistics = new HashMap<String, Object>();
private final Set<HermesAdminListener> listeners = new HashSet<HermesAdminListener>();
private final List statisticsHeader = new ArrayList();
private final Map destinationConfigs = new HashMap();
private final Hermes hermes;
private boolean isNameInNamespaceCheck = true;
private long ms = 10000;
static {
defaultStatistics.put("Unavailable", "No statistics currently available.");
}
public static Map getDefaultStatistics() {
return defaultStatistics;
}
/**
*
*/
public HermesAdminSupport(Hermes hermes) {
super();
this.hermes = hermes;
}
public void delete(DestinationConfig dConfig, Collection<String> messageIds) throws JMSException, NamingException {
delete(dConfig, messageIds, null);
}
public void delete(DestinationConfig dConfig, Collection<String> messageIds, ProgressMonitor progress) throws JMSException, NamingException {
final Destination d = getHermes().getDestination(dConfig.getName(), Domain.getDomain(dConfig.getDomain()));
final String sql = JMSUtils.createMessageSelectorUsingIn(messageIds);
int deleted = 0;
while (deleted < messageIds.size()) {
Message m = hermes.receive(d, ms, sql);
if (m != null) {
deleted++;
if (progress != null) {
progress.setNote(deleted + " message" + TextUtils.plural(deleted) + " deleted");
progress.setProgress(deleted);
if (progress.isCanceled()) {
hermes.rollback();
return;
}
}
} else {
throw new JMSException("Timeout reading from MessageConsumer to delete messages");
}
}
}
public void addListener(HermesAdminListener listener) {
listeners.add(listener);
}
public void removeListener(HermesAdminListener listener) {
listeners.remove(listener);
}
protected void notifyDestinationAdded(DestinationConfig config) {
for (final HermesAdminListener listener : listeners) {
listener.onDestinationAdded(config);
}
}
protected void notifyDestinationRemoved(DestinationConfig config) {
for (final HermesAdminListener listener : listeners) {
listener.onDestinationRemoved(config);
}
}
public long getAge(DestinationConfig dest) throws JMSException {
long rval = 0;
QueueBrowser browser = hermes.createBrowser(dest);
Enumeration iter = browser.getEnumeration();
if (iter.hasMoreElements()) {
Message topMessage = (Message) iter.nextElement();
if (topMessage != null) {
rval = topMessage.getJMSTimestamp();
}
}
browser.close();
return rval;
}
public abstract int getDepth(DestinationConfig destination) throws JMSException;
public Hermes getHermes() {
return hermes;
}
public int truncate(DestinationConfig dConfig) throws JMSException {
boolean keepRunning = true;
StringBuffer message = new StringBuffer();
int numToDelete = 0;
ProgressMonitor monitor = new ProgressMonitor(HermesBrowser.getBrowser(), "Deleting from " + dConfig.getName(), "Discovering size of " + dConfig.getName(), 0, 102);
monitor.setMillisToDecideToPopup(100);
monitor.setMillisToPopup(400);
try {
QueueBrowser browser = getHermes().createBrowser(dConfig);
Enumeration iter = browser.getEnumeration();
monitor.setProgress(1);
Hermes.ui.getDefaultMessageSink().add("Discovering size of " + dConfig.getName());
while (iter.hasMoreElements() && keepRunning && !monitor.isCanceled()) {
iter.nextElement();
numToDelete++;
}
browser.close();
getHermes().rollback();
if (monitor.isCanceled()) {
keepRunning = false;
}
String message2 = dConfig.getName() + " is already empty.";
if (numToDelete == 1) {
message2 = "Deleting one message from " + dConfig.getName();
} else {
message2 = "Deleting " + numToDelete + " messages from " + dConfig.getName();
}
Hermes.ui.getDefaultMessageSink().add(message2);
monitor.setProgress(2);
final Destination destination = getHermes().getDestination(dConfig.getName(), Domain.getDomain(dConfig.getDomain()));
for (int i = 0; i < numToDelete && keepRunning && !monitor.isCanceled(); i++) {
Message m = null;
while (m == null && keepRunning) {
m = getHermes().receive(destination, 10000);
}
monitor.setNote(new Long(i) + " messages deleted");
float l_i = i;
float l_numToDelete = numToDelete;
int progress = Math.round(2 + ((l_i / l_numToDelete) * 100));
monitor.setProgress(progress);
}
if (monitor.isCanceled()) {
keepRunning = false;
}
if (numToDelete > 0) {
if (keepRunning) {
getHermes().commit();
message.append("Committed. ").append(numToDelete).append(" messages deleted from " + dConfig.getName());
} else {
getHermes().rollback();
message.append("Trucate of ").append(dConfig.getName()).append(" rolled back");
}
}
} catch (Exception ex) {
message.append("During truncate of ").append(dConfig.getName()).append(": ").append(ex.getMessage());
log.error(ex);
} finally {
if (monitor != null) {
monitor.close();
}
}
Hermes.ui.getDefaultMessageSink().add(message);
return numToDelete;
}
public Map getStatistics(DestinationConfig destination) throws JMSException {
return defaultStatistics;
}
public Collection getStatistics(Collection destinations) throws JMSException {
List rval = new ArrayList();
for (Iterator iter = destinations.iterator(); iter.hasNext();) {
DestinationConfig d = (DestinationConfig) iter.next();
rval.add(getStatistics(d));
}
return rval;
}
public Enumeration createBrowserProxy(Enumeration iter) throws JMSException {
return iter;
}
protected Collection discoverDurableSubscriptions(String topicName, String jndiName) throws JMSException {
return new ArrayList();
}
private void discoverDestinationConfigsFromContext(String path, Context ctx, Collection<DestinationConfig> rval, Set<String> visited) throws JMSException {
try {
if (isNameInNamespaceCheck) {
try {
if (visited.contains(ctx.getNameInNamespace())) {
return;
}
visited.add(ctx.getNameInNamespace());
} catch (OperationNotSupportedException ex) {
isNameInNamespaceCheck = false;
}
}
for (final NamingEnumeration iter = ctx.list(""); iter.hasMore();) {
final NameClassPair entry = (NameClassPair) iter.next();
try {
final Object object = ctx.lookup(entry.getName());
DestinationConfig config = null;
if (object instanceof Destination) {
final Domain domain = Domain.getDomain((Destination) object);
if (domain == Domain.QUEUE) {
config = HermesBrowser.getConfigDAO().createDestinationConfig();
config.setDomain(Domain.QUEUE.getId());
} else if (domain == Domain.TOPIC) {
config = HermesBrowser.getConfigDAO().createDestinationConfig();
config.setDomain(Domain.TOPIC.getId());
rval.addAll(discoverDurableSubscriptions(JMSUtils.getDestinationName((Topic) object), path == null ? entry.getName() : path + "/" + entry.getName()));
} else {
config = HermesBrowser.getConfigDAO().createDestinationConfig();
config.setDomain(Domain.UNKNOWN.getId());
}
} else if (object instanceof Context) {
String ctxPath;
if (path == null) {
ctxPath = entry.getName();
} else {
ctxPath = path + "/" + entry.getName();
}
discoverDestinationConfigsFromContext(ctxPath, (Context) object, rval, visited);
}
if (config != null) {
String binding = null;
if (path == null) {
binding = entry.getName();
} else {
binding = path + "/" + entry.getName();
}
config.setName(binding);
rval.add(config);
}
} catch (Throwable ex) {
log.error("discoverDestinationConfig binding=" + entry.getName() + ": " + ex.getMessage(), ex);
}
}
} catch (NamingException e) {
log.error(e.getMessage(), e);
throw new HermesException(e);
}
}
public Collection<DestinationConfig> discoverDestinationConfigs() throws JMSException {
if (hermes.getConnectionFactory() instanceof JNDIConnectionFactory) {
final JNDIConnectionFactory cf = (JNDIConnectionFactory) hermes.getConnectionFactory();
final Collection<DestinationConfig> rval = new ArrayList<DestinationConfig>();
final Context ctx = cf.createContext();
discoverDestinationConfigsFromContext(null, ctx, rval, new HashSet<String>());
return rval;
} else {
throw new HermesException("The default provider extension cannot discover queues or topics on " + hermes.getConnectionFactory().getClass().getName());
}
}
public MessageRenderer getMessageRenderer() throws JMSException {
return null;
}
public QueueBrowser createDurableSubscriptionBrowser(DestinationConfig dConfig) throws JMSException {
return new TopicBrowser(getHermes().getSession(), getHermes().getDestinationManager(), dConfig);
}
public String getRealDestinationName(DestinationConfig dConfig) throws JMSException {
try {
return JMSUtils.getDestinationName(getHermes().getDestination(dConfig.getName(), Domain.getDomain(dConfig.getDomain())));
} catch (NamingException ex) {
throw new HermesException(ex);
}
}
}