/* * 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; import hermes.browser.HermesBrowser; import hermes.browser.dialog.SelectorImpl; import hermes.config.ClasspathGroupConfig; import hermes.config.ConnectionConfig; import hermes.config.DestinationConfig; import hermes.config.FactoryConfig; import hermes.config.HermesConfig; import hermes.config.NamingConfig; import hermes.config.QuickFIXConfig; import hermes.config.SessionConfig; import hermes.config.WatchConfig; import hermes.fix.quickfix.QuickFIXMessageCache; import hermes.impl.ClassLoaderManager; import hermes.impl.ConnectionFactoryManager; import hermes.impl.ConnectionFactoryManagerImpl; import hermes.impl.ConnectionManager; import hermes.impl.ConnectionManagerFactory; import hermes.impl.DefaultHermesImpl; import hermes.impl.DestinationManager; import hermes.impl.JNDIDestinationManager; import hermes.impl.NullClassLoaderManager; import hermes.impl.SessionManager; import hermes.impl.SimpleClassLoaderManager; import hermes.impl.jms.SimpleDestinationManager; import hermes.impl.jms.ThreadLocalSessionManager; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.jms.JMSException; import javax.jms.QueueConnectionFactory; import javax.jms.TopicConnectionFactory; import javax.naming.Binding; import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.swing.JOptionPane; import javax.swing.UIManager; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.PropertyException; import javax.xml.bind.Unmarshaller; import javax.xml.transform.stream.StreamSource; import org.apache.log4j.Logger; /** * @author colincrist@hermesjms.com * @version $Id: JAXBHermesLoader.java,v 1.52 2007/02/18 19:01:42 colincrist Exp * $ */ public class JAXBHermesLoader implements HermesLoader { private static final Logger log = Logger.getLogger(JAXBHermesLoader.class); private static final String FILE_NAME = "hermes-config.xml"; private static final String DEFAULT_EXTENSION_LOADER = "hermes.ext.ExtensionFinderImpl"; private URL url; private File file; private HermesConfig config; private JAXBElement<HermesConfig> element; private ClassLoaderManager classLoaderManager; private Hashtable properties; private final Set listeners = new HashSet(); private final Map<String, FactoryConfig> factoryConfigById = new HashMap<String, FactoryConfig>(); private boolean ignoreClasspathGroups; private Context context; private String extensionLoaderClass = DEFAULT_EXTENSION_LOADER; private final ThreadLocal<JAXBContext> contextTL = new ThreadLocal<JAXBContext>() { @Override protected JAXBContext initialValue() { try { return JAXBContext.newInstance("hermes.config"); } catch (JAXBException e) { log.error(e.getMessage(), e); return null; } } }; public JAXBHermesLoader() { } @Override public void setContext(Context context) { this.context = context; } @Override public void backup() throws HermesException { try { if (file != null) { copyFile(file.getAbsolutePath(), file.getAbsolutePath() + ".backup"); } } catch (IOException e) { throw new HermesException(e); } } @Override public void restore() throws HermesException { try { if (file != null) { copyFile(file.getAbsolutePath() + ".backup", file.getAbsolutePath()); } } catch (IOException e) { throw new HermesException(e); } } @Override public void save() throws HermesException { try { if (file != null) { OutputStream ostream = new FileOutputStream(file); Marshaller m = contextTL.get().createMarshaller(); config.setLastEditedByHermesVersion(Hermes.VERSION); config.setLastEditedByUser(System.getProperty("user.name")); config.setLookAndFeel(UIManager.getLookAndFeel().getClass().getName()); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); element.setValue(config); m.marshal(element, ostream); ostream.close(); } else { throw new HermesException("No file to save configuration to (did you load from a URL?)"); } } catch (FileNotFoundException e) { throw new HermesException(e); } catch (PropertyException e) { throw new HermesException(e); } catch (JAXBException e) { throw new HermesException(e); } catch (IOException e) { throw new HermesException(e); } } /* * (non-Javadoc) * * @see hermes.HermesLoader#doLoad() */ @Override public void addDestinationConfig(Hermes hermes, DestinationConfig config) throws JMSException { if (factoryConfigById.containsKey(hermes.getId())) { FactoryConfig fConfig = factoryConfigById.get(hermes.getId()); fConfig.getDestination().add(config); hermes.addDestinationConfig(config); notifyDestinationAdded(hermes, config); } else { throw new HermesException("No such session " + hermes.getId()); } } @Override public void replaceDestinationConfigs(Hermes hermes, Collection dConfigs) throws JMSException { boolean keepDurableSubscriptions = true, keepDurableSubscriptionsDialogShown = false; // HJMS-139 for (final Iterator iter = dConfigs.iterator(); iter.hasNext();) { final DestinationConfig dConfig = (DestinationConfig) iter.next(); DestinationConfig oldConfig = null; try { if (dConfig.getDomain() == Domain.TOPIC.getId()) { oldConfig = hermes.getDestinationConfig(dConfig.getName(), Domain.TOPIC); } else { oldConfig = hermes.getDestinationConfig(dConfig.getName(), Domain.QUEUE); } } catch (Throwable t) { log.error(t.getMessage(), t); } if (oldConfig != null && oldConfig.getProperties() != null) { dConfig.setProperties(oldConfig.getProperties()); } } // End HJMS-139 if (factoryConfigById.containsKey(hermes.getId())) { final FactoryConfig fConfig = factoryConfigById.get(hermes.getId()); for (final Iterator iter = fConfig.getDestination().iterator(); iter.hasNext();) { final DestinationConfig dConfig = (DestinationConfig) iter.next(); if (dConfig.getDomain() == Domain.TOPIC.getId() && dConfig.isDurable()) { if (!keepDurableSubscriptionsDialogShown) { if (HermesBrowser.getBrowser() != null) { if (JOptionPane.showConfirmDialog(HermesBrowser.getBrowser(), "Do you want to keep configured durable subscriptions?", "Durable Subscriptions", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) { keepDurableSubscriptions = false; } } keepDurableSubscriptionsDialogShown = true; } if (!keepDurableSubscriptions) { iter.remove(); notifyDestinationRemoved(hermes, dConfig); } } else { iter.remove(); notifyDestinationRemoved(hermes, dConfig); } } for (final Iterator iter = dConfigs.iterator(); iter.hasNext();) { final DestinationConfig dConfig = (DestinationConfig) iter.next(); fConfig.getDestination().add(dConfig); hermes.addDestinationConfig(dConfig); notifyDestinationAdded(hermes, dConfig); } } else { throw new HermesException("No such session " + hermes.getId()); } } /** * Everything is in here to load up all the Hermes instances from JAXB, it * kinda sux really. Would be nice to have proper framework for this. */ @Override public List<Hermes> load() throws HermesException { ArrayList<Hermes> rval = null; InputStream istream = null; String from; factoryConfigById.clear(); if (properties == null) { throw new HermesException("No properties available"); } try { if (file == null) { if (!properties.containsKey(Context.PROVIDER_URL)) { from = FILE_NAME; } else { from = (String) properties.get(Context.PROVIDER_URL); } log.debug("attempting to load from URL: " + from); try { istream = new URL(from).openStream(); } catch (IOException ex) { log.info("failed to load configuration from " + from + ", attempting to load as a file..."); } if (istream == null) { file = new File(from); log.debug("trying to load from file: " + file.getName()); if (!file.exists()) { throw new NoConfigurationException(); } istream = new FileInputStream(file); } } else { istream = new FileInputStream(file); } rval = new ArrayList<Hermes>(); Unmarshaller u = contextTL.get().createUnmarshaller(); element = u.unmarshal(new StreamSource(istream), HermesConfig.class); config = element.getValue(); Hermes.ui.setConfig(config); if (config.getLastEditedByHermesVersion() == null) { // // First time Hermes1.7RC3 was run with this config config.setLastEditedByHermesVersion(Hermes.VERSION); config.setDisplayFactoryAdmin(true); } // This is for the 1.10 upgrade if (config.getQuickFIX() == null) { QuickFIXConfig quickFIXConfig = new QuickFIXConfig(); quickFIXConfig.setCacheSize(1024); config.setQuickFIX(quickFIXConfig); } config.setSelectorImpl(SelectorImpl.JAMSEL.getClazz().getName()); // This is for the 1.9 upgrdfe if (config.getAutoBrowseRefreshRate() == 0) { config.setAutoBrowseRefreshRate(10); } // // This is for the 1.8 upgrade if (config.getMaxColumnsInStatisticsTable() == 0) { config.setMaxColumnsInStatisticsTable(10); } // // This is for the 1.7 upgrade where we want to move the old global // classloader into a default ClassloaderGroup. if (config.getLoader() != null && config.getLoader().size() > 0) { ClasspathGroupConfig gConfig = new ClasspathGroupConfig(); gConfig.setId(SimpleClassLoaderManager.DEFAULT_LOADER); gConfig.getLibrary().addAll(config.getLoader()); config.getClasspathGroup().clear(); config.getClasspathGroup().add(gConfig); config.getLoader().clear(); } if (!ignoreClasspathGroups) { classLoaderManager = new SimpleClassLoaderManager(config.getClasspathGroup()); } else { classLoaderManager = new NullClassLoaderManager(); } SingletonManager.put(ClassLoaderManager.class, classLoaderManager); // // QuickFIX QuickFIXMessageCache cache = (QuickFIXMessageCache) SingletonManager.get(QuickFIXMessageCache.class); cache.setSize(config.getQuickFIX().getCacheSize()); // // Deal with any renderers HermesBrowser.getRendererManager().setConfig(classLoaderManager.getDefaultClassLoader(), config); Hermes.ui.getThreadPool().setThreads(config.getMaxThreadPoolSize()); // HermesBrowser.getThreadPool().setClassLoader(classLoader); if (config.getWatch() == null) { // // Maybe an upgrade from a pre-1.6 version, fill in what should // be there in the config. WatchConfig wConfig = new WatchConfig(); wConfig.setShowAge(true); config.getWatch().add(wConfig); } for (Iterator iter = config.getFactory().iterator(); iter.hasNext();) { final FactoryConfig factoryConfig = (FactoryConfig) iter.next(); /* * If for some reason the XML has no connection or sesssion then * clean up the XML. */ if (factoryConfig.getConnection().size() == 0) { log.debug("cleaning up FactoryConfig with no connections"); iter.remove(); continue; } ConnectionConfig firstConnection = factoryConfig.getConnection().get(0); if (firstConnection.getSession().size() == 0) { log.debug("cleaning up FactoryConfig with no sessions"); iter.remove(); continue; } SessionConfig firstSession = firstConnection.getSession().get(0); if (firstSession.getId() == null) { log.debug("cleaning up FactoryConfig with a null session"); iter.remove(); continue; } try { Hermes hermes = createHermes(factoryConfig); rval.add(hermes); notifyHermesAdded(hermes); for (Iterator diter = hermes.getDestinations(); diter.hasNext();) { DestinationConfig destinationConfig = (DestinationConfig) diter.next(); boolean isQueue = hermes.getConnectionFactory() instanceof QueueConnectionFactory; boolean isTopic = hermes.getConnectionFactory() instanceof TopicConnectionFactory; if (destinationConfig.getDomain() == 0 && HermesBrowser.getBrowser() != null) { if (isQueue && isTopic) { Object options[] = { "Queue", "Topic" }; int n = JOptionPane.showOptionDialog(HermesBrowser.getBrowser(), "This XML is from an older version of Hermes and it is unclear which domain the destination\n" + destinationConfig.getName() + " for session " + hermes.getId() + " is in. Please choose whether queue or topic domain", "Select domain", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]); if (n == JOptionPane.YES_OPTION) { isQueue = true; isTopic = false; log.info(destinationConfig.getName() + " is now in the queue domain"); } else { isQueue = false; isTopic = true; log.info(destinationConfig.getName() + " is now in the topic domain"); } } if (isQueue) { destinationConfig.setDomain(Domain.QUEUE.getId()); } else if (isTopic) { destinationConfig.setDomain(Domain.TOPIC.getId()); } } notifyDestinationAdded(hermes, destinationConfig); } } catch (Throwable t) { log.error("unable to create Hermes instance " + firstSession.getId() + ": " + t.getMessage(), t); } } return rval; } catch (Exception ex) { log.error(ex.getMessage(), ex); HermesBrowser.getBrowser().showErrorDialog("Unable to load configuration", ex); throw new HermesException(ex); } } @Override public Hermes createHermes(FactoryConfig factoryConfig) throws JAXBException, IOException, JMSException, NamingException, InstantiationException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { Hermes hermes = null; ConnectionFactoryManager connectionFactoryManager = null; JNDIConnectionFactory jndiFactory = null; if (factoryConfig.getExtension() == null) { factoryConfig.setExtension(HermesBrowser.getConfigDAO().createDefaultProviderExtConfig(factoryConfig.getProvider().getClassName())); } ClassLoader classLoader = getClass().getClassLoader(); if (factoryConfig.getClasspathId() == null) { factoryConfig.setClasspathId(SimpleClassLoaderManager.DEFAULT_LOADER); } classLoader = classLoaderManager.createClassLoader(factoryConfig.getClasspathId(), factoryConfig.getExtension()); Thread.currentThread().setContextClassLoader(classLoader); connectionFactoryManager = new ConnectionFactoryManagerImpl(classLoaderManager, factoryConfig); // // You can now get the factory from the manager. if (factoryConfig.getProvider().getClassName().equals(JNDIConnectionFactory.class.getName()) || factoryConfig.getProvider().getClassName().equals(JNDIQueueConnectionFactory.class.getName()) || factoryConfig.getProvider().getClassName().equals(JNDITopicConnectionFactory.class.getName())) { jndiFactory = (JNDIConnectionFactory) connectionFactoryManager.getConnectionFactory(); jndiFactory._setDelegateClassLoader(classLoader); } for (Iterator iter2 = factoryConfig.getDestination().iterator(); iter2.hasNext();) { DestinationConfig destinationConfig = (DestinationConfig) iter2.next(); if (destinationConfig.isDurable() && destinationConfig.getClientID() == null) { log.warn("removing durable subscription to " + destinationConfig.getName() + "with a null clientID"); iter2.remove(); } else { connectionFactoryManager.addDestinationConfig(destinationConfig); } } if (factoryConfig.getConnection().size() > 0) { ConnectionConfig connectionConfig = factoryConfig.getConnection().get(0); ConnectionManager connectionManager = null; if (connectionConfig.isConnectionPerThread()) { connectionManager = ConnectionManagerFactory.create(ConnectionManager.Policy.CONNECTION_PER_THREAD); } else { connectionManager = ConnectionManagerFactory.create(ConnectionManager.Policy.SHARED_CONNECTION); } connectionManager.setClientID(connectionConfig.getClientID()); connectionManager.setUsername(connectionConfig.getUsername()); connectionManager.setPassword(connectionConfig.getPassword()); if (connectionConfig.getSession().size() > 0) { SessionManager sessionManager; DestinationManager destinationManager; SessionConfig sessionConfig = connectionConfig.getSession().get(0); if (jndiFactory != null) { jndiFactory._setDelegateClassLoader(classLoader); destinationManager = new JNDIDestinationManager(jndiFactory._getProperties(), true); sessionManager = new ThreadLocalSessionManager(sessionConfig, destinationManager); } else { destinationManager = new SimpleDestinationManager(); sessionManager = new ThreadLocalSessionManager(sessionConfig, destinationManager); } log.debug("SESSION IS " + sessionConfig.getId()); if (sessionConfig.getReconnects() != null) { sessionManager.setReconnects(sessionConfig.getReconnects().intValue()); } classLoaderManager.putClassLoaderByHermes(sessionConfig.getId(), classLoader); factoryConfigById.put(sessionConfig.getId(), factoryConfig); sessionManager.setTransacted(sessionConfig.isTransacted()); sessionManager.setId(sessionConfig.getId()); sessionManager.setFactoryConfig(factoryConfig); sessionManager.setAudit(sessionConfig.isAudit()); sessionManager.setParent(connectionManager); connectionManager.setParent(connectionFactoryManager); if (config.getAuditDirectory() != null) { sessionManager.setAuditDirectory(config.getAuditDirectory()); } else if (sessionConfig.getAuditDirectory() != null) { sessionManager.setAuditDirectory(sessionConfig.getAuditDirectory()); } connectionManager.addChild(sessionManager); hermes = new DefaultHermesImpl(factoryConfig.getExtension(), sessionManager, classLoader); connectionFactoryManager.addChild(connectionManager); connectionManager.setHermes(hermes); } } return hermes; } /* * (non-Javadoc) * * @see hermes.HermesLoader#getConfig() */ @Override public HermesConfig getConfig() throws HermesException { return config; } private static void copyFile(String src, String dest) throws IOException { File destFile = new File(dest); if (destFile.exists()) { destFile.delete(); } FileChannel srcChannel = new FileInputStream(src).getChannel(); FileChannel dstChannel = new FileOutputStream(dest).getChannel(); dstChannel.transferFrom(srcChannel, 0, srcChannel.size()); srcChannel.close(); dstChannel.close(); } /* * (non-Javadoc) * * @see hermes.HermesLoader#setProperties(java.util.Hashtable) */ @Override public void setProperties(Hashtable map) { this.properties = map; } @Override public Iterator getConfigurationListeners() { return listeners.iterator(); } @Override public void addConfigurationListener(HermesConfigurationListener listener) { listeners.add(listener); // // Give it its initial state.. try { for (NamingEnumeration e = context.listBindings(""); e.hasMore();) { Binding binding = (Binding) e.next(); try { if (context.lookup(binding.getName()) instanceof Hermes) { Hermes hermes = (Hermes) context.lookup(binding.getName()); listener.onHermesAdded(hermes); for (Iterator diter = hermes.getDestinations(); diter.hasNext();) { DestinationConfig destinationConfig = (DestinationConfig) diter.next(); listener.onDestinationAdded(hermes, destinationConfig); } } } catch (NamingException ex) { // NOP } } for (Iterator namingIter = config.getNaming().iterator(); namingIter.hasNext();) { NamingConfig namingConfig = (NamingConfig) namingIter.next(); listener.onNamingAdded(namingConfig); } } catch (NamingException e) { log.error(e.getMessage(), e); } } public void removeConfigurationListener(HermesConfigurationListener listener) { listeners.remove(listener); } public void notifyNamingAdded(NamingConfig namingConfig) { for (Iterator iter = listeners.iterator(); iter.hasNext();) { HermesConfigurationListener listener = (HermesConfigurationListener) iter.next(); listener.onNamingAdded(namingConfig); } } @Override public void notifyNamingRemoved(NamingConfig namingConfig) { for (Iterator iter = listeners.iterator(); iter.hasNext();) { HermesConfigurationListener listener = (HermesConfigurationListener) iter.next(); listener.onNamingRemoved(namingConfig); } } public void notifyHermesAdded(Hermes hermes) { for (Iterator iter = listeners.iterator(); iter.hasNext();) { HermesConfigurationListener listener = (HermesConfigurationListener) iter.next(); listener.onHermesAdded(hermes); } } @Override public void notifyHermesRemoved(Hermes hermes) { for (Iterator iter = listeners.iterator(); iter.hasNext();) { HermesConfigurationListener listener = (HermesConfigurationListener) iter.next(); listener.onHermesRemoved(hermes); } } public void notifyDestinationAdded(Hermes hermes, DestinationConfig destinationConfig) { for (Iterator iter = listeners.iterator(); iter.hasNext();) { HermesConfigurationListener listener = (HermesConfigurationListener) iter.next(); listener.onDestinationAdded(hermes, destinationConfig); } } public void notifyDestinationRemoved(Hermes hermes, DestinationConfig destinationConfig) { for (Iterator iter = listeners.iterator(); iter.hasNext();) { HermesConfigurationListener listener = (HermesConfigurationListener) iter.next(); listener.onDestinationRemoved(hermes, destinationConfig); } } /** * @return Returns the context. */ @Override public Context getContext() { return context; } /** * @param extensionLoaderClass * The extensionLoaderClass to set. */ @Override public void setExtensionLoaderClass(String extensionLoader) { this.extensionLoaderClass = extensionLoader; } @Override public ClassLoaderManager getClassLoaderManager() { return classLoaderManager; } public boolean isIgnoreClasspathGroups() { return ignoreClasspathGroups; } @Override public void setIgnoreClasspathGroups(boolean ignoreClasspathGroups) { this.ignoreClasspathGroups = ignoreClasspathGroups; } }