/*
* 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.mq;
import hermes.Domain;
import hermes.Hermes;
import hermes.HermesAdmin;
import hermes.HermesException;
import hermes.browser.MessageRenderer;
import hermes.config.DestinationConfig;
import hermes.ext.HermesAdminSupport;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.WeakHashMap;
import javax.jms.JMSException;
import javax.jms.Message;
import org.apache.log4j.Logger;
import com.ibm.mq.MQC;
import com.ibm.mq.MQEnvironment;
import com.ibm.mq.MQException;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.MQSecurityExit;
import com.ibm.mq.jms.MQConnectionFactory;
import com.ibm.mq.jms.MQQueueEnumeration;
import com.ibm.mq.pcf.CMQC;
import com.ibm.mq.pcf.CMQCFC;
import com.ibm.mq.pcf.PCFException;
import com.ibm.mq.pcf.PCFMessage;
import com.ibm.mq.pcf.PCFMessageAgent;
/**
* @author colincrist@hermesjms.com
* @version $Id: MQSeriesAdmin.java,v 1.17 2006/07/13 07:35:35 colincrist Exp $
*/
public class MQSeriesAdmin extends HermesAdminSupport implements HermesAdmin
{
private static final Logger log = Logger.getLogger(MQSeriesAdmin.class);
private static Field baseMessageField;
private MQQueueManager queueManager;
private MQConnectionFactory mqCF;
private MQSeriesMessageRenderer messageRenderer = new MQSeriesMessageRenderer(this);
private WeakHashMap jmsToNativeMap = new WeakHashMap();
static
{
try
{
baseMessageField = MQQueueEnumeration.class.getDeclaredField("baseMessage");
baseMessageField.setAccessible(true);
}
catch (Throwable t)
{
log.error("cannot location baseMessage field in MQEnumeration, access to native messags unavailable");
}
}
/**
*
*/
public MQSeriesAdmin(Hermes hermes, MQConnectionFactory mqCF)
{
super(hermes);
this.mqCF = mqCF;
// log.debug("session to " + hermes.getId()) ;
}
private synchronized MQQueueManager getQueueManager() throws Exception
{
if (queueManager == null)
{
MQEnvironment.channel = mqCF.getChannel();
MQEnvironment.port = mqCF.getPort();
MQEnvironment.hostname = mqCF.getHostName();
MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES);
if (mqCF.getSecurityExit() != null) {
Class clazz = getClass().getClassLoader().loadClass(mqCF.getSecurityExit()) ;
MQSecurityExit securityExit = null ;
if (mqCF.getSecurityExitInit() != null) {
securityExit = (MQSecurityExit) clazz.getConstructor(String.class).newInstance(mqCF.getSecurityExitInit()) ;
} else {
securityExit = (MQSecurityExit) clazz.newInstance() ;
}
MQEnvironment.securityExit = securityExit ;
}
queueManager = new MQQueueManager(mqCF.getQueueManager());
}
return queueManager;
}
public Enumeration createBrowserProxy(final Enumeration iter) throws JMSException
{
if (false)
{
final MQQueueEnumeration mqEnum = (MQQueueEnumeration) iter;
return new Enumeration()
{
public boolean hasMoreElements()
{
return iter.hasMoreElements();
}
public Object nextElement()
{
final Message m = (Message) iter.nextElement();
try
{
if (baseMessageField != null)
{
final Object o = baseMessageField.get(iter);
if (o instanceof MQMessage)
{
synchronized (jmsToNativeMap)
{
jmsToNativeMap.put(m, new WeakReference(o));
}
}
}
}
catch (Throwable e)
{
log.error(e.getMessage(), e);
}
return m;
}
};
}
else
{
return iter;
}
}
MQMessage getMQMessage(Message m) throws JMSException
{
synchronized (jmsToNativeMap)
{
if (jmsToNativeMap.containsKey(m))
{
WeakReference ref = (WeakReference) jmsToNativeMap.get(m);
return (MQMessage) ref.get();
}
else
{
throw new JMSException("No reference found to native message");
}
}
}
@Override
public String getRealDestinationName(DestinationConfig dConfig) throws JMSException
{
String queueName = super.getRealDestinationName(dConfig);
if (queueName.startsWith("queue:///"))
{
queueName = queueName.substring(9);
}
if (queueName.indexOf("?") != -1)
{
queueName = queueName.substring(0, queueName.indexOf("?"));
}
log.debug("real name=" + queueName);
return queueName;
}
/*
* (non-Javadoc)
*
* @see hermes.ProviderExtensionSession#size(javax.jms.Destination)
*/
public int getDepth(DestinationConfig dConfig) throws JMSException
{
try
{
final String queueName = getRealDestinationName(dConfig);
final MQQueue queue = getQueueManager().accessQueue(queueName, MQC.MQOO_INQUIRE | MQC.MQOO_INPUT_AS_Q_DEF, null, null, null);
final int depth = queue.getCurrentDepth();
queue.close();
return depth;
}
catch (Exception e)
{
close();
throw new HermesException(e);
}
}
/*
* (non-Javadoc)
*
* @see hermes.ProviderExtensionSession#close()
*/
public synchronized void close() throws JMSException
{
try
{
if (queueManager != null)
{
try
{
//
// Do I need both?
queueManager.disconnect();
queueManager.close();
}
finally
{
queueManager = null;
}
}
}
catch (MQException e)
{
throw new HermesException(e);
}
}
private void getQueueByType(PCFMessageAgent agent, int type, Collection destinations) throws PCFException, MQException, IOException
{
final PCFMessage request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q_NAMES);
request.addParameter(CMQC.MQCA_Q_NAME, "*");
request.addParameter(CMQC.MQIA_Q_TYPE, type);
final PCFMessage[] responses = agent.send(request);
final String[] names = (String[]) responses[0].getParameterValue(CMQCFC.MQCACF_Q_NAMES);
for (int i = 0; i < names.length; i++)
{
final DestinationConfig dConfig = new DestinationConfig();
dConfig.setName(names[i].trim());
dConfig.setDomain(Domain.QUEUE.getId());
destinations.add(dConfig);
}
}
public synchronized Collection discoverDestinationConfigs() throws JMSException
{
final Collection rval = new ArrayList();
PCFMessageAgent agent = null;
try
{
agent = new PCFMessageAgent(getQueueManager());
getQueueByType(agent, MQC.MQQT_LOCAL, rval) ;
getQueueByType(agent, MQC.MQQT_ALIAS, rval) ;
}
catch (MQException ex)
{
if (ex.reasonCode != 2033)
{
throw new HermesException(ex) ;
}
else
{
log.debug("PCF calls gave a 2033 reason code, ignoring") ;
}
}
catch (Exception ex)
{
throw new HermesException(ex);
}
finally
{
if (agent != null)
{
try
{
agent.disconnect();
}
catch (MQException e)
{
log.error(e.getMessage(), e);
}
}
}
return rval;
}
public synchronized Map getStatistics(DestinationConfig dConfig) throws JMSException
{
final Map stats = new LinkedHashMap();
MQQueue queue = null ;
try
{
final String queueName = getRealDestinationName(dConfig);
queue = getQueueManager().accessQueue(queueName, MQC.MQOO_INQUIRE | MQC.MQOO_INPUT_AS_Q_DEF, null, null, null);
stats.put("Description", queue.getDescription().trim());
stats.put("CurrentDepth", new Integer(queue.getCurrentDepth()));
stats.put("OpenOutputCount", new Integer(queue.getOpenOutputCount()));
stats.put("OpenInputCount", new Integer(queue.getOpenInputCount()));
if (queue.getInhibitGet() == MQC.MQQA_GET_INHIBITED)
{
stats.put("InhibitGet", Boolean.TRUE);
}
else
{
stats.put("InhibitGet", Boolean.FALSE);
}
if (queue.getInhibitPut() == MQC.MQQA_PUT_INHIBITED)
{
stats.put("InhibitPut", Boolean.TRUE);
}
else
{
stats.put("InhibitPut", Boolean.FALSE);
}
if (queue.getShareability() == MQC.MQQA_SHAREABLE)
{
stats.put("Sharable", Boolean.TRUE);
}
else
{
stats.put("Sharable", Boolean.FALSE);
}
if (queue.getTriggerControl() == MQC.MQTC_ON)
{
stats.put("TriggerControl", Boolean.TRUE);
stats.put("TriggerData", queue.getTriggerData());
stats.put("TriggerDepth", new Integer(queue.getTriggerDepth()));
stats.put("TriggerMessagePriority", new Integer(queue.getTriggerMessagePriority()));
switch (queue.getTriggerType())
{
case MQC.MQTT_NONE:
stats.put("TriggerType", "None");
break;
case MQC.MQTT_DEPTH:
stats.put("TriggerType", "Depth");
break;
case MQC.MQTT_EVERY:
stats.put("TriggerType", "Every");
break;
case MQC.MQTT_FIRST:
stats.put("TriggerType", "First");
break;
default:
stats.put("TriggerType", "Unknown");
}
}
else
{
stats.put("TriggerControl", Boolean.FALSE);
}
stats.put("MaximumDepth", new Integer(queue.getMaximumDepth()));
stats.put("MaximumMessageLength", new Integer(queue.getMaximumMessageLength()));
}
catch (MQException ex)
{
if (ex.reasonCode != 2033)
{
throw new HermesException(ex) ;
}
else
{
log.debug("PCF calls gave a 2033 reason code, ignoring") ;
}
}
catch (Exception ex) {
throw new HermesException(ex) ;
}
finally
{
if (queue != null)
{
try
{
queue.close() ;
}
catch (MQException ex)
{
log.error("ignoring error closing queue: " + ex.getMessage(), ex) ;
}
}
}
return stats ;
}
public MessageRenderer getMessageRenderer() throws JMSException
{
return null;
}
}