summaryrefslogtreecommitdiff
path: root/qpid/java/broker-plugins/experimental
diff options
context:
space:
mode:
authorRajith Muditha Attapattu <rajith@apache.org>2011-05-27 15:44:23 +0000
committerRajith Muditha Attapattu <rajith@apache.org>2011-05-27 15:44:23 +0000
commit66765100f4257159622cefe57bed50125a5ad017 (patch)
treea88ee23bb194eb91f0ebb2d9b23ff423e3ea8e37 /qpid/java/broker-plugins/experimental
parent1aeaa7b16e5ce54f10c901d75c4d40f9f88b9db6 (diff)
parent88b98b2f4152ef59a671fad55a0d08338b6b78ca (diff)
downloadqpid-python-66765100f4257159622cefe57bed50125a5ad017.tar.gz
Creating a branch for experimenting with some ideas for JMS client.rajith_jms_client
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/rajith_jms_client@1128369 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java/broker-plugins/experimental')
-rw-r--r--qpid/java/broker-plugins/experimental/info/MANIFEST.MF16
-rw-r--r--qpid/java/broker-plugins/experimental/info/build.properties31
-rw-r--r--qpid/java/broker-plugins/experimental/info/build.xml32
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/Activator.java204
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/AppInfo.java94
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/Info.java143
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/InfoService.java30
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/InfoServiceImpl.java66
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/SystemInfo.java91
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/HttpPoster.java130
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/IniFileReader.java193
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/SoapClient.java155
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/XMLWriter.java100
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/systest/InfoPluginTest.java276
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/HttpPosterTest.java107
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/InfoServiceImplTest.java63
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/InfoServlet.java57
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/InfoTest.java112
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/IniFileReaderTest.java136
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/SoapClientTest.java208
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/SystemInfoTest.java56
-rw-r--r--qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/XMLWriterTest.java132
-rw-r--r--qpid/java/broker-plugins/experimental/shutdown/MANIFEST.MF15
-rw-r--r--qpid/java/broker-plugins/experimental/shutdown/build.xml32
-rw-r--r--qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Activator.java71
-rw-r--r--qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Shutdown.java104
-rw-r--r--qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/ShutdownMBean.java47
-rwxr-xr-xqpid/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd25
28 files changed, 2726 insertions, 0 deletions
diff --git a/qpid/java/broker-plugins/experimental/info/MANIFEST.MF b/qpid/java/broker-plugins/experimental/info/MANIFEST.MF
new file mode 100644
index 0000000000..f213104d8d
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/MANIFEST.MF
@@ -0,0 +1,16 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: QpidPlugin
+Bundle-SymbolicName: qpid_info_plugin;singleton:=true
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-Version: 1.0.0
+Bundle-Activator: org.apache.qpid.info.Activator
+Import-Package: org.apache.qpid.server.configuration,
+ org.osgi.framework,
+ org.apache.qpid.common,
+ org.apache.qpid.server.registry
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ClassPath: .
+Bundle-ActivationPolicy: lazy
+Export-Package: org.apache.qpid.info;uses:="org.osgi.framework"
+
diff --git a/qpid/java/broker-plugins/experimental/info/build.properties b/qpid/java/broker-plugins/experimental/info/build.properties
new file mode 100644
index 0000000000..bdbbe1c2af
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/build.properties
@@ -0,0 +1,31 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ lib/eventTrackerClient-2.7.0.jar,\
+ lib/commons-logging-1.0.4.jar
+src.includes = src/,\
+ plugin.xml,\
+ lib/,\
+ build.properties,\
+ bin/,\
+ META-INF/
diff --git a/qpid/java/broker-plugins/experimental/info/build.xml b/qpid/java/broker-plugins/experimental/info/build.xml
new file mode 100644
index 0000000000..c5881aa839
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/build.xml
@@ -0,0 +1,32 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+nn - or more contributor license agreements. See the NOTICE file
+ -n distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you 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.
+ -
+ -->
+<project name="AMQ Broker Info Plugin" default="build">
+
+ <property name="module.depends" value="common broker broker-plugins"/>
+ <property name="module.test.depends" value="test broker/test management/common client systests common/test"/>
+ <property name="module.manifest" value="MANIFEST.MF"/>
+ <property name="module.plugin" value="true"/>
+
+ <import file="../../../module.xml"/>
+
+ <target name="bundle" depends="bundle-tasks"/>
+
+</project>
diff --git a/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/Activator.java b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/Activator.java
new file mode 100644
index 0000000000..c7d3fd38ff
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/Activator.java
@@ -0,0 +1,204 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info;
+
+import org.apache.qpid.info.util.HttpPoster;
+import org.apache.qpid.info.util.IniFileReader;
+import org.apache.qpid.info.util.SoapClient;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/** The Activator class for the OSGI info service */
+public class Activator implements BundleActivator
+{
+
+ private final List<String> _soapPropList = Arrays.asList("soap.hostname",
+ "soap.port", "soap.path", "soap.action", "soap.envelope");
+
+ private final List<String> _httpPropList = Arrays.asList("http.url",
+ "http.envelope");
+
+ InfoServiceImpl _service = null;
+
+ BundleContext _ctx = null;
+
+ /**
+ * Start bundle method
+ *
+ * @param ctx the bundle context
+ */
+ public void start(BundleContext ctx) throws Exception
+ {
+ if (null != ctx)
+ {
+ _ctx = ctx;
+ _service = new InfoServiceImpl();
+ ctx.registerService(InfoService.class.getName(), _service, null);
+ sendInfo("STARTUP");
+ }
+ }
+
+ /**
+ * Stop the bundle method
+ *
+ * @param ctx the bundle context
+ */
+ public void stop(BundleContext ctx) throws Exception
+ {
+ sendInfo("SHUTDOWN");
+ }
+
+ /**
+ * Sends the information message
+ *
+ * @param action label that identifies if we are starting up or shutting down
+ */
+ private void sendInfo(String action)
+ {
+ if ((null == _ctx) && (null == _service))
+ {
+ // invalid state
+ return;
+ }
+
+ IniFileReader ifr = new IniFileReader();
+ try
+ {
+ String QPID_HOME = System.getProperty("QPID_HOME");
+ String cfgFilePath = QPID_HOME + File.separator + "etc"
+ + File.separator + "qpidinfo.ini";
+ ifr.load(cfgFilePath);
+ }
+ catch (Throwable ex)
+ {
+ // drop everything to be silent
+ return;
+ }
+
+ // Only send Messages if we have some sections.
+ if (ifr.getSections().size() != 0)
+ {
+ Info<? extends Map<String, ?>> info = _service.invoke(action);
+ String protocol = ifr.getSections().get("").getProperty("protocol");
+ sendMessages(protocol, ifr, info);
+ }
+ }
+
+ /**
+ * Sends all the messages configured in the properties file
+ *
+ * @param protocol indicates what protocol to be used: http and soap implemented
+ * for now
+ * @param ifr an instance of IniFileReader class
+ * @param info an instance of an Info object, encapsulating the information
+ * we want to send
+ */
+ private void sendMessages(String protocol, IniFileReader ifr,
+ Info<? extends Map<String, ?>> info)
+ {
+ if (null != protocol)
+ {
+ // Set the global properties first (as they are the defaults)
+ Properties defaultProps = ifr.getSections().get("");
+ if (protocol.toLowerCase().startsWith("http"))
+ {
+ for (String section : ifr.getSections().keySet())
+ {
+ // Skip the defaults
+ if (section.equals(""))
+ {
+ continue;
+ }
+ Properties props = new Properties();
+ props.putAll(defaultProps);
+ props.putAll(ifr.getSections().get(section));
+ if (isValid(protocol, props))
+ {
+ new HttpPoster(props, info.toXML()).run();
+ }
+ }
+
+ }
+ else if (protocol.toLowerCase().startsWith("soap"))
+ {
+ for (String section : ifr.getSections().keySet())
+ {
+ Properties props = new Properties();
+ props.putAll(defaultProps);
+ props.putAll(ifr.getSections().get(section));
+ if (isValid(protocol, props))
+ {
+ new SoapClient(info.toMap(), props).sendSOAPMessage();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if the properties for a specified protocol are valid
+ *
+ * @param protocol String representing the protocol
+ * @param props The properties associate with the specified protocol
+ * @return boolean
+ */
+ private boolean isValid(String protocol, Properties props)
+ {
+ if (null == protocol)
+ {
+ return false;
+ }
+ String value = "";
+ if (protocol.toLowerCase().startsWith("http"))
+ {
+ for (String prop : _httpPropList)
+ {
+ if (null == props.get(prop))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (protocol.toLowerCase().startsWith("soap"))
+ {
+ for (String prop : _soapPropList)
+ {
+ value = props.getProperty(prop);
+ if (null == value)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+} // end class
+
diff --git a/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/AppInfo.java b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/AppInfo.java
new file mode 100644
index 0000000000..a5d267282b
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/AppInfo.java
@@ -0,0 +1,94 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info;
+
+import org.apache.qpid.common.QpidProperties;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.TreeMap;
+
+/** AppInfo class is gathering application specific information */
+public class AppInfo
+{
+
+ private static final List<String> appProps = Arrays.asList("QPID_HOME",
+ "QPID_WORK");
+
+ private static Map<String, String> appInfoMap = new TreeMap<String, String>();
+
+ /**
+ * getInfo method retrieves a key-value map for specific application properties
+ *
+ * @return Map<String,String>
+ */
+ public static Map<String, String> getInfo()
+ {
+
+ // Gather the selected app props
+ Properties sysprops = System.getProperties();
+ String propName;
+ for (Iterator<Entry<Object, Object>> it = sysprops.entrySet()
+ .iterator(); it.hasNext();)
+ {
+ Entry<Object, Object> en = it.next();
+ propName = en.getKey().toString();
+ if (appProps.indexOf(propName) >= 0)
+ {
+ appInfoMap.put(propName, en.getValue().toString());
+ }
+ }
+
+ ServerConfiguration sc;
+ try
+ {
+ sc = ApplicationRegistry.getInstance().getConfiguration();
+ if (null != sc)
+ {
+ appInfoMap.put("jmxport", sc.getJMXManagementPort() + "");
+ appInfoMap.put("port", sc.getPorts().toString());
+ appInfoMap.put("version", QpidProperties.getReleaseVersion());
+ appInfoMap.put("vhosts", "standalone");
+ appInfoMap.put("JMXPrincipalDatabase", sc
+ .getJMXPrincipalDatabase());
+ appInfoMap.put("KeystorePath", sc.getKeystorePath());
+ appInfoMap.put("PluginDirectory", sc.getPluginDirectory());
+ appInfoMap.put("CertType", sc.getCertType());
+ appInfoMap.put("QpidWork", sc.getQpidWork());
+ appInfoMap.put("Bind", sc.getBind());
+ }
+ }
+ catch (Exception e)
+ {
+ // drop everything to be silent
+ }
+ return appInfoMap;
+
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/Info.java b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/Info.java
new file mode 100644
index 0000000000..2fb9382526
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/Info.java
@@ -0,0 +1,143 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+ */
+
+/**
+ *
+ * @author sorin
+ *
+ * Info object
+ */
+
+package org.apache.qpid.info;
+
+import org.apache.qpid.info.util.XMLWriter;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * The Info class encapsulates all the information we are collecting
+ * and it is able to render it in different data representations
+ */
+public class Info<T extends Map<String, ?>>
+{
+ private T _info;
+
+ /**
+ * Constructor.
+ *
+ * @param info instantiates the object with a Map<String,?>
+ */
+ public Info(T info)
+ {
+ _info = info;
+ }
+
+ @Override
+ public String toString()
+ {
+ String result = "";
+ for (Iterator<String> it = _info.keySet().iterator(); it.hasNext();)
+ {
+ String str = it.next();
+ result += str + "=" + _info.get(str).toString() + "\n";
+ }
+ return result;
+ }
+
+ /**
+ * Renders Info map to a property object
+ *
+ * @return A Properties object representing the Info map
+ */
+ public Properties toProps()
+ {
+ Properties props = new Properties();
+ if (null == _info)
+ {
+ return null;
+ }
+ for (Iterator<String> it = _info.keySet().iterator(); it.hasNext();)
+ {
+ String key = it.next();
+ props.put(key, _info.get(key));
+ }
+ return props;
+ }
+
+ /**
+ * Renders Info map to a StringBuffer
+ *
+ * @return A StringBuffer object representing the Info map
+ */
+ public StringBuffer toStringBuffer()
+ {
+ StringBuffer sb = new StringBuffer();
+ for (Iterator<String> it = _info.keySet().iterator(); it.hasNext();)
+ {
+ String str = it.next();
+ sb.append(str + "=" + _info.get(str).toString() + "\n");
+ }
+ return sb;
+ }
+
+ /**
+ * Renders Info map to a StringBuffer containing an XML string
+ *
+ * @return A StringBuffer object containing an XML representation of the Info map
+ */
+ public StringBuffer toXML()
+ {
+ XMLWriter xw = new XMLWriter(new StringBuffer());
+ xw.writeXMLHeader();
+ Map<String, String> attr = new HashMap<String, String>();
+ xw.writeOpenTag("qpidinfo", attr);
+ String key;
+ for (Iterator<String> it = _info.keySet().iterator(); it.hasNext();)
+ {
+ attr.clear();
+ key = it.next();
+ xw.writeTag(key, attr, _info.get(key).toString());
+ }
+ xw.writeCloseTag("qpidinfo");
+ return xw.getXML();
+ }
+
+ /**
+ * Renders Info map to a HashMap
+ *
+ * @return A HashMap object representing the Info map
+ */
+ public HashMap<String, String> toMap()
+ {
+ String key;
+ HashMap<String, String> infoMap = new HashMap<String, String>();
+ for (Iterator<String> it = _info.keySet().iterator(); it.hasNext();)
+ {
+ key = it.next();
+ infoMap.put(key, _info.get(key).toString());
+ }
+ return infoMap;
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/InfoService.java b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/InfoService.java
new file mode 100644
index 0000000000..2804dfb1b4
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/InfoService.java
@@ -0,0 +1,30 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+ */
+
+ /**
+ * Interface exposing the service methods
+ */
+ package org.apache.qpid.info;
+
+ public interface InfoService
+ {
+ public Info<?> invoke(String action);
+ }
diff --git a/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/InfoServiceImpl.java b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/InfoServiceImpl.java
new file mode 100644
index 0000000000..5522f2701e
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/InfoServiceImpl.java
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+ */
+
+/**
+ *
+ * @author sorin
+ *
+ * Implementation for Info service
+ */
+
+package org.apache.qpid.info;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+
+public class InfoServiceImpl implements InfoService
+{
+
+ SortedMap<String, String> infoMap = new TreeMap<String, String>();
+
+ /**
+ * invoke method collects all the information from System and Application
+ * and encapsulates them in an Info object
+ * @return An instance of an Info object
+ */
+ public Info<? extends Map<String,?>> invoke(String action)
+ {
+ // Record the action (STARTUP/SHUTDOWN)
+ infoMap.put("action",action);
+
+ // Record the current time stamp
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
+ infoMap.put("time", sdf.format(Calendar.getInstance().getTime()));
+
+ // Add the system specific properties
+ infoMap.putAll(SystemInfo.getInfo());
+
+ // Add the application specific properties
+ infoMap.putAll(AppInfo.getInfo());
+
+ return new Info<SortedMap<String, String>>(infoMap);
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/SystemInfo.java b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/SystemInfo.java
new file mode 100644
index 0000000000..8bd94fe14d
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/SystemInfo.java
@@ -0,0 +1,91 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+import java.util.Map.Entry;
+
+/**
+ * Collector for system specific information
+ */
+public class SystemInfo
+{
+
+ private static Map<String, String> sysInfoMap = new TreeMap<String, String>();
+
+ private static final List<String> sysProps = Arrays.asList(
+ "java.class.path", "java.home", "java.vm.name", "java.vm.vendor",
+ "java.vm.version", "java.class.version", "java.runtime.version",
+ "os.arch", "os.name", "os.version", "sun.arch.data.model",
+ "user.home", "user.dir", "user.name", "user.timezone");
+
+ /**
+ * getInfo collects all the properties specified in sysprops list
+ * @return A Map<String,String>
+ */
+ public static Map<String, String> getInfo()
+ {
+
+ // Get the hostname
+ try
+ {
+ InetAddress addr = InetAddress.getLocalHost();
+ String hostname = addr.getHostName();
+ sysInfoMap.put("hostname", hostname);
+ sysInfoMap.put("ip", addr.getHostAddress());
+ }
+ catch (UnknownHostException e)
+ {
+ // drop everything to be silent
+ }
+ // Get the runtime info
+ sysInfoMap.put("CPUCores", Runtime.getRuntime().availableProcessors()
+ + "");
+ sysInfoMap.put("Maximum_Memory", Runtime.getRuntime().maxMemory() + "");
+ sysInfoMap.put("Free_Memory", Runtime.getRuntime().freeMemory() + "");
+
+ // Gather the selected system props
+ Properties sysprops = System.getProperties();
+ String propName;
+ for (Iterator<Entry<Object, Object>> it = sysprops.entrySet()
+ .iterator(); it.hasNext();)
+ {
+ Entry<Object, Object> en = it.next();
+ propName = en.getKey().toString();
+ if (sysProps.indexOf(propName) >= 0)
+ {
+ sysInfoMap.put(propName, en.getValue().toString());
+ }
+ }
+
+ return sysInfoMap;
+
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/HttpPoster.java b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/HttpPoster.java
new file mode 100644
index 0000000000..d27980be05
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/HttpPoster.java
@@ -0,0 +1,130 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info.util;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.InetAddress;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.UnknownHostException;
+
+/**
+ *
+ * An simple Http post class for qpid info service
+ */
+public class HttpPoster implements Runnable
+{
+ private final String _url;
+
+ private final Hashtable<String, String> _header;
+
+ private final List<String> _response = new ArrayList<String>();
+
+ private final StringBuffer _buf;
+
+ /**
+ * Constructor
+ *
+ * @param props Properties containing the URL
+ * @param buf Buffer containing the message to be posted
+ */
+ public HttpPoster(Properties props, StringBuffer buf)
+ {
+ _buf = buf;
+ if (null != props)
+ {
+ _url = props.getProperty("http.url");
+ _header = new Hashtable<String, String>();
+ try
+ {
+ String hostname = InetAddress.getLocalHost().getHostName();
+ _header.put("hostname", hostname);
+ }
+ catch (UnknownHostException e)
+ {
+ // Silently ignoring the error ;)
+ }
+ }
+ else
+ {
+ _url = null;
+ _header = null;
+ }
+ }
+
+ /** Posts the message from the _buf StringBuffer to the http server */
+ public void run()
+ {
+ if (null == _url)
+ {
+ return;
+ }
+ String line;
+ URL urlDest;
+ URLConnection urlConn;
+ try
+ {
+ urlDest = new URL(_url);
+ urlConn = urlDest.openConnection();
+ urlConn.setDoOutput(true);
+ urlConn.setUseCaches(false);
+ for (Iterator<String> it = _header.keySet().iterator(); it.hasNext();)
+ {
+ String prop = it.next();
+ urlConn.setRequestProperty(prop, _header.get(prop));
+ }
+ OutputStreamWriter wr =
+ new OutputStreamWriter(urlConn.getOutputStream());
+ wr.write(_buf.toString());
+ wr.flush();
+ // Get the response
+ BufferedReader rd = new BufferedReader(new InputStreamReader(
+ urlConn.getInputStream()));
+ while ((line = rd.readLine()) != null)
+ {
+ _response.add(line);
+ }
+ }
+ catch (Exception ex)
+ {
+ // Silently ignoring the error ;)
+ }
+ }
+
+ /**
+ * Retrieves the response from the http server
+ *
+ * @return List<String> response received from the http server
+ */
+ public List<String> get_response()
+ {
+ return _response;
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/IniFileReader.java b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/IniFileReader.java
new file mode 100644
index 0000000000..60a025d322
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/IniFileReader.java
@@ -0,0 +1,193 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * This class is simple implementation of an ini file reader. It expects a
+ * file with the following structure:
+ *
+ * ; global values, can be overwritten in sections
+ * key1=value1
+ * key2=value2
+ *
+ * [Section1]
+ * key1=value1_new ; overwriting the global key1
+ * key3=value3
+ * key4=value4
+ *
+ * [Section2]
+ * key5=value5
+ * key6=value6
+ * key7=value7
+ *
+ * Note: Commentaries are preceded by ; or # and are supported throughout
+ * A commentary line at the end of section is interpreted as
+ * a section end marker
+ *
+ * A structure <String,Properties> (section name, associated properties)
+ * is generated as a result of processing the ini file.
+ */
+public class IniFileReader
+{
+ private final Map<String, Properties> _sections;
+
+ private final String COMMENT_SEMICOLON = ";";
+
+ private final String COMMENT_HASH = "#";
+
+ enum State
+ {
+ IN_SECTION, OFF_SECTION, GLOBAL
+ }
+
+ /*
+ * IniFileReader constructor
+ */
+
+ public IniFileReader()
+ {
+ _sections = new HashMap<String, Properties>();
+ }
+
+ /**
+ * Cleans up the after comments or the empty spaces/tabs surrounding the given string
+ *
+ * @param str The String to be cleaned
+ *
+ * @return String Cleanup Version
+ */
+ private String cleanUp(String str)
+ {
+ if (str.contains(COMMENT_SEMICOLON))
+ {
+ str = str.substring(0, str.indexOf(COMMENT_SEMICOLON));
+ }
+ if (str.contains(COMMENT_HASH))
+ {
+ str = str.substring(0, str.indexOf(COMMENT_HASH));
+ }
+ return str.trim();
+ }
+
+ /**
+ * Loads and parses the ini file with the full path specified in the argument
+ *
+ * @param fileName Full path to the ini file
+ *
+ * @throws IllegalArgumentException If the file cannot be processed
+ */
+ public void load(String fileName) throws IllegalArgumentException
+ {
+ if (!new File(fileName).isFile())
+ {
+ throw new IllegalArgumentException("File: " + fileName + " does not exist or cannot be read.");
+ }
+ State state = State.GLOBAL;
+ String line;
+ Properties sectionProps = new Properties();
+ String sectionName = "";
+ try
+ {
+ BufferedReader in = new BufferedReader(new FileReader(fileName));
+ while ((line = in.readLine()) != null)
+ {
+ String str = cleanUp(line);
+
+ // Did we get a section header?
+ if (str.startsWith("["))
+ {
+ if (!str.endsWith("]"))
+ {
+ // Index of 1 to skip '['
+ throw new IllegalArgumentException(str.substring(1)
+ + " is not closed");
+ }
+
+ // We encountered a new section header
+ if (state != State.IN_SECTION)
+ {
+ _sections.put(sectionName, sectionProps);
+ sectionProps = new Properties();
+ sectionName = str.replace("[", "").replace("]", "")
+ .trim();
+ state = State.IN_SECTION;
+ }
+ }
+
+ // Any other line tested separately, ignore if out of a section
+ // and add if in section
+ if (str.length() == 0)
+ {
+ // We encountered a commented or an empty line, both cases
+ // mean we are off the section
+ if (state == State.IN_SECTION)
+ {
+ _sections.put(sectionName, sectionProps);
+ state = State.OFF_SECTION;
+ }
+ }
+ else
+ {
+ // proper line, add it to the props
+ if (state != State.OFF_SECTION)
+ {
+ if (str.contains("="))
+ {
+ int ix = str.indexOf("=");
+ sectionProps.put(str.substring(0, ix).trim(), str
+ .substring(ix + 1).trim());
+ }
+ }
+ }
+ }
+ in.close();
+ }
+ catch (IOException e)
+ {
+ _sections.clear();
+ return;
+ }
+ if (state != State.OFF_SECTION)
+ {
+ _sections.put(sectionName, sectionProps);
+ }
+ }
+
+ /**
+ * Getter for the Sections Map
+ *
+ * @return Map<String,Properties> The parsed content of the ini file in this structure
+ */
+ public Map<String, Properties> getSections()
+ {
+ return _sections;
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/SoapClient.java b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/SoapClient.java
new file mode 100644
index 0000000000..0f66085fc3
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/SoapClient.java
@@ -0,0 +1,155 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+ */
+/**
+ *
+ * @author sorin
+ *
+ * An simple SOAP client for qpid info service
+ */
+package org.apache.qpid.info.util;
+
+import java.io.BufferedWriter;
+import java.io.OutputStreamWriter;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.Properties;
+
+public class SoapClient
+{
+
+ private final StringBuffer _xmlData;
+
+ private final Properties _destprops;
+
+ private final String _hostname;
+
+ private final int _port;
+
+ private final String _urlpath;
+
+ private final String _soapenvelope;
+
+ private final String _soapaction;
+
+ private final StringBuffer _soapMessage = new StringBuffer();
+
+
+ public SoapClient(HashMap<String, String> map, Properties destprops)
+ {
+ _destprops = destprops;
+ _hostname = (String) _destprops.get("soap.hostname");
+ _port = Integer.parseInt((String) _destprops.get("soap.port"));
+ _urlpath = (String) destprops.get("soap.path");
+ _soapenvelope = (String) destprops.get("soap.envelope");
+ _soapaction = (String) destprops.get("soap.action");
+ _xmlData = new StringBuffer(_soapenvelope);
+ replaceVariables(map);
+ }
+
+ public StringBuffer getXMLData()
+ {
+ return _xmlData;
+ }
+
+ public StringBuffer getSoapMessage() {
+ return _soapMessage;
+ }
+
+ public String getSoapEnvelope() {
+ return _soapenvelope;
+ }
+
+ /**
+ * Clears and sets new XML data
+ * @param sb the new data to set
+ */
+ public void setXMLData(StringBuffer sb)
+ {
+ _xmlData.delete(0, _xmlData.length());
+ _xmlData.append(sb);
+ }
+
+
+ public void replaceVariables(HashMap<String, String> vars)
+ {
+ int ix = 0;
+ for (String var : vars.keySet())
+ {
+ while ((ix = _xmlData.indexOf("@" + var.toUpperCase())) >= 0)
+ {
+ _xmlData.replace(ix, ix + 1 + var.length(), vars.get(var));
+ }
+ }
+ }
+
+ public void replaceVariables(Properties varProps)
+ {
+ if (varProps == null)
+ {
+ return;
+ }
+ int ix = 0;
+ for (Object var : varProps.keySet())
+ {
+ while ((ix = _xmlData.indexOf("@" + var)) >= 0)
+ {
+ _xmlData.replace(ix, ix + 1 + var.toString().length(), varProps
+ .get(var).toString());
+ }
+ }
+ }
+
+
+ public void sendSOAPMessage()
+ {
+
+ try
+ {
+ InetAddress addr = InetAddress.getByName(_hostname);
+ Socket sock = new Socket(addr, _port);
+ StringBuffer sb = new StringBuffer();
+ sb.append("POST " + _urlpath + " HTTP/1.1\r\n");
+ sb.append("Host: " + _hostname + ":" + _port + "\r\n");
+ sb.append("Content-Length: " + _xmlData.length() + "\r\n");
+ sb.append("Content-Type: text/xml; charset=\"utf-8\"\r\n");
+ sb.append("SOAPAction: \"urn:"+ _soapaction +"\"\r\n");
+ sb.append("User-Agent: Axis2\r\n");
+ sb.append("\r\n");
+ // Send header
+ BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(sock
+ .getOutputStream(), "UTF-8"));
+ synchronized(_soapMessage) {
+ _soapMessage.setLength(0);
+ _soapMessage.append(sb);
+ _soapMessage.append(_xmlData);
+ }
+ // Send data
+ wr.write(_soapMessage.toString());
+ wr.flush();
+ wr.close();
+
+ } catch (Exception ex)
+ {
+ // Drop any exception
+ }
+ }
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/XMLWriter.java b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/XMLWriter.java
new file mode 100644
index 0000000000..a266edae00
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/util/XMLWriter.java
@@ -0,0 +1,100 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info.util;
+
+import java.util.Map;
+
+/**
+ *
+ * Naive and rudimentary XML writer
+ * It has methods to write the header, a tag with attributes
+ * and values. It escapes the XML special characters
+ */
+public class XMLWriter
+{
+
+ private final StringBuffer _sb;
+
+ private final String INDENT = " ";
+
+ public XMLWriter(StringBuffer sb)
+ {
+ _sb = sb;
+ }
+
+ public StringBuffer getXML()
+ {
+ return _sb;
+ }
+
+ public void writeXMLHeader()
+ {
+ _sb.append("<?xml version=\"1.0\"?>\n");
+ }
+
+ public void writeTag(String tagName, Map<String, String> attributes,
+ String value)
+ {
+ writeOpenTag(tagName, attributes);
+ writeValue(value);
+ writeCloseTag(tagName);
+ }
+
+ public void writeOpenTag(String tagName, Map<String, String> attributes)
+ {
+ _sb.append("<").append(tagName);
+ if (null == attributes)
+ {
+ _sb.append(">\n");
+ return;
+ }
+ for (String key : attributes.keySet())
+ {
+ _sb.append(" ").append(key + "=\"" + attributes.get(key) + "\"");
+ }
+ _sb.append(">\n");
+
+ }
+
+ private void writeValue(String val)
+ {
+ _sb.append(INDENT).append(escapeXML(val) + "\n");
+ }
+
+ public void writeCloseTag(String tagName)
+ {
+ _sb.append("</" + tagName + ">\n");
+ }
+
+ private String escapeXML(String xmlStr)
+ {
+ if (null == xmlStr)
+ return null;
+ xmlStr = xmlStr.replaceAll("&", "&amp;");
+ xmlStr = xmlStr.replace("<", "&lt;");
+ xmlStr = xmlStr.replace(">", "&gt;");
+ xmlStr = xmlStr.replace("\"", "&quot;");
+ xmlStr = xmlStr.replace("'", "&apos;");
+ return xmlStr;
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/systest/InfoPluginTest.java b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/systest/InfoPluginTest.java
new file mode 100644
index 0000000000..156c9eb138
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/systest/InfoPluginTest.java
@@ -0,0 +1,276 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info.systest;
+
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class InfoPluginTest extends QpidBrokerTestCase
+{
+ private String QPID_HOME = null;
+
+ private ServerSocket _server = null;
+
+ private int _port;
+
+ private static final String CR = System.getProperty("line.separator");
+
+ private static final String FS = File.separator;
+
+ private final String _cfgRelPath = "etc" + FS + "qpidinfo.ini";
+
+ private File _tmpCfgFile;
+
+ private final String _soapEnvelopeHead = "<?xml version=\"1.0\"?><soap:Envelope xmlns:soap=\"http://www.w3.org/2001/12/soap-envelope\" soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">";
+
+ private final String _soapEnvelopeTail = "</soap:Envelope>";
+
+ private String _soapMessage1 = "@ACTION" + "-" + "@VERSION";
+
+ private String _soapMessage2 = "@VERSION" + "-" + "@ACTION";
+
+ private CountDownLatch _latch = new CountDownLatch(2);
+
+ final List<List<String>> _recv = new ArrayList<List<String>>();
+
+ Thread _socketAcceptor;
+
+ public void setUp() throws Exception
+ {
+ QPID_HOME = System.getProperty("QPID_HOME");
+ if (QPID_HOME != null)
+ {
+ System.out.println("QPID_HOME=" + QPID_HOME);
+ }
+ else
+ {
+ fail("QPID_HOME not set");
+ }
+
+ startSoapServer();
+ // Must start the server first to identify a free port.
+ createConfigFile();
+ }
+
+ public void tearDown() throws Exception
+ {
+ System.out.println("*** Stopping socket server...");
+ _socketAcceptor.join(2000);
+
+ System.out.println("*** Deleting the config file...");
+ if (_tmpCfgFile.isFile())
+ {
+ _tmpCfgFile.delete();
+ }
+ super.tearDown();
+ }
+
+ private void createConfigFile()
+ {
+ try
+ {
+ _tmpCfgFile = new File(QPID_HOME + FS + _cfgRelPath);
+ _tmpCfgFile.deleteOnExit();
+ if (_tmpCfgFile.isFile())
+ {
+ _tmpCfgFile.delete();
+ }
+ assertTrue("Unable to create file.", _tmpCfgFile.createNewFile());
+ assertTrue(_tmpCfgFile.isFile());
+ FileWriter fwriter = new FileWriter(_tmpCfgFile);
+ BufferedWriter writer = new BufferedWriter(fwriter);
+ writer.write("protocol=soap");
+ writer.write(CR);
+ writer.write("soap.hostname=localhost");
+ writer.write(CR);
+ writer.write("soap.port=" + _port);
+ writer.write(CR);
+ writer.write(CR);
+ writer.write("[MSG1]");
+ writer.write(CR);
+ writer.write("soap.path=/info1");
+ writer.write(CR);
+ writer.write("soap.action=submitinfo1");
+ writer.write(CR);
+ writer.write("soap.envelope=" + _soapEnvelopeHead + _soapMessage1
+ + _soapEnvelopeTail);
+ writer.write(CR);
+ writer.write(CR);
+ writer.write("[MSG2]");
+ writer.write(CR);
+ writer.write("soap.path=/info2");
+ writer.write(CR);
+ writer.write("soap.action=submitinfo2");
+ writer.write(CR);
+ writer.write("soap.envelope=" + _soapEnvelopeHead + _soapMessage2
+ + _soapEnvelopeTail);
+ writer.write(CR);
+ writer.write(CR);
+ writer.close();
+ assertTrue("Config file size is zero", _tmpCfgFile.length() > 0);
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create the qpidinfo.properties due to: "
+ + e.getMessage());
+ }
+ }
+
+ private void startSoapServer() throws Exception
+ {
+ try
+ {
+ _server = new ServerSocket(0);
+ _port = _server.getLocalPort();
+ assertTrue("Server not yet bound.", _port != -1);
+
+ assertNotNull("SocketServer is null", _server);
+ }
+ catch (Exception ex)
+ {
+ fail("Unable to start the socket server due to: " + ex.getMessage());
+ }
+
+ _socketAcceptor = new Thread()
+ {
+ public void run()
+ {
+ while (true)
+ {
+ try
+ {
+ Socket socket = _server.accept();
+ new ConnectionHandler(socket);
+ }
+ catch (IOException e)
+ {
+ fail("Error opening the socket in accept mode");
+ }
+ }
+ }
+ };
+ _socketAcceptor.start();
+ System.out.println("*** Socket server started...");
+ }
+
+ class ConnectionHandler implements Runnable
+ {
+ private Socket _socket;
+
+ public ConnectionHandler(Socket socket)
+ {
+ _socket = socket;
+ Thread t = new Thread(this);
+ t.start();
+ }
+
+ public void run()
+ {
+ System.out.println("*** Connection handler running...");
+ List<String> buf = new ArrayList<String>();
+ String line;
+ try
+ {
+ BufferedReader br = new BufferedReader(new InputStreamReader(
+ _socket.getInputStream()));
+ assertNotNull(br);
+ while ((line = br.readLine()) != null)
+ {
+ buf.add(line);
+ }
+ br.close();
+ System.out.println("*** Received buffer: " + buf);
+ System.out.println("*** Latch countdown");
+ _latch.countDown();
+ synchronized (_recv)
+ {
+ _recv.add(buf);
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ fail("Exception while reading from the socket");
+ }
+
+ }
+
+ }
+
+ public void testInfoPlugin() throws Exception
+ {
+ //Start the broker
+ super.setUp();
+ if (!_latch.await(10, TimeUnit.SECONDS))
+ {
+ fail("Timeout awaiting for the latch, upon startup");
+ }
+
+ validateResponses("STARTUP");
+
+ _recv.clear();
+ _latch = new CountDownLatch(2);
+
+ stopBroker();
+
+ if (!_latch.await(10, TimeUnit.SECONDS))
+ {
+ fail("Timeout awaiting for the latch, upon shutdown");
+ }
+
+ validateResponses("SHUTDOWN");
+
+ }
+
+ /**
+ * Check the responses from the server to ensure they contain the required messages.
+ * @param action String to match for the SHUTDOWN or STARTUP action.
+ */
+ private void validateResponses(String action)
+ {
+ assertTrue("Received less than 2 messages", _recv.size() > 1);
+
+ // Message 1
+ assertTrue("Message does not contain Host: localhost:" + _port + "\n" + _recv.get(0), _recv.get(0).contains("Host: localhost:" + _port));
+ assertTrue("Message does not contain: User-Agent: Axis2 " + "\n" + _recv.get(0), _recv.get(0).contains("User-Agent: Axis2"));
+ assertTrue("Message does not contain: SOAPAction: \"urn:submitinfo\"" + "\n" + _recv.get(0).get(4), _recv.get(0).get(4).startsWith("SOAPAction: \"urn:submitinfo"));
+ assertTrue("Message does not contain '" + action + "' in the soap envelope" + "\n" + _recv.get(0).get(7), _recv.get(0).get(7).contains(action));
+
+ // Message 2
+ assertTrue("Message does not contain Host: localhost:" + _port + "\n" + _recv.get(1), _recv.get(1).contains("Host: localhost:" + _port));
+ assertTrue("Message does not contain: User-Agent: Axis2 " + "\n" + _recv.get(1), _recv.get(1).contains("User-Agent: Axis2"));
+ assertTrue("Message does not contain: SOAPAction: \"urn:submitinfo\"" + "\n" + _recv.get(1).get(4), _recv.get(1).get(4).startsWith("SOAPAction: \"urn:submitinfo"));
+ assertTrue("Message does not contain '" + action + "' in the soap envelope" + "\n" + _recv.get(1).get(7), _recv.get(1).get(7).contains(action));
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/HttpPosterTest.java b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/HttpPosterTest.java
new file mode 100644
index 0000000000..4f76fea8ef
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/HttpPosterTest.java
@@ -0,0 +1,107 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info.test;
+
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.qpid.info.util.HttpPoster;
+import org.mortbay.jetty.testing.ServletTester;
+
+import junit.framework.TestCase;
+
+/*
+ * This test verifies that the plugin posts correctly to a webserver
+ * We use an embedded jetty container to mimic the webserver
+ */
+public class HttpPosterTest extends TestCase
+{
+
+ private ServletTester tester;
+
+ private String baseURL;
+
+ private final String contextPath = "/info";
+
+ /*
+ * This method generates a dummy HttpPoster with a dummy body containing a
+ * single line. The url we are posting to can be controlled by the parameter
+ * url
+ *
+ * @param url
+ */
+ private HttpPoster getHttpPoster(String url)
+ {
+ StringBuffer sb = new StringBuffer("test=TEST");
+ Properties props = new Properties();
+ props.put("http.url", url);
+ return new HttpPoster(props, sb);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception
+ {
+ tester = new ServletTester();
+ tester.setContextPath("/");
+ tester.addServlet(InfoServlet.class, contextPath);
+ baseURL = tester.createSocketConnector(true);
+ tester.start();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ tester.stop();
+ }
+
+ /*
+ * This test is posting a string to an embedded Jetty Servlet and captures
+ * the response message. If the servlet receives the message ok, it will
+ * print Ok. A failure test is following where we post to a non-existent URL
+ */
+ public void testHttpPoster() throws Exception
+ {
+ // Test HttpPoster posts correctly to the servlet
+ HttpPoster hp = getHttpPoster(baseURL + contextPath);
+ assertNotNull(hp);
+ hp.run();
+ List<String> response = hp.get_response();
+ assertTrue(response.size() > 0);
+ assertEquals("OK <br>", response.get(0).toString());
+
+ // Failure Test
+ hp = getHttpPoster("http://localhost/nonexistent");
+ hp.run();
+ response = hp.get_response();
+ assertTrue(response.size() == 0);
+
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/InfoServiceImplTest.java b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/InfoServiceImplTest.java
new file mode 100644
index 0000000000..9f359582a5
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/InfoServiceImplTest.java
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info.test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.qpid.info.Info;
+import org.apache.qpid.info.InfoServiceImpl;
+
+import junit.framework.TestCase;
+
+/*
+ * This test verifies the invoke() method for the info service making sure that the parameters are returned
+ */
+public class InfoServiceImplTest extends TestCase
+{
+
+ InfoServiceImpl _isi = null;
+
+ @SuppressWarnings("unchecked")
+ public void testInvoke()
+ {
+ _isi = new InfoServiceImpl();
+ assertNotNull(_isi);
+ Info<? extends Map<String, String>> info = (Info<? extends Map<String, String>>) _isi
+ .invoke("START");
+ assertNotNull(info);
+ Properties props = info.toProps();
+ assertNotNull(props);
+ List<String> infoProps = Arrays.asList("java.class.path",
+ "java.vm.name", "java.class.version", "os.arch", "os.name",
+ "os.version", "sun.arch.data.model", "user.dir", "user.name",
+ "user.timezone");
+ for (String tag : infoProps)
+ {
+ assertNotNull("Info.toProps() does not have the property: " + tag,
+ props.getProperty(tag));
+ }
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/InfoServlet.java b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/InfoServlet.java
new file mode 100644
index 0000000000..6b12a2d80c
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/InfoServlet.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info.test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.servlet.GenericServlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+/*
+ * This is a servlet used by the embedded Jetty to be able to receive http post
+ * from the info plugin
+ */
+
+public class InfoServlet extends GenericServlet
+{
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void service(ServletRequest request, ServletResponse response)
+ throws ServletException, IOException
+ {
+ String line;
+ BufferedReader in = request.getReader();
+ while ((line = in.readLine()) != null)
+ {
+ System.out.println(line);
+ }
+ response.setContentType("text/html");
+ PrintWriter out = response.getWriter();
+ out.println("OK <br>\n");
+ System.out.println("ServletResponse: OK");
+ }
+
+} \ No newline at end of file
diff --git a/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/InfoTest.java b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/InfoTest.java
new file mode 100644
index 0000000000..bb4965ef1e
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/InfoTest.java
@@ -0,0 +1,112 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info.test;
+
+import java.util.HashMap;
+import java.util.Properties;
+import junit.framework.TestCase;
+import org.apache.qpid.info.Info;
+
+/*
+ * This test verifies the toString(), toProps(), toXML() and toStringBuffer() methods of the Info object
+ *
+ */
+public class InfoTest extends TestCase
+{
+ private HashMap<String, String> _infoPayLoad = null;
+
+ private Info<HashMap<String, String>> _info = null;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _infoPayLoad = new HashMap<String, String>();
+ _infoPayLoad.put("test", "Test");
+ _info = new Info<HashMap<String, String>>(_infoPayLoad);
+ }
+
+ /*
+ * Test the conversion toString() of the Info object
+ */
+ public void testToString()
+ {
+ assertNotNull("toString() returned null", _info.toString());
+ assertEquals("toString() did not return the proper string",
+ "test=Test\n", _info.toString());
+ }
+
+ /*
+ * Test the conversion toProps() of the Info object
+ */
+ public void testToProps()
+ {
+ Properties props = new Properties();
+ props.put("test", "Test");
+ assertNotNull("toProperties() returned null", _info.toProps());
+ assertEquals("toProperties not returned the proper object", props, _info
+ .toProps());
+ }
+
+ /*
+ * Test the conversion toStringBuffer() of the Info object
+ */
+ public void testToStringBuffer()
+ {
+ StringBuffer sb = new StringBuffer("test=Test\n");
+ assertNotNull(_info.toStringBuffer());
+ assertEquals(sb.toString(), _info.toStringBuffer().toString());
+ }
+
+ /*
+ * Test conversion toXML() of the info object
+ */
+ public void testToXML()
+ {
+ String INDENT = " ";
+ StringBuffer sb = new StringBuffer();
+ sb.append("<?xml version=\"1.0\"?>\n");
+ sb.append("<qpidinfo>\n");
+ sb.append("<test>\n");
+ sb.append(INDENT + "Test\n");
+ sb.append("</test>\n");
+ sb.append("</qpidinfo>\n");
+ assertEquals("toString() does not return the proper string", _info
+ .toXML().toString(), sb.toString());
+ }
+
+ /*
+ * Test the conversion toMap() of the Info object
+ */
+ public void testToMap()
+ {
+ HashMap<String, String> thm = _info.toMap();
+ assertFalse("toMap() returned empty map", thm.isEmpty());
+ assertEquals("testToMap did not returned 1", 1, thm.size());
+ assertTrue("toMap() returned a map not containing expected key: test",
+ thm.containsKey("test"));
+ assertTrue(
+ "toMap() returned a map not containing the value for key test: Test",
+ thm.containsValue("Test"));
+
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/IniFileReaderTest.java b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/IniFileReaderTest.java
new file mode 100644
index 0000000000..77ecaa2176
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/IniFileReaderTest.java
@@ -0,0 +1,136 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info.test;
+
+import junit.framework.TestCase;
+import org.apache.qpid.info.util.IniFileReader;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Test the Loading of the ini file reader by first writing
+ * out a correct ini file.
+ */
+public class IniFileReaderTest extends TestCase
+{
+
+ public void testLoad()
+ {
+ IniFileReader ifr = new IniFileReader();
+ File iniFile = null;
+ try
+ {
+ iniFile = File.createTempFile("temp", "ini");
+ iniFile.deleteOnExit();
+ BufferedWriter writer = new BufferedWriter(new FileWriter(iniFile));
+ writer.write("# Global Comment1\n");
+ writer.write("globalprop1=globalval1\n");
+ writer.write("globalprop2=globalval2\n");
+ writer.write("\n");
+ writer.write("[Section1] # Comment on Section\n");
+ writer.write("key1=val1 # Comment on Value\n");
+ writer.write("key2=val2\n");
+ writer.write("\n");
+ writer.write("#Section2 Comment\n");
+ writer.write("[Section2]\n");
+ writer.write("key3=val3\n");
+ writer.write("key4=val4\n");
+ writer.write("key5=val5\n");
+ writer.write("\n");
+ writer.write("[Section3]\n");
+ writer.write("key6=val6\n");
+ writer.write("key7=val7\n");
+ writer.write("\n");
+ writer.close();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ fail("Unable to create temporary File");
+ }
+ ifr.load(iniFile.getAbsolutePath());
+ Map<String, Properties> sections = ifr.getSections();
+ assertNotNull("Sections not null", sections);
+ assertEquals("Have 4 sections", sections.keySet().size(), 4);
+ assertTrue("Get globalprop1", sections.get("").getProperty("globalprop1").equals("globalval1"));
+ assertTrue("Get globalprop2", sections.get("").getProperty("globalprop2").equals("globalval2"));
+ assertNotNull("Section1 not null", sections.get("Section1"));
+ assertEquals("Section1 has 2 properties", sections.get("Section1").size(), 2);
+ assertTrue("Section1 key1 has val1", sections.get("Section1").getProperty("key1").equals("val1"));
+ assertTrue("Section1 key2 has val2", sections.get("Section1").getProperty("key2").equals("val2"));
+ assertEquals("Section2 has 3 properties", sections.get("Section2").size(), 3);
+ assertTrue("Section2 key3 has val3", sections.get("Section2").getProperty("key3").equals("val3"));
+ assertTrue("Section2 key4 has val4", sections.get("Section2").getProperty("key4").equals("val4"));
+ assertTrue("Section2 key5 has val5", sections.get("Section2").getProperty("key5").equals("val5"));
+ assertEquals("Section3 has 2 properties", sections.get("Section3").size(), 2);
+ assertTrue("Section3 key6 has val6", sections.get("Section3").getProperty("key6").equals("val6"));
+ assertTrue("Section3 key7 has val7", sections.get("Section3").getProperty("key7").equals("val7"));
+ }
+
+ /**
+ * Test to ensure that the loading of a file with an unclosed section header
+ * fails to parse.
+ *
+ * Section needs to be fully enclosed in square brackets '[<name>]'
+ */
+ public void testIncompleteSection1Load()
+ {
+ IniFileReader ifr = new IniFileReader();
+ File iniFile = null;
+ try
+ {
+ iniFile = File.createTempFile(getName(), "ini");
+ iniFile.deleteOnExit();
+ BufferedWriter writer = new BufferedWriter(new FileWriter(iniFile));
+ writer.write("# Global Comment1\n");
+ writer.write("globalprop1=globalval1\n");
+ writer.write("globalprop2=globalval2\n");
+ writer.write("\n");
+ writer.write("[Section1\n"); // Note '[Section1' not complete
+ writer.write("key1=val1\n");
+ writer.write("key2=val2\n");
+ writer.write("\n");
+ writer.close();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ fail("Unable to create temporary File");
+ }
+ try
+ {
+ ifr.load(iniFile.getAbsolutePath());
+ fail("File should fail to parse");
+ }
+ catch (IllegalArgumentException iae)
+ {
+ assertEquals("Incorrect Exception", "Section1 is not closed", iae.getMessage());
+ }
+
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/SoapClientTest.java b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/SoapClientTest.java
new file mode 100644
index 0000000000..a3d993a39f
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/SoapClientTest.java
@@ -0,0 +1,208 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info.test;
+
+import junit.framework.TestCase;
+import org.apache.qpid.info.util.SoapClient;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Properties;
+
+public class SoapClientTest extends TestCase
+{
+
+ private int _port;
+
+ private final String _hostName = "localhost";
+
+ private final String _urlPath = "/testSoap";
+
+ private ServerSocket _server = null;
+
+ /*
+ * Generate a soap client from a custom URL, hostname, port and soap context
+ * path to be derived
+ */
+ private SoapClient getSoapClient()
+ {
+ Properties destprops = new Properties();
+ destprops.setProperty("soap.hostname", _hostName);
+ destprops.setProperty("soap.port", _port + "");
+ destprops.setProperty("soap.urlpath", _urlPath);
+ destprops.setProperty("soap.envelope", "<ip>@IP</ip>");
+ destprops.setProperty("soap.action", "send");
+ HashMap<String, String> soapmap = new HashMap<String, String>();
+ soapmap.put("IP", "127.0.0.1");
+ return new SoapClient(soapmap, destprops);
+ }
+
+ /*
+ * A connection handler class that verifies the correct message is received
+ *
+ */
+ class ConnectionHandler implements Runnable
+ {
+ private Socket socket;
+
+ public ConnectionHandler(Socket socket)
+ {
+ this.socket = socket;
+ Thread t = new Thread(this);
+ t.start();
+ }
+
+ public void run()
+ {
+ String line;
+ final List<String> response = new ArrayList<String>();
+ try
+ {
+ BufferedReader br = new BufferedReader(new InputStreamReader(
+ socket.getInputStream()));
+ assertNotNull(br);
+ while ((line = br.readLine()) != null)
+ {
+ response.add(line);
+ }
+ br.close();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ fail("Exception while reading from the socket");
+ }
+ assertTrue(response.contains("<ip>127.0.0.1</ip>"));
+ assertTrue(response.contains("SOAPAction: \"urn:send\""));
+ assertTrue(response
+ .contains("Content-Type: text/xml; charset=\"utf-8\""));
+ assertTrue(response.contains("Host: localhost" + _port));
+ assertTrue(response.contains("User-Agent: Axis2"));
+ }
+
+ }
+
+ /*
+ * Test that the SOAP client sends the expected data to the socket We mock a
+ * simple SOAP envelope: <ip>127.0.0.1</ip>
+ */
+ public void testSoapClient() throws Exception
+ {
+ //
+ try
+ {
+ _server = new ServerSocket(0);
+ _port = _server.getLocalPort();
+ assertTrue("Server is not yet bound to a port", _port != -1);
+ assertNotNull(_server);
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ fail("Unable to start the socket server");
+ }
+
+ Thread _socketAcceptor = new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ Socket socket = _server.accept();
+ new ConnectionHandler(socket);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ };
+ _socketAcceptor.start();
+ // Sleep for 1 second to allow the ServerSocket readiness
+ Thread.sleep(1000);
+ SoapClient sc = getSoapClient();
+ assertNotNull(sc);
+ sc.sendSOAPMessage();
+
+ _socketAcceptor.join(2000);
+
+ assertFalse("Socket Acceptor not stopped.", _socketAcceptor.isAlive());
+ }
+
+ /**
+ * Test SoapClient correctly clears previously set values
+ */
+ public void testSoapClientXMLData()
+ {
+ SoapClient sc = getSoapClient();
+
+ StringBuffer initial = new StringBuffer("Initial Value");
+
+ sc.setXMLData(initial);
+
+ assertEquals("getXMLData is not set with initial value",
+ initial.toString(), sc.getXMLData().toString());
+
+
+ StringBuffer sb = new StringBuffer("<?xml version=\"1.0\"?><ip=@IP><port=@PORT>");
+ sc.setXMLData(sb);
+ assertEquals(sc.getXMLData().length(), sb.length());
+ assertEquals("getXMLData does not return the same StringBuffer set by setXMLData",
+ sb.toString(), sc.getXMLData().toString());
+ }
+
+ /**
+ * Test that variable replacement is performed on the soap.envelope.
+ * Create dummy soap message and validate that the variable have been replaced.
+ */
+ public void testReplaceVariablesMap()
+ {
+ Properties props = new Properties();
+ // Add dummy values as required to create a soap message
+ props.setProperty("soap.hostname", _hostName);
+ props.setProperty("soap.port", "0");
+ props.setProperty("soap.urlpath", _urlPath);
+ props.setProperty("soap.action", "send");
+
+ /// The envelope is what we care about
+ props.setProperty("soap.envelope", "<addr>@IP:@PORT</addr>");
+ HashMap<String, String> soapmap = new HashMap<String, String>();
+
+ /// Variables that should be replaced.
+ final String ip = "127.0.0.1";
+ soapmap.put("IP", ip);
+ final String port = "8080";
+ soapmap.put("PORT", port);
+
+ SoapClient sc = new SoapClient(soapmap, props);
+ assertNotNull("SoapClient is null", sc);
+
+ assertTrue("Replace variables did not work as expected", ("<addr>" + ip + ":" + port + "</addr>").equals(sc.getXMLData().toString()));
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/SystemInfoTest.java b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/SystemInfoTest.java
new file mode 100644
index 0000000000..6cb8e3a90a
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/SystemInfoTest.java
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info.test;
+
+import junit.framework.TestCase;
+import org.apache.qpid.info.SystemInfo;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/** Test the SystemInfo component */
+public class SystemInfoTest extends TestCase
+{
+
+ /**
+ * Ensure the list of required properties are returned by the
+ * SystemInfo.getInfo call
+ */
+ public void testGetInfo()
+ {
+ Map<String, String> sysInfoMap = SystemInfo.getInfo();
+ assertNotNull("SystemInfo.getInfo() returned null", sysInfoMap);
+ List<String> sysInfoProps = Arrays.asList(
+ "java.class.path",
+ "java.vm.name", "java.class.version", "os.arch", "os.name",
+ "os.version", "sun.arch.data.model", "user.dir", "user.name",
+ "user.timezone", "hostname", "ip", "CPUCores", "Maximum_Memory",
+ "Free_Memory");
+
+ for (String tag : sysInfoProps)
+ {
+ assertNotNull("Map does not contain the tag: " + tag, sysInfoMap.get(tag));
+ }
+ }
+
+} \ No newline at end of file
diff --git a/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/XMLWriterTest.java b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/XMLWriterTest.java
new file mode 100644
index 0000000000..f352226361
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/test/XMLWriterTest.java
@@ -0,0 +1,132 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.info.test;
+
+import junit.framework.TestCase;
+import org.apache.qpid.info.util.XMLWriter;
+
+import java.util.HashMap;
+
+/*
+ * This test verifies the XML writer custom class operations
+ */
+
+public class XMLWriterTest extends TestCase
+{
+
+ private XMLWriter xw = null;
+
+ /** Test constructor arg is returned via getXML() */
+ public void testXMLWriter()
+ {
+ StringBuffer input = new StringBuffer("Test");
+ xw = new XMLWriter(input);
+ assertNotNull("XMLWriter could not instantiate", xw);
+ assertEquals("XMLWriter.getXML() failed", input, xw.getXML());
+ }
+
+ /** Test header generation */
+ public void testWriteXMLHeader()
+ {
+ xw = new XMLWriter(new StringBuffer());
+ assertNotNull(xw);
+ xw.writeXMLHeader();
+ assertEquals("XMLWriter.writeXMLHeader(...) failed", "<?xml version=\"1.0\"?>\n", xw.getXML().toString());
+ }
+
+ /** Test tag created and written correctly */
+ public void testWriteTag()
+ {
+ String INDENT = " ";
+ xw = new XMLWriter(new StringBuffer());
+ assertNotNull("XMLWriter could not instantiate", xw);
+ xw.writeTag("test", new HashMap<String, String>(), "TEST");
+ assertEquals("XMLWriter.writeTag(...) failed", "<test>\n" + INDENT + "TEST\n" + "</test>\n", xw.getXML()
+ .toString());
+ }
+
+ /** Test tag created and written correctly */
+ public void testWriteTagWithNullAttribute()
+ {
+ String INDENT = " ";
+ xw = new XMLWriter(new StringBuffer());
+ assertNotNull("XMLWriter could not instantiate", xw);
+ xw.writeTag("test", null, "TEST");
+ assertEquals("XMLWriter.writeTag(...) failed", "<test>\n" + INDENT + "TEST\n" + "</test>\n", xw.getXML()
+ .toString());
+ }
+
+ /** Test tag created and written correctly with attribute */
+ public void testWriteTagWithAttribute()
+ {
+ String INDENT = " ";
+ xw = new XMLWriter(new StringBuffer());
+ assertNotNull("XMLWriter could not instantiate", xw);
+ HashMap<String, String> attr = new HashMap<String, String>();
+ attr.put("id", "1");
+
+ xw.writeTag("test", attr, "TEST");
+ assertEquals("XMLWriter.writeTag(...) failed", "<test id=\"1\">\n" + INDENT + "TEST\n" + "</test>\n", xw.getXML()
+ .toString());
+ }
+
+ /** Test open tag with an empty attribute map. Just creates an open tag */
+ public void testWriteOpenTag()
+ {
+ xw = new XMLWriter(new StringBuffer());
+ assertNotNull(xw);
+ HashMap<String, String> attr = new HashMap<String, String>();
+ xw.writeOpenTag("test", attr);
+ assertEquals("XMLWriter.writeOpenTag(...) failed", "<test>\n", xw.getXML().toString());
+ }
+
+ /** Test open tag with a null attribute map. Just creates an open tag */
+ public void testNullAtrributeOnTag()
+ {
+ xw = new XMLWriter(new StringBuffer());
+ assertNotNull(xw);
+ xw.writeOpenTag("test", null);
+ assertEquals("XMLWriter.writeOpenTag(...) failed", "<test>\n", xw.getXML().toString());
+ }
+
+ /** Test that setting an attribute value on the tag is correctly outputted. */
+ public void testAtrributeOnTag()
+ {
+ xw = new XMLWriter(new StringBuffer());
+ assertNotNull(xw);
+ HashMap<String, String> attr = new HashMap<String, String>();
+
+ attr.put("id", "1");
+ xw.writeOpenTag("test1", attr);
+ assertEquals("XMLWriter.writeOpenTag(...) failed", "<test1 id=\"1\">\n", xw.getXML().toString());
+ }
+
+ /** Test Close Tag is correctly written */
+ public void testWriteCloseTag()
+ {
+ xw = new XMLWriter(new StringBuffer());
+ assertNotNull(xw);
+ xw.writeCloseTag("test");
+ assertEquals("</test>\n", xw.getXML().toString());
+ }
+
+}
diff --git a/qpid/java/broker-plugins/experimental/shutdown/MANIFEST.MF b/qpid/java/broker-plugins/experimental/shutdown/MANIFEST.MF
new file mode 100644
index 0000000000..49e90c6aad
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/shutdown/MANIFEST.MF
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Experimental Shutdown
+Bundle-Description: Experimental Qpid Broker Shutdown Plugin
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-DocURL: http://qpid.apache.org/
+Bundle-SymbolicName: broker-plugins-experimental-shutdown;singleton:=true
+Bundle-Version: 1.0.0
+Bundle-Activator: org.apache.qpid.shutdown.Activator
+Import-Package: javax.management;resolution:=optional,
+ org.apache.log4j,
+ org.osgi.framework
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-ActivationPolicy: lazy
+
diff --git a/qpid/java/broker-plugins/experimental/shutdown/build.xml b/qpid/java/broker-plugins/experimental/shutdown/build.xml
new file mode 100644
index 0000000000..ec4fce374e
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/shutdown/build.xml
@@ -0,0 +1,32 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements. See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership. The ASF licenses this file
+ - to you 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.
+ -
+ -->
+<project name="AMQ Broker Shutdown Plugin" default="build">
+
+ <property name="module.depends" value="common broker broker-plugins"/>
+ <property name="module.test.depends" value="test broker/test management/common client systests"/>
+ <property name="module.manifest" value="MANIFEST.MF"/>
+ <property name="module.plugin" value="true"/>
+
+ <import file="../../../module.xml"/>
+
+ <target name="bundle" depends="bundle-tasks"/>
+
+</project>
diff --git a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Activator.java b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Activator.java
new file mode 100644
index 0000000000..ad5e7707b6
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Activator.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.shutdown;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.log4j.Logger;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator
+{
+ private static final Logger _logger = Logger.getLogger(Activator.class);
+
+ private static final String SHUTDOWN_MBEAN_NAME = "org.apache.qpid:type=ShutdownMBean";
+
+ /** @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */
+ public void start(BundleContext ctx) throws Exception {
+ Shutdown shutdown = new Shutdown();
+ if (ctx != null)
+ {
+ ctx.registerService(ShutdownMBean.class.getName(), shutdown, null);
+ }
+
+ // MBean registration
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ ObjectName name = new ObjectName(SHUTDOWN_MBEAN_NAME);
+ mbs.registerMBean(shutdown, name);
+
+ _logger.info("Shutdown plugin MBean registered");
+ }
+
+ /** @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */
+ public void stop(BundleContext ctx) throws Exception
+ {
+ // Unregister MBean
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ ObjectName name = new ObjectName(SHUTDOWN_MBEAN_NAME);
+ try
+ {
+ mbs.unregisterMBean(name);
+ }
+ catch (InstanceNotFoundException e)
+ {
+ //ignore
+ }
+
+ _logger.info("Shutdown plugin MBean unregistered");
+ }
+}
diff --git a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Shutdown.java b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Shutdown.java
new file mode 100644
index 0000000000..9a6f85fe9c
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Shutdown.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.shutdown;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Implementation of the JMX broker shutdown plugin.
+ */
+public class Shutdown implements ShutdownMBean
+{
+ private static final Logger _logger = Logger.getLogger(Shutdown.class);
+
+ private static final String FORMAT = "yyyyy/MM/dd hh:mm:ss";
+ private static final int THREAD_COUNT = 1;
+ private static final ScheduledExecutorService EXECUTOR = new ScheduledThreadPoolExecutor(THREAD_COUNT);
+
+ private final Runnable _shutdown = new SystemExiter();
+
+ /** @see ShutdownMBean#shutdown() */
+ public void shutdown()
+ {
+ _logger.info("Shutting down at user's request");
+ shutdownBroker(0);
+ }
+
+ /** @see ShutdownMBean#shutdown(long) */
+ public void shutdown(long delay)
+ {
+ _logger.info("Scheduled broker shutdown after " + delay + "ms");
+ shutdownBroker(delay);
+ }
+
+ /** @see ShutdownMBean#shutdownAt(String) */
+ public void shutdownAt(String when)
+ {
+ Date date;
+ DateFormat df = new SimpleDateFormat(FORMAT);
+ try
+ {
+ date = df.parse(when);
+ }
+ catch (ParseException e)
+ {
+ _logger.error("Invalid date \"" + when + "\": expecting " + FORMAT, e);
+ return;
+ }
+ _logger.info("Scheduled broker shutdown at " + when);
+ long now = System.currentTimeMillis();
+ long time = date.getTime();
+ if (time > now)
+ {
+ shutdownBroker(time - now);
+ }
+ else
+ {
+ shutdownBroker(0);
+ }
+ }
+
+ /**
+ * Submits the {@link SystemExiter} job to shutdown the broker.
+ */
+ private void shutdownBroker(long delay)
+ {
+ EXECUTOR.schedule(_shutdown, delay, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Shutting down the system in another thread to avoid JMX exceptions being thrown.
+ */
+ class SystemExiter implements Runnable
+ {
+ public void run()
+ {
+ System.exit(0);
+ }
+ }
+}
diff --git a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/ShutdownMBean.java b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/ShutdownMBean.java
new file mode 100644
index 0000000000..6294f869e9
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/ShutdownMBean.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.qpid.shutdown;
+
+/**
+ * Shutdown plugin JMX MBean interface.
+ *
+ * Shuts the Qpid broker down via JMX.
+ */
+public interface ShutdownMBean
+{
+ /**
+ * Broker will be shut down immediately.
+ */
+ public void shutdown();
+
+ /**
+ * Broker will be shutdown after the specified delay
+ *
+ * @param delay the number of ms to wait
+ */
+ public void shutdown(long delay);
+
+ /**
+ * Broker will be shutdown at the specified date and time.
+ *
+ * @param when the date and time to shutdown
+ */
+ public void shutdownAt(String when);
+}
diff --git a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd
new file mode 100755
index 0000000000..f49578ba8c
--- /dev/null
+++ b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd
@@ -0,0 +1,25 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+ver: 0.11.0
+
+Bundle-SymbolicName: qpid-shutdown-plugin
+Bundle-Version: ${ver}
+Export-Package: *;version=${ver}
+Bundle-RequiredExecutionEnvironment: J2SE-1.5