Return-Path: Delivered-To: apmail-activemq-commits-archive@www.apache.org Received: (qmail 63992 invoked from network); 23 Oct 2009 14:16:05 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 23 Oct 2009 14:16:05 -0000 Received: (qmail 23783 invoked by uid 500); 23 Oct 2009 14:15:27 -0000 Delivered-To: apmail-activemq-commits-archive@activemq.apache.org Received: (qmail 23752 invoked by uid 500); 23 Oct 2009 14:15:26 -0000 Mailing-List: contact commits-help@activemq.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@activemq.apache.org Delivered-To: mailing list commits@activemq.apache.org Received: (qmail 23699 invoked by uid 99); 23 Oct 2009 14:15:26 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 23 Oct 2009 14:15:26 +0000 X-ASF-Spam-Status: No, hits=-2.6 required=5.0 tests=BAYES_00 X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 23 Oct 2009 14:15:21 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id ED6E5238888E; Fri, 23 Oct 2009 14:15:00 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r829073 - /activemq/trunk/activemq-console/src/main/java/org/apache/activemq/console/command/CreateCommand.java Date: Fri, 23 Oct 2009 14:15:00 -0000 To: commits@activemq.apache.org From: dejanb@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20091023141500.ED6E5238888E@eris.apache.org> Author: dejanb Date: Fri Oct 23 14:15:00 2009 New Revision: 829073 URL: http://svn.apache.org/viewvc?rev=829073&view=rev Log: https://issues.apache.org/activemq/browse/AMQ-2462 - new activemq-admin commands - create command Added: activemq/trunk/activemq-console/src/main/java/org/apache/activemq/console/command/CreateCommand.java Added: activemq/trunk/activemq-console/src/main/java/org/apache/activemq/console/command/CreateCommand.java URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-console/src/main/java/org/apache/activemq/console/command/CreateCommand.java?rev=829073&view=auto ============================================================================== --- activemq/trunk/activemq-console/src/main/java/org/apache/activemq/console/command/CreateCommand.java (added) +++ activemq/trunk/activemq-console/src/main/java/org/apache/activemq/console/command/CreateCommand.java Fri Oct 23 14:15:00 2009 @@ -0,0 +1,292 @@ +/* + * 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.console.command; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.List; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +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 org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +public class CreateCommand extends AbstractCommand { + + protected final String[] helpFile = new String[] { + "Task Usage: Main create path/to/brokerA [create-options]", + "Description: Creates a runnable broker instance in the specified path.", + "", + "List Options:", + " --amqconf Path to ActiveMQ conf file that will be used in the broker instance. Default is: conf/activemq.xml", + " --version Display the version information.", + " -h,-?,--help Display the create broker help information.", + "" + }; + + protected final String DEFAULT_TARGET_ACTIVEMQ_CONF = "conf/activemq.xml"; // default activemq conf to create in the new broker instance + protected final String DEFAULT_BROKERNAME_XPATH = "/beans/broker/@brokerName"; // default broker name xpath to change the broker name + + protected final String[] BASE_SUB_DIRS = { "bin", "conf" }; // default sub directories that will be created + protected final String BROKER_NAME_REGEX = "[$][{]brokerName[}]"; // use to replace broker name property holders + + protected String amqConf = "conf/activemq.xml"; // default conf if no conf is specified via --amqconf + + // default files to copy from activemq home to the new broker instance + protected String[][] fileCopyMap = { + { "conf/log4j.properties", "conf/log4j.properties" }, + { "conf/broker.ks", "conf/broker.ks" }, + { "conf/broker.ts", "conf/broker.ts" }, + { "conf/camel.xml", "conf/camel.xml" }, + { "conf/jetty.xml", "conf/jetty.xml" }, + { "conf/credentials.properties", "conf/credentials.properties" } + }; + + // default files to create + protected String[][] fileWriteMap = { + { "winActivemq", "bin/${brokerName}.bat" }, + { "unixActivemq", "bin/${brokerName}" } + }; + + + protected String brokerName; + protected File amqHome; + protected File targetAmqBase; + + protected void runTask(List tokens) throws Exception { + context.print("Running create broker task..."); + amqHome = new File(System.getProperty("activemq.home")); + for (String token : tokens) { + + targetAmqBase = new File(token); + brokerName = targetAmqBase.getName(); + + + if (targetAmqBase.exists()) { + BufferedReader console = new BufferedReader(new InputStreamReader(System.in)); + String resp; + while (true) { + context.print("Target directory (" + targetAmqBase.getCanonicalPath() + ") already exists. Overwrite (y/n): "); + resp = console.readLine(); + if (resp.equalsIgnoreCase("y") || resp.equalsIgnoreCase("yes")) { + break; + } else if (resp.equalsIgnoreCase("n") || resp.equalsIgnoreCase("no")) { + return; + } + } + } + + context.print("Creating directory: " + targetAmqBase.getCanonicalPath()); + targetAmqBase.mkdirs(); + createSubDirs(targetAmqBase, BASE_SUB_DIRS); + writeFileMapping(targetAmqBase, fileWriteMap); + copyActivemqConf(amqHome, targetAmqBase, amqConf); + copyFileMapping(amqHome, targetAmqBase, fileCopyMap); + } + } + + /** + * Handle the --amqconf options. + * + * @param token - option token to handle + * @param tokens - succeeding command arguments + * @throws Exception + */ + protected void handleOption(String token, List tokens) throws Exception { + if (token.startsWith("--amqconf")) { + // If no amqconf specified, or next token is a new option + if (tokens.isEmpty() || tokens.get(0).startsWith("-")) { + context.printException(new IllegalArgumentException("Attributes to amqconf not specified")); + return; + } + + amqConf = tokens.remove(0); + } else { + // Let super class handle unknown option + super.handleOption(token, tokens); + } + } + + protected void createSubDirs(File target, String[] subDirs) throws IOException { + File subDirFile; + for (String subDir : BASE_SUB_DIRS) { + subDirFile = new File(target, subDir); + context.print("Creating directory: " + subDirFile.getCanonicalPath()); + subDirFile.mkdirs(); + } + } + + protected void writeFileMapping(File targetBase, String[][] fileWriteMapping) throws IOException { + for (String[] fileWrite : fileWriteMapping) { + File dest = new File(targetBase, resolveParam(BROKER_NAME_REGEX, brokerName, fileWrite[1])); + context.print("Creating new file: " + dest.getCanonicalPath()); + writeFile(fileWrite[0], dest); + } + } + + protected void copyFileMapping(File srcBase, File targetBase, String[][] fileMapping) throws IOException { + for (String[] fileMap : fileMapping) { + File src = new File(srcBase, fileMap[0]); + File dest = new File(targetBase, resolveParam(BROKER_NAME_REGEX, brokerName, fileMap[1])); + context.print("Copying from: " + src.getCanonicalPath() + "\n to: " + dest.getCanonicalPath()); + copyFile(src, dest); + } + } + + protected void copyActivemqConf(File srcBase, File targetBase, String activemqConf) throws IOException, ParserConfigurationException, SAXException, TransformerException, XPathExpressionException { + File src = new File(srcBase, activemqConf); + + if (!src.exists()) { + throw new FileNotFoundException("File: " + src.getCanonicalPath() + " not found."); + } + + File dest = new File(targetBase, DEFAULT_TARGET_ACTIVEMQ_CONF); + context.print("Copying from: " + src.getCanonicalPath() + "\n to: " + dest.getCanonicalPath()); + + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Element docElem = builder.parse(src).getDocumentElement(); + + XPath xpath = XPathFactory.newInstance().newXPath(); + Attr brokerNameAttr = (Attr) xpath.evaluate(DEFAULT_BROKERNAME_XPATH, docElem, XPathConstants.NODE); + brokerNameAttr.setValue(brokerName); + + writeToFile(new DOMSource(docElem), dest); + } + + protected void printHelp() { + context.printHelp(helpFile); + } + + // write the default files to create (i.e. script files) + private void writeFile(String typeName, File dest) throws IOException { + String data; + if (typeName.equals("winActivemq")) { + data = winActivemqData; + data = resolveParam("[$][{]activemq.home[}]", amqHome.getCanonicalPath().replaceAll("[\\\\]", "/"), data); + data = resolveParam("[$][{]activemq.base[}]", targetAmqBase.getCanonicalPath().replaceAll("[\\\\]", "/"), data); + } else if (typeName.equals("unixActivemq")) { + data = unixActivemqData; + data = resolveParam("[$][{]activemq.home[}]", amqHome.getCanonicalPath().replaceAll("[\\\\]", "/"), data); + data = resolveParam("[$][{]activemq.base[}]", targetAmqBase.getCanonicalPath().replaceAll("[\\\\]", "/"), data); + } else { + throw new IllegalStateException("Unknown file type: " + typeName); + } + + ByteBuffer buf = ByteBuffer.allocate(data.length()); + buf.put(data.getBytes()); + buf.flip(); + + FileChannel destinationChannel = new FileOutputStream(dest).getChannel(); + destinationChannel.write(buf); + destinationChannel.close(); + + // Set file permissions available for Java 6.0 only +// dest.setExecutable(true); +// dest.setReadable(true); +// dest.setWritable(true); + } + + // utlity method to write an xml source to file + private void writeToFile(Source src, File file) throws TransformerException { + TransformerFactory tFactory = TransformerFactory.newInstance(); + Transformer fileTransformer = tFactory.newTransformer(); + + Result res = new StreamResult(file); + fileTransformer.transform(src, res); + } + + // utility method to copy one file to another + private void copyFile(File from, File dest) throws IOException { + if (!from.exists()) { + return; + } + FileChannel sourceChannel = new FileInputStream(from).getChannel(); + FileChannel destinationChannel = new FileOutputStream(dest).getChannel(); + sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel); + sourceChannel.close(); + destinationChannel.close(); + } + + // replace a property place holder (paramName) with the paramValue + private String resolveParam(String paramName, String paramValue, String target) { + return target.replaceAll(paramName, paramValue); + } + + // Embedded windows script data + private static final String winActivemqData = + "@echo off\n" + + "set ACTIVEMQ_HOME=\"${activemq.home}\"\n" + + "set ACTIVEMQ_BASE=\"${activemq.base}\"\n" + + "\n" + + "set PARAM=%1\n" + + ":getParam\n" + + "shift\n" + + "if \"%1\"==\"\" goto end\n" + + "set PARAM=%PARAM% %1\n" + + "goto getParam\n" + + ":end\n" + + "\n" + + "%ACTIVEMQ_HOME%/bin/activemq %PARAM%"; + + + // Embedded unix script data + private static final String unixActivemqData = "## Figure out the ACTIVEMQ_BASE from the directory this script was run from\n" + + "PRG=\"$0\"\n" + + "progname=`basename \"$0\"`\n" + + "saveddir=`pwd`\n" + + "# need this for relative symlinks\n" + + "dirname_prg=`dirname \"$PRG\"`\n" + + "cd \"$dirname_prg\"\n" + + "while [ -h \"$PRG\" ] ; do\n" + + " ls=`ls -ld \"$PRG\"`\n" + + " link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n" + + " if expr \"$link\" : '.*/.*' > /dev/null; then\n" + + " PRG=\"$link\"\n" + + " else\n" + + " PRG=`dirname \"$PRG\"`\"/$link\"\n" + + " fi\n" + + "done\n" + + "ACTIVEMQ_BASE=`dirname \"$PRG\"`/..\n" + + "cd \"$saveddir\"\n" + + "\n" + + "ACTIVEMQ_BASE=`cd \"$ACTIVEMQ_BASE\" && pwd`\n\n" + + "export ACTIVEMQ_HOME=${activemq.home}\n" + + "export ACTIVEMQ_BASE=$ACTIVEMQ_BASE\n\n" + + "${ACTIVEMQ_HOME}/bin/activemq \"$*\""; + +}