ARTEMIS-790 Added Configuration Migration Tool

This commit is contained in:
Martyn Taylor 2016-12-09 17:49:30 +00:00
parent 887b8c8532
commit 0bcde8140f
5 changed files with 307 additions and 136 deletions

View File

@ -0,0 +1,84 @@
/*
* 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.activemq.artemis.tools.migrate.config;
import java.io.File;
public class Main {
public static void main(String[] args) throws Exception {
if (args.length == 0) {
System.err.println("Invalid args");
printUsage();
} else {
File input = new File(args[0]);
if (input.isDirectory()) {
System.out.println("Scanning directory: " + input.getAbsolutePath());
recursiveTransform(input);
} else {
if (args.length != 2) {
System.err.println("Invalid args");
printUsage();
} else {
try {
XMLConfigurationMigration migration = new XMLConfigurationMigration(input, new File(args[1]));
} catch (Exception e) {
// Unable to process file, move on.
}
}
}
}
}
private static void recursiveTransform(File root) throws Exception {
for (File file : root.listFiles()) {
scanAndTransform(file);
}
}
public static void scanAndTransform(File pFile) throws Exception {
try {
for (File f : pFile.listFiles()) {
if (f.isDirectory()) {
scanAndTransform(f);
} else {
try {
if (f.getName().endsWith("xml")) {
File file = new File(f.getAbsolutePath() + ".new");
XMLConfigurationMigration migration = new XMLConfigurationMigration(f, file);
if (migration.transform()) {
File r = new File(f.getAbsolutePath());
f.renameTo(new File(f.getAbsolutePath() + ".bk"));
file.renameTo(r);
}
}
} catch (Exception e) {
//Unable to process file, continue
}
}
}
} catch (NullPointerException e) {
System.out.println(pFile.getAbsoluteFile());
}
}
public static void printUsage() {
System.out.println("Please specify a directory to scan, or input and output file");
}
}

View File

@ -26,8 +26,10 @@ import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@ -41,83 +43,96 @@ import org.w3c.dom.NodeList;
public class XMLConfigurationMigration {
private static XMLConfigurationMigration migration;
// Attributes
private static final String xPathAttrName = "@name";
// JMS XPaths
private static final String xPathJMS = "/configuration/jms";
private static final String xPathJMSQueues = "/configuration/jms/queue";
private static final String xPathJMSTopics = "/configuration/jms/topic";
// Core Queue XPaths
private static final String xPathQueues = "/configuration/core/queues";
private static final String xPathQueue = "/configuration/core/queues/queue";
private static final String xPathAddress = "address";
private static final String xPathFilter = "filter/@string";
private static final String xPathSelector = "selector/@string";
private static final String xPathDurable = "durable";
private static final String jmsQueuePrefix = "jms.queue.";
private static final String jmsTopicPrefix = "jms.topic.";
private final Map<String, Address> jmsQueueAddresses = new HashMap<>();
private final Map<String, Address> jmsTopicAddresses = new HashMap<>();
private final Map<String, Address> coreAddresses = new HashMap<>();
private final Map<String, Address> aliases = new HashMap<>();
private final Document document;
public static void main(String[] args) throws Exception {
private final File input;
if (args.length == 0) {
System.err.println("Invalid args");
printUsage();
} else {
File input = new File(args[0]);
if (input.isDirectory()) {
System.out.println("Scanning directory: " + input.getAbsolutePath());
recursiveTransform(input);
} else {
if (args.length != 2) {
System.err.println("Invalid args");
printUsage();
} else {
transform(input, new File(args[1]));
}
}
}
}
private final File output;
private static void recursiveTransform(File root) throws Exception {
for (File file : root.listFiles()) {
scanAndTransform(file);
}
}
private final Node coreElement;
public static void scanAndTransform(File pFile) throws Exception {
try {
for (File f : pFile.listFiles()) {
if (f.isDirectory()) {
scanAndTransform(f);
} else {
try {
if (f.getName().endsWith("xml")) {
File file = new File(f.getAbsolutePath() + ".new");
if (transform(f, file)) {
File r = new File(f.getAbsolutePath());
private final XPath xPath;
f.renameTo(new File(f.getAbsolutePath() + ".bk"));
file.renameTo(r);
}
}
} catch (Exception e) {
//continue
}
}
}
} catch (NullPointerException e) {
System.out.println(pFile.getAbsoluteFile());
}
}
public XMLConfigurationMigration(File input, File output) throws Exception {
public static void printUsage() {
System.out.println("Please specify a directory to scan, or input and output file");
}
this.input = input;
this.output = output;
public static boolean transform(File input, File output) throws Exception {
migration = new XMLConfigurationMigration(input);
try {
if (!input.exists()) {
System.err.println("Input file not found: " + input);
throw new Exception("Input file not found: " + input);
}
if (migration.convertQueuesToAddresses()) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder db = factory.newDocumentBuilder();
this.document = db.parse(this.input);
xPath = XPathFactory.newInstance().newXPath();
coreElement = (Node) xPath.evaluate("/configuration/core", document, XPathConstants.NODE);
if (coreElement == null) {
throw new Exception("Not a artemis config");
}
} catch (Exception e) {
throw new Exception(e);
}
}
public boolean transform() throws Exception {
try {
boolean queuesChanged = convertQueuesToAddresses();
boolean jmsChanged = convertJMSToAddresses();
writeAddressesToDocument();
document.normalize();
if (queuesChanged || jmsChanged) {
Properties properties = new Properties();
properties.put(OutputKeys.INDENT, "yes");
properties.put("{http://xml.apache.org/xslt}indent-amount", "3");
properties.put(OutputKeys.ENCODING, "UTF-8");
migration.write(output, properties);
write(output, properties);
return true;
}
} catch (Exception e) {
System.err.println("Error tranforming document");
e.printStackTrace();
@ -125,103 +140,165 @@ public class XMLConfigurationMigration {
return false;
}
public XMLConfigurationMigration(File input) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder db = factory.newDocumentBuilder();
this.document = db.parse(input);
}
public boolean convertQueuesToAddresses() throws Exception {
Map<String, Address> addresses = new HashMap<>();
String xPathQueues = "/configuration/core/queues";
String xPathQueue = "/configuration/core/queues/queue";
String xPathAttrName = "@name";
String xPathAddress = "address";
String xPathFilter = "filter/@string";
String xPathDurable = "durable";
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList xpathResult = (NodeList) xPath.evaluate(xPathQueue, document, XPathConstants.NODESET);
if (xpathResult == null || xpathResult.getLength() == 0) {
// doesn't require change
Node coreQueuesElement = getNode(xPathQueues);
if (coreQueuesElement == null) {
return false;
}
for (int i = 0; i < xpathResult.getLength(); i++) {
Node queueNode = xpathResult.item(i);
NodeList coreQueueElements = getNodeList(xPathQueue);
for (int i = 0; i < coreQueueElements.getLength(); i++) {
Node queueNode = coreQueueElements.item(i);
Queue queue = new Queue();
queue.setName(xPath.evaluate(xPathAttrName, queueNode, XPathConstants.STRING).toString());
queue.setDurable(xPath.evaluate(xPathDurable, queueNode, XPathConstants.STRING).toString());
queue.setFilter(xPath.evaluate(xPathFilter, queueNode, XPathConstants.STRING).toString());
queue.setName(getString(queueNode, xPathAttrName));
queue.setDurable(getString(queueNode, xPathDurable));
queue.setFilter(getString(queueNode, xPathFilter));
String addressName = getString(queueNode, xPathAddress);
String addressName = xPath.evaluate(xPathAddress, queueNode, XPathConstants.STRING).toString();
Address address;
if (addresses.containsKey(addressName)) {
address = addresses.get(addressName);
if (coreAddresses.containsKey(addressName)) {
address = coreAddresses.get(addressName);
} else {
address = new Address();
address.setName(addressName);
addresses.put(addressName, address);
coreAddresses.put(addressName, address);
}
address.getQueues().add(queue);
}
Node queues = ((Node) xPath.evaluate(xPathQueues, document, XPathConstants.NODE));
// Remove Core Queues Element from Core
Node queues = getNode(xPathQueues);
if (queues != null) {
Node core = queues.getParentNode();
core.removeChild(queues);
Element a = document.createElement("addresses");
for (Address addr : addresses.values()) {
Element eAddr = document.createElement("address");
eAddr.setAttribute("name", addr.getName());
eAddr.setAttribute("type", addr.getRoutingType());
if (addr.getQueues().size() > 0) {
Element eQueues = document.createElement("queues");
for (Queue queue : addr.getQueues()) {
Element eQueue = document.createElement("queue");
eQueue.setAttribute("name", queue.getName());
eQueue.setAttribute("max-consumers", addr.getDefaultMaxConsumers());
eQueue.setAttribute("delete-on-no-consumers", addr.getDefaultDeleteOnNoConsumers());
if (queue.getDurable() != null && !queue.getDurable().isEmpty()) {
Element eDurable = document.createElement("durable");
eDurable.setTextContent(queue.getDurable());
eQueue.appendChild(eDurable);
}
if (queue.getFilter() != null && !queue.getFilter().isEmpty()) {
Element eFilter = document.createElement("filter");
eFilter.setAttribute("string", queue.getFilter());
eQueue.appendChild(eFilter);
}
eQueues.appendChild(eQueue);
}
eAddr.appendChild(eQueues);
}
a.appendChild(eAddr);
}
core.appendChild(a);
coreElement.removeChild(queues);
}
document.normalize();
return true;
}
public boolean convertJMSToAddresses() throws Exception {
Node jmsElement = getNode(xPathJMS);
if (jmsElement == null) {
return false;
}
NodeList jmsQueueElements = getNodeList(xPathJMSQueues);
for (int i = 0; i < jmsQueueElements.getLength(); i++) {
Node jmsQueueElement = jmsQueueElements.item(i);
String name = jmsQueuePrefix + getString(jmsQueueElement, xPathAttrName);
Address address;
if (jmsQueueAddresses.containsKey(name)) {
address = jmsQueueAddresses.get(name);
} else {
address = new Address();
address.setName(name);
address.setRoutingType("anycast");
jmsQueueAddresses.put(name, address);
}
Queue queue = new Queue();
queue.setName(name);
queue.setDurable(getString(jmsQueueElement, xPathDurable));
queue.setFilter(getString(jmsQueueElement, xPathSelector));
address.getQueues().add(queue);
}
NodeList jmsTopicElements = getNodeList(xPathJMSTopics);
for (int i = 0; i < jmsTopicElements.getLength(); i++) {
Node jmsTopicElement = jmsTopicElements.item(i);
String name = jmsTopicPrefix + getString(jmsTopicElement, xPathAttrName);
Address address;
if (jmsTopicAddresses.containsKey(name)) {
address = jmsTopicAddresses.get(name);
} else {
address = new Address();
address.setName(name);
address.setRoutingType("multicast");
jmsTopicAddresses.put(name, address);
}
Queue queue = new Queue();
queue.setName(name);
address.getQueues().add(queue);
}
jmsElement.getParentNode().removeChild(jmsElement);
return true;
}
public void writeAddressesToDocument() {
Element addressElement = document.createElement("addresses");
writeAddressListToDoc("= JMS Queues =", jmsQueueAddresses.values(), addressElement);
writeAddressListToDoc("= JMS Topics =", jmsTopicAddresses.values(), addressElement);
writeAddressListToDoc("= Core Queues =", coreAddresses.values(), addressElement);
coreElement.appendChild(addressElement);
}
private void writeAddressListToDoc(String comment, Collection<Address> addresses, Node addressElement) {
if (addresses.isEmpty())
return;
addressElement.appendChild(document.createComment("=================="));
addressElement.appendChild(document.createComment(comment));
addressElement.appendChild(document.createComment("=================="));
for (Address addr : addresses) {
Element eAddr = document.createElement("address");
eAddr.setAttribute("name", addr.getName());
eAddr.setAttribute("type", addr.getRoutingType());
if (addr.getQueues().size() > 0) {
Element eQueues = document.createElement("queues");
for (Queue queue : addr.getQueues()) {
Element eQueue = document.createElement("queue");
eQueue.setAttribute("name", queue.getName());
eQueue.setAttribute("max-consumers", addr.getDefaultMaxConsumers());
eQueue.setAttribute("delete-on-no-consumers", addr.getDefaultDeleteOnNoConsumers());
if (queue.getDurable() != null && !queue.getDurable().isEmpty()) {
Element eDurable = document.createElement("durable");
eDurable.setTextContent(queue.getDurable());
eQueue.appendChild(eDurable);
}
if (queue.getFilter() != null && !queue.getFilter().isEmpty()) {
Element eFilter = document.createElement("filter");
eFilter.setAttribute("string", queue.getFilter());
eQueue.appendChild(eFilter);
}
eQueues.appendChild(eQueue);
}
eAddr.appendChild(eQueues);
}
addressElement.appendChild(eAddr);
}
}
public void write(File output, Properties outputProperties) throws TransformerException {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperties(outputProperties);
StreamResult streamResult = new StreamResult(output);
transformer.transform(new DOMSource(document), streamResult);
}
private String getString(Node node, String xPathQuery) throws XPathExpressionException {
return xPath.evaluate(xPathQuery, node, XPathConstants.STRING).toString();
}
private NodeList getNodeList(String xPathQuery) throws XPathExpressionException {
return (NodeList) xPath.evaluate(xPathQuery, document, XPathConstants.NODESET);
}
private Node getNode(String xPathQuery) throws XPathExpressionException {
return (Node) xPath.evaluate(xPathQuery, document, XPathConstants.NODE);
}
}

View File

@ -1,2 +1,2 @@
Manifest-Version: 1.0
Main-Class: org.apache.activemq.artemis.tools.migrate.config.XMLConfigurationMigration
Main-Class: org.apache.activemq.artemis.tools.migrate.config.Main

View File

@ -27,10 +27,11 @@ public class XMLConfigurationMigrationTest {
@Test
public void testQueuesReplacedWithAddresses() throws Exception {
File brokerXml = new File(this.getClass().getClassLoader().getResource("broker.xml").toURI());
XMLConfigurationMigration tool = new XMLConfigurationMigration(brokerXml);
File output = new File("target/out.xml");
tool.convertQueuesToAddresses();
XMLConfigurationMigration tool = new XMLConfigurationMigration(brokerXml, output);
tool.transform();
Properties properties = new Properties();
properties.put(OutputKeys.INDENT, "yes");
@ -42,6 +43,6 @@ public class XMLConfigurationMigrationTest {
@Test
public void scanAndReplaceTest() throws Exception {
File dir = new File(this.getClass().getClassLoader().getResource("replace").getPath());
XMLConfigurationMigration.scanAndTransform(dir);
Main.scanAndTransform(dir);
}
}

View File

@ -18,8 +18,17 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:activemq /schema/artemis-server.xsd">
<jms xmlns="urn:activemq:jms">
<!--the queue used by the example-->
<queue name="exampleQueue"/>
<queue name="queue1">
<durable>true</durable>
<selector string="car='red'" />
</queue>
<queue name="queue2"/>
<queue name="queue3"/>
<topic name="topic1"/>
<topic name="topic2"/>
<topic name="topic3"/>
</jms>
<core xmlns="urn:activemq:core">