All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.messaging.jmq.admin.jmsspi.JMSAdminImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2000, 2020 Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2020, 2022 Contributors to the Eclipse Foundation
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.messaging.jmq.admin.jmsspi;

import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.ERROR;
import static java.lang.System.Logger.Level.INFO;
import static java.lang.System.Logger.Level.WARNING;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

import jakarta.jms.Connection;
import jakarta.jms.DeliveryMode;
import jakarta.jms.ExceptionListener;
import jakarta.jms.InvalidSelectorException;
import jakarta.jms.JMSException;
import jakarta.jms.Message;
import jakarta.jms.ObjectMessage;
import jakarta.jms.Queue;
import jakarta.jms.QueueConnection;
import jakarta.jms.QueueReceiver;
import jakarta.jms.QueueSender;
import jakarta.jms.QueueSession;
import jakarta.jms.Session;
import jakarta.jms.TemporaryQueue;

import com.sun.messaging.AdministeredObject;
import com.sun.messaging.ConnectionConfiguration;
import com.sun.messaging.DestinationConfiguration;
import com.sun.messaging.QueueConnectionFactory;
import com.sun.messaging.jmq.ClientConstants;
import com.sun.messaging.jmq.Version;
import com.sun.messaging.jmq.admin.apps.broker.BrokerCmdOptions;
import com.sun.messaging.jmq.admin.bkrutil.BrokerConstants;
import com.sun.messaging.jmq.admin.resources.AdminResources;
import com.sun.messaging.jmq.admin.util.Globals;
import com.sun.messaging.jmq.admin.util.JMSObjFactory;
import com.sun.messaging.jmq.jmsclient.ConnectionImpl;
import com.sun.messaging.jmq.jmsclient.JMSXAWrappedConnectionFactoryImpl;
import com.sun.messaging.jmq.jmsspi.JMSAdmin;
import com.sun.messaging.jmq.jmsspi.PropertiesHolder;
import com.sun.messaging.jmq.util.BrokerExitCode;
import com.sun.messaging.jmq.util.DestType;
import com.sun.messaging.jmq.util.admin.DestinationInfo;
import com.sun.messaging.jmq.util.admin.MessageType;

public class JMSAdminImpl implements JMSAdmin, ExceptionListener {

    private static AdminResources ar = Globals.getAdminResources();

    public static final long DEFAULT_TIMEOUT = 5000;

    private String adminuserName = null;
    private String adminPassword = null;

    private long timeout = -1;

    private QueueConnectionFactory qcf;
    private QueueConnection connection;
    private QueueSession session;
    private Queue requestQueue;
    private TemporaryQueue replyQueue;
    private QueueSender sender;
    protected QueueReceiver receiver;

    private AdministeredObject tmpDestination = null;
    private AdministeredObject tmpConnFactory = null;

    private boolean secureTransportUsed = false;

    // When this class is used to start a broker, these properties are passed to the broker
    private PropertiesHolder brokerPropertiesHolder;

    protected static final System.Logger logger = System.getLogger(JMSAdminImpl.class.getName());

    /*
     * This class should only be instantiated via JMSAdminFactoryImpl. REVISIT: hard-coded error messages
     */
    protected JMSAdminImpl(Properties connectionProps, PropertiesHolder brokerPropertiesHolder, String username, String adminPassword) throws JMSException {

        this.timeout = DEFAULT_TIMEOUT;
        this.adminuserName = username;
        this.adminPassword = adminPassword;
        this.brokerPropertiesHolder = brokerPropertiesHolder;

        createFactory(connectionProps); // init the qcf !!

        String connType = connectionProps.getProperty(ConnectionConfiguration.imqConnectionType, "");

        if (connType.equals("TLS") || connType.equals("SSL")) {
            secureTransportUsed = true;
        }
    }

    /**
     * Return the SPI version
     */
    @Override
    public String getVersion() {
        Version version = new Version();
        return (version.getJMSAdminSpiVersion());
    }

    /**
     * Create a ConnectionFactory administered object
     *
     * @param type Either QUEUE or TOPIC.
     * @param properties Connection specific properties.
     * @return New created ConnectionFactory administered object.
     * @exception JMSException thrown if connectionFactory could not be created.
     */
    @Override
    public Object createConnectionFactoryObject(int type, java.util.Map properties) throws JMSException {

        Object cf = null;
        Properties tmpProps = getProperties(properties);

        fillDefaultConnectionFactoryProperties(tmpProps);

        if (type == TOPIC) {
            cf = JMSObjFactory.createTopicConnectionFactory(tmpProps);
        } else if (type == QUEUE) {
            cf = JMSObjFactory.createQueueConnectionFactory(tmpProps);
        } else {
            throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_INVALID_DOMAIN_TYPE));
        }
        return cf;
    }

    /**
     * Create a XAConnectionFactory administered object
     *
     * @param type Either QUEUE or TOPIC.
     * @param properties Connection specific properties.
     * @return New created JMSXAConnectionFactory administered object. ^^^^^
     * @exception JMSException thrown if XAConnectionFactory could not be created.
     */
    @Override
    public Object createXAConnectionFactoryObject(int type, java.util.Map properties) throws JMSException {

        Object xcf = null;
        Properties tmpProps = getProperties(properties);

        fillDefaultConnectionFactoryProperties(tmpProps);

        if (type == TOPIC) {
            xcf = new com.sun.messaging.jmq.jmsclient.JMSXATopicConnectionFactoryImpl();
            setProperties((AdministeredObject) xcf, tmpProps);

        } else if (type == QUEUE) {
            xcf = new com.sun.messaging.jmq.jmsclient.JMSXAQueueConnectionFactoryImpl();
            setProperties((AdministeredObject) xcf, tmpProps);

        } else {
            throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_INVALID_DOMAIN_TYPE));
        }
        return xcf;
    }

    /**
     * Create a Destination administered object
     *
     * @param destinationName The destination name.
     * @param type Either QUEUE or TOPIC.
     * @param properties destination specific properties.
     * @return New created Destination administered object.
     * @exception JMSException thrown if destination object could not be created.
     */
    @Override
    public Object createDestinationObject(String destinationName, int type, java.util.Map properties) throws JMSException {
        Map props = properties;
        if (props == null) {
            props = new Properties();
        }
        props.put(DestinationConfiguration.imqDestinationName, destinationName);
        return createDestinationObject(type, props);
    }

    /**
     * Create a Destination administered object. The destination name is assumed in properties like imqDestinationName=xxxxx
     *
     * @param type Either QUEUE or TOPIC.
     * @param properties destination specific properties.
     * @return New created Destination administered object.
     * @exception JMSException thrown if destination object could not be created.
     */
    @Override
    public Object createDestinationObject(int type, java.util.Map properties) throws JMSException {
        if (properties == null || properties.get(DestinationConfiguration.imqDestinationName) == null) {
            throw new JMSException(ar.getKString(ar.X_JMSSPI_NO_DESTINATION_NAME));
        }
        Object dest = null;

        Properties tmpProps = getProperties(properties);

        if (type == TOPIC) {
            dest = JMSObjFactory.createTopic(tmpProps);

        } else if (type == QUEUE) {
            dest = JMSObjFactory.createQueue(tmpProps);

        } else {
            throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_INVALID_DOMAIN_TYPE));
        }
        return dest;
    }

    /**
     * Wrap a standard JMS ConnectionFactory administered object
     *
     * @param obj a XAQueue/TopicConnectionFactory or Queue/TopicConnectionFactory object
     * @return a JMSXAConnectionFactory object ^^^^^
     * @exception JMSException if fail to wrap
     */
    @Override
    public Object wrapJMSConnectionFactoryObject(Object obj) throws JMSException {
        if (obj instanceof jakarta.jms.XAQueueConnectionFactory) {
            return new JMSXAWrappedConnectionFactoryImpl((jakarta.jms.XAQueueConnectionFactory) obj);
        }
        if (obj instanceof jakarta.jms.XATopicConnectionFactory) {
            return new JMSXAWrappedConnectionFactoryImpl((jakarta.jms.XATopicConnectionFactory) obj);
        }
        if (obj instanceof jakarta.jms.QueueConnectionFactory) {
            return new JMSXAWrappedConnectionFactoryImpl((jakarta.jms.QueueConnectionFactory) obj);
        }
        if (obj instanceof jakarta.jms.TopicConnectionFactory) {
            return new JMSXAWrappedConnectionFactoryImpl((jakarta.jms.TopicConnectionFactory) obj);
        }

        throw new JMSException(ar.getKString(ar.X_JMSSPI_INVALID_OBJECT_TYPE));
    }

    @Override
    public void validateJMSSelector(String selector) throws JMSException {
        com.sun.messaging.jmq.jmsselector.JMSSelector jmsselector = new com.sun.messaging.jmq.jmsselector.JMSSelector();
        try {
            jmsselector.validateSelectorPattern(selector);
        } catch (com.sun.messaging.jmq.jmsselector.InvalidJMSSelectorException e) {
            throw new InvalidSelectorException(e.getMessage());
        } catch (Exception e) {
            throw new JMSException(e.getMessage());
        }
    }

    /**
     * @return the client-id property name
     */
    @Override
    public String clientIDPropertyName() {
        return ConnectionConfiguration.imqConfiguredClientID;
    }

    /**
     * Returns a map of all the properties that a destination object has.
     * 

* For each property name returned, a corresponding label that can be used for output display purposes is also returned. * The Map returned contains the property names and property labels as key-value pairs. This information can be used to * display more readable output containing property labels and not property names. * * @param type Either QUEUE or TOPIC. * @return Map containing attribute value pairs of property names and their display labels. */ @Override public Map getAllDestinationObjectProperties(int type) throws JMSException { Properties ret; if (tmpDestination == null) { tmpDestination = (AdministeredObject) JMSObjFactory.createTopic(new Properties()); } ret = new Properties(); for (Enumeration e = tmpDestination.enumeratePropertyNames(); e.hasMoreElements();) { String propName = (String) e.nextElement(); String propLabel = tmpDestination.getPropertyLabel(propName); ret.setProperty(propName, propLabel); } return (ret); } /** * Returns a subset of all the properties that a destination object has. *

* This collection of properties can be used to construct a user interface where not all of the object's properties will * be displayed, and only a selected few (more important) ones are. *

* For each property name returned, a corresponding label that can be used for output display purposes is also returned. * The Map returned contains the property names and property labels as key-value pairs. This information can be used to * display more readable output containing property labels and not property names. * * @param type Either QUEUE or TOPIC. * @return Map containing attribute value pairs of property names and their display labels. */ @Override public Map getDisplayedDestinationObjectProperties(int type) throws JMSException { Properties ret; String propName, propLabel; if (tmpDestination == null) { tmpDestination = (AdministeredObject) JMSObjFactory.createTopic(new Properties()); } ret = new Properties(); propName = DestinationConfiguration.imqDestinationName; propLabel = tmpDestination.getPropertyLabel(propName); ret.setProperty(propName, propLabel); return (ret); } /** * Returns a map of all the properties that a connection factory object has. *

* For each property name returned, a corresponding label that can be used for output display purposes is also returned. * The Map returned contains the property names and property labels as key-value pairs. This information can be used to * display more readable output containing property labels and not property names. * * @param type Either QUEUE or TOPIC. * @return Map containing attribute value pairs of property names and their display labels. */ @Override public Map getAllConnectionFactoryObjectProperies(int type) throws JMSException { Properties ret; if (tmpConnFactory == null) { tmpConnFactory = (AdministeredObject) JMSObjFactory.createTopicConnectionFactory(new Properties()); } ret = new Properties(); for (Enumeration e = tmpConnFactory.enumeratePropertyNames(); e.hasMoreElements();) { String propName = (String) e.nextElement(); String propLabel = tmpConnFactory.getPropertyLabel(propName); ret.setProperty(propName, propLabel); } return (ret); } /** * Returns a subset of all the properties that a connection factory object has. *

* This collection of properties can be used to construct a user interface where not all of the object's properties will * be displayed, and only a selected few (more important) ones are. *

* For each property name returned, a corresponding label that can be used for output display purposes is also returned. * The Map returned contains the property names and property labels as key-value pairs. This information can be used to * display more readable output containing property labels and not property names. * * @param type Either QUEUE or TOPIC. * @return Map containing attribute value pairs of property names and their display labels. */ @Override public Map getDisplayedConnectionFactoryObjectProperies(int type) throws JMSException { Properties ret; String propName, propLabel; if (tmpConnFactory == null) { tmpConnFactory = (AdministeredObject) JMSObjFactory.createTopicConnectionFactory(new Properties()); } ret = new Properties(); propName = ConnectionConfiguration.imqBrokerHostName; propLabel = tmpConnFactory.getPropertyLabel(propName); ret.setProperty(propName, propLabel); propName = ConnectionConfiguration.imqBrokerHostPort; propLabel = tmpConnFactory.getPropertyLabel(propName); ret.setProperty(propName, propLabel); propName = ConnectionConfiguration.imqConfiguredClientID; propLabel = tmpConnFactory.getPropertyLabel(propName); ret.setProperty(propName, propLabel); return (ret); } /** * Connect to the provider. * * @exception JMSException thrown if connection to the provider cannot be established or if an error occurs */ @Override public void connectToProvider() throws JMSException { connection = qcf.createQueueConnection(adminuserName, adminPassword); connection.setExceptionListener(this); connection.start(); session = connection.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE); requestQueue = session.createQueue(MessageType.JMQ_ADMIN_DEST); replyQueue = session.createTemporaryQueue(); sender = session.createSender(requestQueue); sender.setDeliveryMode(DeliveryMode.NON_PERSISTENT); receiver = session.createReceiver(replyQueue); hello(); } /** * Disconnect from the provider. * * @exception JMSException thrown if connection to the provider cannot be closed or ir an error occurs */ @Override public void disconnectFromProvider() throws JMSException { sender.close(); receiver.close(); session.close(); try { connection.close(); } catch (JMSException jmse) { if (!secureTransportUsed) { throw (jmse); } } } /** * Create a physical Destination within the JMS Provider using the provided properties to define provider specific * attributes. Destination is not automatically bound into JNDI namespace. * * @param destinationType QUEUE or TOPIC * @param properties creation properties. * @exception JMSException thrown if Queue could not be created. */ @Override public void createProviderDestination(String destinationName, int destinationType, java.util.Map properties) throws JMSException { ObjectMessage requestMesg = null; Message replyMesg = null; // Create DestinationInfo. DestinationInfo di = new DestinationInfo(); di.setName(destinationName); // REVISIT: // We only check for queueDeliveryPolicy in the properties // hard-coded string; left here because we are not sure // if we are going to expose this attribute yet String qPolicy = null; /* * Early initialization to be used in error messages */ int typeMask = this.getDestTypeMask(destinationType, null); if (properties != null) { if (properties.containsKey("queueDeliveryPolicy")) { qPolicy = (String) properties.get("queueDeliveryPolicy"); typeMask = this.getDestTypeMask(destinationType, qPolicy); } if (properties.containsKey(BrokerCmdOptions.PROP_NAME_MAX_ACTIVE_CONSUMER_COUNT)) { Object tmp = null; String val = null; tmp = properties.get(BrokerCmdOptions.PROP_NAME_MAX_ACTIVE_CONSUMER_COUNT); if (tmp != null) { if (!(tmp instanceof String)) { JMSException jmse; jmse = new JMSException(ar.getString(ar.E_SPI_DEST_CREATION_FAILED, DestType.toString(typeMask), destinationName) + "\n" + ar.getString(ar.E_SPI_ATTR_TYPE_NOT_STRING, BrokerCmdOptions.PROP_NAME_MAX_ACTIVE_CONSUMER_COUNT)); throw jmse; } val = (String) tmp; try { di.setMaxActiveConsumers(Integer.parseInt(val)); } catch (Exception e) { JMSException jmse; jmse = new JMSException(ar.getString(ar.E_SPI_DEST_CREATION_FAILED, DestType.toString(typeMask), destinationName) + "\n" + ar.getString(ar.E_INVALID_INTEGER_VALUE, val, BrokerCmdOptions.PROP_NAME_MAX_ACTIVE_CONSUMER_COUNT)); throw (jmse); } } } } di.setType(typeMask); requestMesg = session.createObjectMessage(); requestMesg.setJMSReplyTo(replyQueue); requestMesg.setIntProperty(MessageType.JMQ_MESSAGE_TYPE, MessageType.CREATE_DESTINATION); requestMesg.setObject(di); sender.send(requestMesg); replyMesg = receiver.receive(timeout); replyMesg.acknowledge(); checkReplyTypeStatus(replyMesg, MessageType.CREATE_DESTINATION_REPLY); } /** * Delete a physical destination within the JMS Provider. * * @param type Either QUEUE or TOPIC. * @exception JMSException thrown if Queue could not be deleted. */ @Override public void deleteProviderDestination(String destinationName, int type) throws JMSException { ObjectMessage requestMesg = null; Message replyMesg = null; requestMesg = session.createObjectMessage(); requestMesg.setJMSReplyTo(replyQueue); requestMesg.setIntProperty(MessageType.JMQ_MESSAGE_TYPE, MessageType.DESTROY_DESTINATION); requestMesg.setStringProperty(MessageType.JMQ_DESTINATION, destinationName); requestMesg.setIntProperty(MessageType.JMQ_DEST_TYPE, this.getDestTypeMask(type, null)); sender.send(requestMesg); replyMesg = receiver.receive(timeout); replyMesg.acknowledge(); checkReplyTypeStatus(replyMesg, MessageType.DESTROY_DESTINATION_REPLY); } /** * Get all provider destinations. * * @return A multi dimensional array containing information about the JMS destinations. array[0] is a String[] listing * the destination names. array[1] is a String[] listing the destination types. * @exception JMSException thrown if array could not be obtained. */ @Override public String[][] getProviderDestinations() throws JMSException { ObjectMessage mesg = null; mesg = session.createObjectMessage(); mesg.setJMSReplyTo(replyQueue); mesg.setIntProperty(MessageType.JMQ_MESSAGE_TYPE, MessageType.GET_DESTINATIONS); sender.send(mesg); mesg = (ObjectMessage) receiver.receive(timeout); mesg.acknowledge(); checkReplyTypeStatus(mesg, MessageType.GET_DESTINATIONS_REPLY); Object obj; if ((obj = mesg.getObject()) != null) { if (obj instanceof Vector) { Vector dests = (Vector) obj; /* * Remove temporary, internal and admin destinations by creating a new Vector and adding all the valid destinations into * this new Vector. */ Vector validDests = new Vector(); for (int i = 0; i < dests.size(); i++) { DestinationInfo di = (DestinationInfo) dests.elementAt(i); if ((!MessageType.JMQ_ADMIN_DEST.equals(di.name)) && (!MessageType.JMQ_BRIDGE_ADMIN_DEST.equals(di.name)) && (!DestType.isInternal(di.fulltype)) && (!DestType.isTemporary(di.type))) { validDests.add(di); } } int numElements = validDests.size(); String[][] destinations = new String[2][numElements]; for (int i = 0; i < numElements; i++) { DestinationInfo di = (DestinationInfo) validDests.get(i); destinations[0][i] = di.name; destinations[1][i] = this.getDestinationType(di.type); } return destinations; } } return null; } /** * Start the provider. * * @param iMQHome Location of the broker executable. * @param optArgs Array of optional broker command line arguments. * @param serverName Instance name of the server. * @exception IOException thrown if the server startup fails. */ @Override public void startProvider(String iMQHome, String optArgs[], String serverName) throws IOException, JMSException { String[] cmdLine = makeStartProviderCmdLine(iMQHome, optArgs, serverName, false); // Log the command line we are about to execute if (logger.isLoggable(DEBUG)) { String commandLineToLog = ""; for (int i = 0; i < cmdLine.length; i++) { commandLineToLog = commandLineToLog + cmdLine[i] + " "; } logger.log(DEBUG, "MQJMSRA: Starting LOCAL broker with command line: " + commandLineToLog); } launchAndWatch(cmdLine); } /** * @param iMQHome Location of the broker executable, ignored if argsOnly true */ @Override public String[] makeStartProviderCmdLine(String iMQHome, String optArgs[], String serverName, boolean argsOnly) throws IOException, JMSException { Vector v = new Vector(); String append = null; if (!argsOnly) { String iMQBrokerPath; if (java.io.File.separator.equals("\\")) { // Windows path // \\imqbrokersvc.exe -console iMQBrokerPath = iMQHome + java.io.File.separator + "imqbrokersvc.exe"; append = "-console"; } else { // Unix path. // /bin/imqbrokerd iMQBrokerPath = iMQHome + java.io.File.separator + "imqbrokerd"; } v.add(iMQBrokerPath); } String portStr = qcf.getProperty(ConnectionConfiguration.imqBrokerHostPort); // Important : Do not change the command line parameter order // unless you know what you are doing. Here are the // constraints - // // 1. The "-javahome" argument, if present, must be first. // Otherwise it does not work on Windows. The caller (of // this method) is responsible for making sure that the // "-javahome" argument is first in the 'optArgs' string. // // 2. The -name, -port and -silent arguments must be at // placed at the end, so that they override anything // specified in the optArgs... // // 3. The -bgnd argument is required for proper signal // handling on solaris. // if (optArgs != null) { for (int i = 0; i < optArgs.length; i++) { v.add(optArgs[i]); } } if (serverName != null) { v.add("-name"); v.add(serverName); } if (append != null) { v.add(append); } v.add("-port"); v.add(portStr); // CR 6944162 Disable use of -bgnd (used on Solaris) // because it prevents passwords being passed to the broker via standard input // v.add("-bgnd"); // disable use of -errorwarn if DEBUG logging is enabled if (!logger.isLoggable(DEBUG)) { // normally we only want to see errors in stdout v.add("-ttyerrors"); } if (!argsOnly) { v.add("-managed"); v.add("-read-stdin"); } return (String[]) v.toArray(new String[0]); } private void launchAndWatch(String[] cmdLine) throws IOException { Process p = Runtime.getRuntime().exec(cmdLine); BrokerWatcher brokerWatcher = new BrokerWatcher(p, cmdLine); brokerWatcher.setDaemon(true); brokerWatcher.start(); // start a thread to log any error messages from the new broker as a WARN message boolean isError = true; StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), isError, "Local broker: "); errorGobbler.setDaemon(true); errorGobbler.start(); // start a thread to log any output messages from the new broker as an INFO message isError = false; StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(), isError, "Local broker: "); outputGobbler.setDaemon(true); outputGobbler.start(); // generate the broker properties afresh Properties brokerProps = brokerPropertiesHolder.getProperties(); // write properties to the input stream of the new process try { OutputStreamWriter osw = new OutputStreamWriter(p.getOutputStream()); BufferedWriter bw = new BufferedWriter(osw); for (Enumeration e = brokerProps.propertyNames(); e.hasMoreElements();) { String thisPropertyName = (String) e.nextElement(); String thisPropertyValue = brokerProps.getProperty(thisPropertyName); bw.write(thisPropertyName + "=" + thisPropertyValue); bw.newLine(); } if (this.adminPassword != null) { // if set, override any admin password set via brokerProps bw.write("imq.imqcmd.password=" + this.adminPassword); bw.newLine(); } bw.close(); } catch (IOException ioe) { logger.log(ERROR, ioe.getMessage(), ioe); } } /** * Ping the provider. * * @exception JMSException thrown if ping fails */ @Override public void pingProvider() throws JMSException { // temporarily turn off logging because we do not want to log a message if the provider is not running // as this might not be an error. Logger rootLogger = Logger.getLogger(ConnectionImpl.ROOT_LOGGER_NAME); Level savedLevel = rootLogger.getLevel(); rootLogger.setLevel(Level.SEVERE); Connection pingConn = null; try { pingConn = qcf.createQueueConnection(adminuserName, adminPassword); } finally { // re-enable logging logging rootLogger.setLevel(savedLevel); } try { pingConn.setExceptionListener(this); pingConn.start(); } finally { try { pingConn.close(); } catch (JMSException jmse) { if (!secureTransportUsed) { throw (jmse); } } } } /** * Get the property value from a provider * * @exception JMSException thrown if the get fails. */ private String getProviderPropertyValue(String propName) throws JMSException { ObjectMessage requestMesg = null; ObjectMessage replyMesg = null; String propVal = null; requestMesg = session.createObjectMessage(); requestMesg.setJMSReplyTo(replyQueue); requestMesg.setIntProperty(MessageType.JMQ_MESSAGE_TYPE, MessageType.GET_BROKER_PROPS); sender.send(requestMesg); replyMesg = (ObjectMessage) receiver.receive(timeout); replyMesg.acknowledge(); checkReplyTypeStatus(replyMesg, MessageType.GET_BROKER_PROPS_REPLY); Object obj; if ((obj = replyMesg.getObject()) != null) { if (obj instanceof Properties) { Properties props = (Properties) obj; propVal = props.getProperty(propName); } } return (propVal); } /** * Get the instance name of the provider * * @exception JMSException thrown if the get fails. */ @Override public String getProviderInstanceName() throws JMSException { return (getProviderPropertyValue(BrokerConstants.PROP_NAME_BKR_INSTANCE_NAME)); } /** * Get the VARHOME directory of the provider * * @exception JMSException thrown if the get fails. */ @Override public String getProviderVarHome() throws JMSException { return (getProviderPropertyValue(BrokerConstants.PROP_NAME_BKR_VARHOME)); } /** * Shutdown the provider. @exception JMSException thrown if the shutdown fails @throws */ @Override public void shutdownProvider() throws JMSException { try { tryToShutdownProvider(); } catch (JMSException jmse) { if ((com.sun.messaging.jmq.jmsclient.resources.ClientResources.X_CONSUMER_CLOSED.equals(jmse.getErrorCode())) || (com.sun.messaging.jmq.jmsclient.resources.ClientResources.X_SESSION_CLOSED.equals(jmse.getErrorCode()))) { // we seem to have lost the connection - try once to reconnect before giving up try { Thread.sleep(1000); } catch (InterruptedException e) { } connectToProvider(); tryToShutdownProvider(); } else { // re-throw the exception if not X_CONSUMER_CLOSED or X_SESSION_CLOSED throw jmse; } } } private void tryToShutdownProvider() throws JMSException { ObjectMessage requestMesg; Message replyMesg; requestMesg = session.createObjectMessage(); requestMesg.setJMSReplyTo(replyQueue); requestMesg.setIntProperty(MessageType.JMQ_MESSAGE_TYPE, MessageType.SHUTDOWN); sender.send(requestMesg); // disable reconnect since we don't want the client to try to reconnect // ConnectionImpl ci = (ConnectionImpl)connection; // ci.setImqReconnect(false); replyMesg = receiver.receive(timeout); checkReplyTypeStatus(replyMesg, MessageType.SHUTDOWN_REPLY); } /** * Restart the provider. * * @exception JMSException thrown if the restart fails */ @Override public void restartProvider() throws JMSException { ObjectMessage requestMesg = null; Message replyMesg = null; requestMesg = session.createObjectMessage(); requestMesg.setJMSReplyTo(replyQueue); requestMesg.setIntProperty(MessageType.JMQ_MESSAGE_TYPE, MessageType.SHUTDOWN); requestMesg.setBooleanProperty(MessageType.JMQ_RESTART, true); sender.send(requestMesg); replyMesg = receiver.receive(timeout); checkReplyTypeStatus(replyMesg, MessageType.SHUTDOWN_REPLY); } /** * Return the provider host name */ @Override public String getProviderHostName() throws JMSException { return qcf.getProperty(ConnectionConfiguration.imqBrokerHostName); } /** * Return the provider host port number */ @Override public String getProviderHostPort() throws JMSException { return qcf.getProperty(ConnectionConfiguration.imqBrokerHostPort); } /** * Delete provider instance. * * @param mqBinDir Location of MQ's bin directory, which contains the broker executable. * @param optArgs Optional broker command line arguments. * @param serverName instance name of MQ broker to delete * @exception JMSException thrown if the delete fails. */ @Override public void deleteProviderInstance(String mqBinDir, String optArgs, String serverName) throws IOException, JMSException { String iMQBrokerPath; int exitCode = 0; boolean interrupted = false; if (java.io.File.separator.equals("\\")) { // Windows path // \\bin\\imqbrokerd.exe iMQBrokerPath = mqBinDir + java.io.File.separator + "imqbrokerd.exe"; } else { // Unix path. // /bin/imqbrokerd iMQBrokerPath = mqBinDir + java.io.File.separator + "imqbrokerd"; } // String portStr = // qcf.getProperty(ConnectionConfiguration.imqBrokerHostPort); // Important : Do not change the command line parameter order // unless you know what you are doing. Here are the // constraints - // // 1. The "-javahome" argument, if present, must be first. // Otherwise it does not work on Windoze. The caller (of // this method) is responsible for making sure that the // "-javahome" argument is first in the 'optArgs' string. // // 2. The -name, -port and -silent arguments must be at // placed at the end, so that they override anything // specified in the optArgs... // // 3. The -bgnd argument is required for proper signal // handling on solaris. // String cmdLine = iMQBrokerPath; if (optArgs != null) { cmdLine = cmdLine + " " + optArgs; } if (serverName != null) { cmdLine = cmdLine + " -name " + serverName; } cmdLine = cmdLine + " -remove instance -silent -force"; Process p = Runtime.getRuntime().exec(cmdLine); // Close the receiver end of stdout and stderr streams. // Otherwise the child process blocks while trying to // write... p.getInputStream().close(); p.getErrorStream().close(); try { p.waitFor(); exitCode = p.exitValue(); } catch (InterruptedException iex) { interrupted = true; } if (interrupted) { throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_INT_PREM, serverName)); } /* * Proper handling of exit codes will be done once the following bug is fixed: 4713518 - imqbrokerd -remove: * Enhancements needed for app server integration */ switch (exitCode) { case BrokerExitCode.NORMAL: break; case BrokerExitCode.INSTANCE_NOT_EXISTS: throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_NOT_EXIST, serverName)); case BrokerExitCode.INSTANCE_BEING_USED: throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_BEING_USED, serverName)); case BrokerExitCode.NO_PERMISSION_ON_INSTANCE: throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_NO_PERM, serverName)); case BrokerExitCode.PROBLEM_REMOVING_PERSISTENT_STORE: throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_PROB_RM_STORE, serverName)); case BrokerExitCode.IOEXCEPTION: throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_IOEXCEPTION, serverName)); default: throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_UNKNOWN, serverName)); } } /** * Delete provider instance. * * @param mqBinDir Location of MQ's bin directory, which contains the broker executable. * @param optArgs Array of optional broker command line arguments. * @param serverName instance name of MQ broker to delete * @exception JMSException thrown if the delete fails. */ @Override public void deleteProviderInstance(String mqBinDir, String optArgs[], String serverName) throws IOException, JMSException { String iMQBrokerPath; int exitCode = 0; boolean interrupted = false; if (java.io.File.separator.equals("\\")) { // Windows path // \\bin\\imqbrokerd.exe iMQBrokerPath = mqBinDir + java.io.File.separator + "imqbrokerd.exe"; } else { // Unix path. // /bin/imqbrokerd iMQBrokerPath = mqBinDir + java.io.File.separator + "imqbrokerd"; } // String portStr = // qcf.getProperty(ConnectionConfiguration.imqBrokerHostPort); // Important : Do not change the command line parameter order // unless you know what you are doing. Here are the // constraints - // // 1. The "-javahome" argument, if present, must be first. // Otherwise it does not work on Windoze. The caller (of // this method) is responsible for making sure that the // "-javahome" argument is first in the 'optArgs' string. // // 2. The -name, -port and -silent arguments must be at // placed at the end, so that they override anything // specified in the optArgs... // // 3. The -bgnd argument is required for proper signal // handling on solaris. // Vector v = new Vector(); v.add(iMQBrokerPath); if (optArgs != null) { for (int i = 0; i < optArgs.length; i++) { v.add(optArgs[i]); } } if (serverName != null) { v.add("-name"); v.add(serverName); } v.add("-remove"); v.add("instance"); v.add("-silent"); v.add("-force"); String[] cmdLine = (String[]) v.toArray(new String[0]); Process p = Runtime.getRuntime().exec(cmdLine); // Close the receiver end of stdout and stderr streams. // Otherwise the child process blocks while trying to // write... p.getInputStream().close(); p.getErrorStream().close(); try { p.waitFor(); exitCode = p.exitValue(); } catch (InterruptedException iex) { interrupted = true; } if (interrupted) { throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_INT_PREM, serverName)); } /* * Proper handling of exit codes will be done once the following bug is fixed: 4713518 - imqbrokerd -remove: * Enhancements needed for app server integration */ switch (exitCode) { case BrokerExitCode.NORMAL: break; case BrokerExitCode.INSTANCE_NOT_EXISTS: throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_NOT_EXIST, serverName)); case BrokerExitCode.INSTANCE_BEING_USED: throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_BEING_USED, serverName)); case BrokerExitCode.NO_PERMISSION_ON_INSTANCE: throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_NO_PERM, serverName)); case BrokerExitCode.PROBLEM_REMOVING_PERSISTENT_STORE: throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_PROB_RM_STORE, serverName)); case BrokerExitCode.IOEXCEPTION: throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_IOEXCEPTION, serverName)); default: throw new jakarta.jms.JMSException(ar.getKString(ar.X_JMSSPI_DELETE_INST_UNKNOWN, serverName)); } } private void hello() throws JMSException { ObjectMessage requestMesg = null; Message replyMesg = null; requestMesg = session.createObjectMessage(); requestMesg.setJMSReplyTo(replyQueue); requestMesg.setIntProperty(MessageType.JMQ_MESSAGE_TYPE, MessageType.HELLO); sender.send(requestMesg); replyMesg = receiver.receive(timeout); replyMesg.acknowledge(); checkReplyTypeStatus(replyMesg, MessageType.HELLO_REPLY); } /* * Map is an interface and its implementation can be anything that implements the Map interface. Whatever it is, convert * it to a Properties object. */ private Properties getProperties(java.util.Map properties) { Properties tmpProps = null; if (properties == null) { tmpProps = new Properties(); } else if (properties instanceof Properties) { tmpProps = (Properties) properties; } else { tmpProps = new Properties(); Iterator iterator = properties.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); tmpProps.put(entry.getKey(), entry.getValue()); } } return tmpProps; } /* * Set the properties on this object. */ private static void setProperties(AdministeredObject obj, Properties objProps) throws JMSException { /* * Set the specified properties on the new object. */ for (Enumeration e = objProps.propertyNames(); e.hasMoreElements();) { String propName = (String) e.nextElement(); String value = objProps.getProperty(propName); if (value != null) { obj.setProperty(propName, value); } } } private void createFactory(Properties connectionProps) throws JMSException { qcf = new QueueConnectionFactory(); qcf.setConnectionType(ClientConstants.CONNECTIONTYPE_ADMIN); for (Enumeration e = connectionProps.propertyNames(); e.hasMoreElements();) { String propName = (String) e.nextElement(); String value = connectionProps.getProperty(propName); if (value != null) { qcf.setProperty(propName, value); } } } private void fillDefaultConnectionFactoryProperties(Properties props) throws JMSException { String val; if (props.getProperty(ConnectionConfiguration.imqBrokerHostName) == null && (val = qcf.getProperty(ConnectionConfiguration.imqBrokerHostName)) != null) { props.setProperty(ConnectionConfiguration.imqBrokerHostName, val); } if (props.getProperty(ConnectionConfiguration.imqBrokerHostPort) == null && (val = qcf.getProperty(ConnectionConfiguration.imqBrokerHostPort)) != null) { props.setProperty(ConnectionConfiguration.imqBrokerHostPort, val); } } // REVISIT: // hard-coded string @SuppressWarnings("deprecation") private static int getDestTypeMask(int type, String policy) { int mask = -1; if (type == TOPIC) { mask = DestType.DEST_TYPE_TOPIC; } else if (type == QUEUE) { mask = DestType.DEST_TYPE_QUEUE; } if (policy == null) { return mask; } if (type == QUEUE) { if (policy.equals("s")) { mask |= DestType.DEST_FLAVOR_SINGLE; } else if (policy.equals("f")) { mask |= DestType.DEST_FLAVOR_FAILOVER; } else if (policy.equals("r")) { mask |= DestType.DEST_FLAVOR_RROBIN; } } return mask; } private static String getDestinationType(int mask) { if (DestType.isTopic(mask)) { return String.valueOf(TOPIC); } else if (DestType.isQueue(mask)) { return String.valueOf(QUEUE); } else { return String.valueOf(UNKNOWN); } } private void checkReplyTypeStatus(Message mesg, int msgType) throws JMSException { int actualMsgType = -1, actualReplyStatus = -1; /* * There is a timing problem in the protocol. The GOODBYE message could be processed before the SHUTDOWN_REPLY message * and therefore could be sending null as a value for 'mesg' when receive() returns. We will assume that the SHUTDOWN * operation was successful when we receive status == 200 or mesg == null. */ if (mesg == null) { if (msgType == MessageType.SHUTDOWN_REPLY) { return; } } actualMsgType = mesg.getIntProperty(MessageType.JMQ_MESSAGE_TYPE); actualReplyStatus = mesg.getIntProperty(MessageType.JMQ_STATUS); if ((msgType == actualMsgType) && (actualReplyStatus == MessageType.OK)) { return; } /* * Otherwise, report an error */ String error = null; try { error = mesg.getStringProperty(MessageType.JMQ_ERROR_STRING); } catch (Exception e) { } throw new JMSException(error); } /* * BEGIN INTERFACE ExceptionListener */ @Override public void onException(JMSException jmse) { } /* * END INTERFACE ExceptionListener */ class BrokerWatcher extends Thread { Process p; String[] cmdLine; BrokerWatcher(Process p, String[] cmdLine) { this.p = p; this.cmdLine = cmdLine; } @Override public void run() { logger.log(DEBUG, "BrokerWatcher started"); try { int status = p.waitFor(); logger.log(DEBUG, "BrokerWatcher: Broker returned with status=" + status); if (status == 255) { // restart broker launchAndWatch(cmdLine); logger.log(DEBUG, "BrokerWatcher terminating after restarting broker"); } logger.log(DEBUG, "BrokerWatcher terminating after normal exit"); } catch (InterruptedException e) { logger.log(WARNING, "InterruptedException watching broker: " + e.getMessage()); } catch (IOException e) { logger.log(WARNING, "Error restarting broker: " + e.getMessage()); } } } static class StreamGobbler extends Thread { InputStream is; boolean isError; String prefix; /** * * @param isError If true, log messages as a WARN message. Otherwise log messages as an INFO message */ StreamGobbler(InputStream is, boolean isError, String prefix) { this.is = is; this.isError = isError; this.prefix = prefix; } @Override public void run() { try { InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line = null; String message = prefix; int noOfLines = 0; while ((line = br.readLine()) != null) { noOfLines++; if (noOfLines > 1) { message = message + "\n"; } message = message + line; } if (noOfLines > 0) { if (isError) { logger.log(WARNING, message); } else { logger.log(INFO, message); } } } catch (IOException ioe) { logger.log(ERROR, ioe.getMessage(), ioe); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy