/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.mq.sm.file; import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; import javax.jms.InvalidClientIDException; import javax.jms.JMSException; import javax.jms.JMSSecurityException; import org.jboss.mq.DurableSubscriptionID; import org.jboss.mq.SpyJMSException; import org.jboss.mq.SpyTopic; import org.jboss.mq.server.JMSDestinationManager; import org.jboss.mq.server.JMSTopic; import org.jboss.mq.sm.StateManager; import org.jboss.mq.xml.XElement; import org.jboss.mq.xml.XElementException; import org.jboss.system.ServiceMBeanSupport; import org.jboss.system.server.ServerConfigLocator; /** * This class is a simple User Manager. It handles credential issues. * *

This is the old state manager. * * @jmx:mbean extends="org.jboss.system.ServiceMBean" * * @author Norbert Lataille (Norbert.Lataille@m4x.org) * @author Hiram Chirino * @author Peter Antman * @version $Revision: 57198 $ */ public class OldStateManager extends ServiceMBeanSupport implements StateManager, OldStateManagerMBean { XElement stateConfig; private final Set loggedOnClientIds = new HashSet(); private String stateFile = "conf/default/jbossmq-state.xml"; private URL systemConfigURL; /** * Constructor for the StateManager object * * @exception XElementException Description of Exception */ public OldStateManager() throws XElementException { //loggedOnClientIds = new HashSet(); } protected void createService() throws Exception { // Get the system configuration URL systemConfigURL = ServerConfigLocator.locate().getServerConfigURL(); } /** * Sets the StateFile attribute of the StateManagerMBean object * * @jmx:managed-attribute * * @param newStateFile The new StateFile value */ public void setStateFile(String newStateFile) { stateFile = newStateFile.trim(); } /** * @jmx:managed-attribute */ public StateManager getInstance() { return this; } /** * Sets the DurableSubscription attribute of the StateManager object * * @param server The new DurableSubscription value * @param sub The new DurableSubscription value * @param topic The new DurableSubscription value * @exception JMSException Description of Exception */ public void setDurableSubscription(JMSDestinationManager server, DurableSubscriptionID sub, SpyTopic topic) throws JMSException { boolean debug = log.isDebugEnabled(); if (debug) log.debug("Checking durable subscription: " + sub + ", on topic: " + topic); try { //Set the known Ids Enumeration enumeration = stateConfig.getElementsNamed("User"); while (enumeration.hasMoreElements()) { // Match the User.Name XElement user = (XElement)enumeration.nextElement(); if (!user.containsField("Id") || !user.getField("Id").equals(sub.getClientID())) { continue; } if (debug) log.debug("Found a matching ClientID configuration section."); XElement subscription = null; // Match the User/DurableSubscription.Name Enumeration enum2 = user.getElementsNamed("DurableSubscription"); while (enum2.hasMoreElements()) { XElement t = (XElement)enum2.nextElement(); if (t.getField("Name").equals(sub.getSubscriptionName())) { subscription = t; break; } } // A new subscription if (subscription == null) { if (debug) log.debug("The subscription was not previously registered."); // it was not previously registered... if (topic == null) { return; } JMSTopic dest = (JMSTopic)server.getJMSDestination(topic); dest.createDurableSubscription(sub); subscription = new XElement("DurableSubscription"); subscription.addField("Name", sub.getSubscriptionName()); subscription.addField("TopicName", topic.getName()); user.addElement(subscription); saveConfig(); } // An existing subscription...it was previously registered... // Check if it is an unsubscribe, or a change of subscription. else { if (debug) log.debug("The subscription was previously registered."); // The client wants an unsubscribe // TODO: we are not spec compliant since we neither check if // the topic has an active subscriber or if there are messages // destined for the client not yet acked by the session!!! if (topic == null) { // we have to change the subscription... SpyTopic prevTopic = new SpyTopic(subscription.getField("TopicName")); JMSTopic dest = (JMSTopic)server.getJMSDestination(prevTopic); // TODO here we should check if the client still has // an active consumer dest.destroyDurableSubscription(sub); //straight deletion, remove subscription subscription.removeFromParent(); saveConfig(); } // The topic previously subscribed to is not the same as the // one in the subscription request. // TODO: we do currently no check if the selector has changed. else if (!subscription.getField("TopicName").equals(topic.getName())) { //new topic so we have to change it if (debug) log.debug("But the topic was different, changing the subscription."); // we have to change the subscription... SpyTopic prevTopic = new SpyTopic(subscription.getField("TopicName")); JMSTopic dest = (JMSTopic)server.getJMSDestination(prevTopic); dest.destroyDurableSubscription(sub); dest = (JMSTopic)server.getJMSDestination(topic); dest.createDurableSubscription(sub); //durable subscription has new topic subscription.setField("TopicName", topic.getName()); saveConfig(); } } return; } // Could not find that user.. throw new JMSException("ClientID '" + sub.getClientID() + "' cannot create durable subscriptions."); } catch (IOException e) { JMSException newE = new SpyJMSException("Could not setup the durable subscription"); newE.setLinkedException(e); throw newE; } catch (XElementException e) { JMSException newE = new SpyJMSException("Could not setup the durable subscription"); newE.setLinkedException(e); throw newE; } } /** * Get the destination a subscription is for. */ public SpyTopic getDurableTopic(DurableSubscriptionID sub) throws JMSException { try { XElement subscription = getSubscription(sub); if (subscription == null) throw new JMSException("No durable subscription found for subscription: " + sub.getSubscriptionName()); return new SpyTopic(subscription.getField("TopicName")); }catch(XElementException e) { JMSException newE = new SpyJMSException("Could not find durable subscription"); newE.setLinkedException(e); throw newE; } } private XElement getSubscription(DurableSubscriptionID sub) throws JMSException,XElementException { boolean debug = log.isDebugEnabled(); //Set the known Ids XElement subscription = null; Enumeration enumeration = stateConfig.getElementsNamed("User"); while (enumeration.hasMoreElements()) { // Match the User.Name XElement user = (XElement)enumeration.nextElement(); if (!user.containsField("Id") || !user.getField("Id").equals(sub.getClientID())) { continue; } if (debug) log.debug("Found a matching ClientID configuration section."); //XElement subscription = null; // Match the User/DurableSubscription.Name Enumeration enum2 = user.getElementsNamed("DurableSubscription"); while (enum2.hasMoreElements()) { XElement t = (XElement)enum2.nextElement(); if (t.getField("Name").equals(sub.getSubscriptionName())) { subscription = t; //break; return subscription; } } } // Nothing found will be null return subscription; } /** * Gets the StateFile attribute of the StateManagerMBean object * * @jmx:managed-attribute * * @return The StateFile value */ public String getStateFile() { return stateFile; } /** * #Description of the Method * * @param login Description of Parameter * @param passwd Description of Parameter * @return Description of the Returned Value * @exception JMSException Description of Exception */ public String checkUser(String login, String passwd) throws JMSException { try { synchronized (stateConfig) { Enumeration enumeration = stateConfig.getElementsNamed("User"); while (enumeration.hasMoreElements()) { XElement element = (XElement)enumeration.nextElement(); String name = element.getField("Name"); if (!name.equals(login)) { continue; } String pw = element.getField("Password"); if (!passwd.equals(pw)) { throw new JMSException("Bad password"); } String clientId = null; if (element.containsField("Id")) { clientId = element.getField("Id"); } if (clientId != null) { synchronized (loggedOnClientIds) { if (loggedOnClientIds.contains(clientId)) { throw new JMSSecurityException ("The login id has an assigned client id. " + "That client id is already connected to the server!"); } loggedOnClientIds.add(clientId); } } return clientId; } throw new JMSSecurityException("This user does not exist"); } } catch (XElementException e) { log.error(e); throw new JMSException("Invalid server user configuration."); } } /** * Ad a logged in clientID to the statemanager. * * The clientID must not be active, and it must not be password protected. * * @param ID The feature to be added to the LoggedOnClientId * attribute * @exception JMSException Description of Exception */ public void addLoggedOnClientId(String ID) throws JMSException { //Check : this ID must not be registered synchronized (loggedOnClientIds) { if (loggedOnClientIds.contains(ID)) { throw new InvalidClientIDException("This loggedOnClientIds is already registered !"); } } //Check : this ID must not be password protected synchronized (stateConfig) { Enumeration enumeration = stateConfig.getElementsNamed("User"); while (enumeration.hasMoreElements()) { XElement element = (XElement)enumeration.nextElement(); try { if (element.containsField("Id") && element.getField("Id").equals(ID)) { throw new InvalidClientIDException("This loggedOnClientIds is password protected !"); } } catch (XElementException ignore) { } } } synchronized (loggedOnClientIds) { loggedOnClientIds.add(ID); } } /** * #Description of the Method * * @param ID Description of Parameter */ public void removeLoggedOnClientId(String ID) { synchronized (loggedOnClientIds) { loggedOnClientIds.remove(ID); } } /** * #Description of the Method * * @exception Exception Description of Exception */ public void startService() throws Exception { loadConfig(); } public Collection getDurableSubscriptionIdsForTopic(SpyTopic topic) throws JMSException { Collection durableSubs = new ArrayList(); try { Enumeration enumeration = stateConfig.getElementsNamed("User/DurableSubscription"); while (enumeration.hasMoreElements()) { XElement element = (XElement)enumeration.nextElement(); String clientId = element.getField("../Id"); String name = element.getField("Name"); String topicName = element.getField("TopicName"); if (topic.getName().equals(topicName)) { durableSubs.add(new DurableSubscriptionID(clientId, name, null)); } // end of if () } } catch (XElementException e) { JMSException jmse = new JMSException("Error in statemanager xml"); jmse.setLinkedException(e); throw jmse; } // end of try-catch return durableSubs; } /** * #Description of the Method * * @param server Description of Parameter * @exception XElementException Description of Exception */ /* public void initDurableSubscriptions(JMSServer server) throws XElementException { //Set the known Ids Enumeration enum = stateConfig.getElementsNamed("User/DurableSubscription"); while (enum.hasMoreElements()) { XElement element = (XElement)enum.nextElement(); String clientId = element.getField("../Id"); String name = element.getField("Name"); String topicName = element.getField("TopicName"); try { log.debug("Restarting Durable Subscription: " + clientId + "," + name + "," + topicName); SpyTopic topic = new SpyTopic(topicName); JMSTopic dest = (JMSTopic)server.getJMSDestination(topic); if (dest == null) { log.warn("Subscription topic of not found: " + topicName); log.warn("Subscription cannot be initialized: " + clientId + "," + name); element.removeFromParent(); } else { dest.createDurableSubscription(new DurableSubscriptionID(clientId, name)); } } catch (JMSException e) { log.error("Could not initialize a durable subscription for : Client Id=" + clientId + ", Name=" + name + ", Topic Name=" + topicName, e); } } } */ /** * @jmx:managed-operation */ public void loadConfig() throws IOException, XElementException { URL configURL = new URL(systemConfigURL, stateFile); if (log.isDebugEnabled()) { log.debug("Loading config from: " + configURL); } InputStream in = new BufferedInputStream(configURL.openStream()); try { stateConfig = XElement.createFrom(in); } finally { in.close(); } } /** * @jmx:managed-operation */ public void saveConfig() throws IOException { URL configURL = new URL(systemConfigURL, stateFile); if (configURL.getProtocol().equals("file")) { File file = new File(configURL.getFile()); if (log.isDebugEnabled()) { log.debug("Saving config to: " + file); } PrintStream stream = new PrintStream(new FileOutputStream(file)); try { stream.print(stateConfig.toXML(true)); } finally { stream.close(); } } else { log.error("Can not save configuration to non-file URL: " + configURL); } } /** * @jmx:managed-operation */ public String displayStateConfig() throws Exception { return stateConfig.toString(); } /* Does not seem to be used public class Identity { String login; String passwd; String loggedOnClientIds; Identity(final String login, final String passwd, final String loggedOnClientIds) { this.login = login; this.passwd = passwd; this.loggedOnClientIds = loggedOnClientIds; } } */ }