mirror of https://github.com/apache/activemq.git
https://issues.apache.org/activemq/browse/AMQ-2462 - new activemq-admin commands
git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@829066 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
5074fefc09
commit
e0ee61348e
|
@ -80,6 +80,22 @@
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>velocity</groupId>
|
||||||
|
<artifactId>velocity</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-collections</groupId>
|
||||||
|
<artifactId>commons-collections</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sf.josql</groupId>
|
||||||
|
<artifactId>josql</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sf.josql</groupId>
|
||||||
|
<artifactId>gentlyweb-utils</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.activemq.console.CommandContext;
|
import org.apache.activemq.console.CommandContext;
|
||||||
|
import org.apache.activemq.console.command.store.amq.AMQJournalToolCommand;
|
||||||
import org.apache.activemq.console.formatter.CommandShellOutputFormatter;
|
import org.apache.activemq.console.formatter.CommandShellOutputFormatter;
|
||||||
|
|
||||||
public class ShellCommand extends AbstractCommand {
|
public class ShellCommand extends AbstractCommand {
|
||||||
|
@ -41,10 +42,12 @@ public class ShellCommand extends AbstractCommand {
|
||||||
"",
|
"",
|
||||||
"Tasks (default task is start):",
|
"Tasks (default task is start):",
|
||||||
" start - Creates and starts a broker using a configuration file, or a broker URI.",
|
" start - Creates and starts a broker using a configuration file, or a broker URI.",
|
||||||
|
" create - Creates a runnable broker instance in the specified path",
|
||||||
" stop - Stops a running broker specified by the broker name.",
|
" stop - Stops a running broker specified by the broker name.",
|
||||||
" list - Lists all available brokers in the specified JMX context.",
|
" list - Lists all available brokers in the specified JMX context.",
|
||||||
" query - Display selected broker component's attributes and statistics.",
|
" query - Display selected broker component's attributes and statistics.",
|
||||||
" browse - Display selected messages in a specified destination.",
|
" browse - Display selected messages in a specified destination.",
|
||||||
|
" journal-audit - Allows you to view records stored in the persistent journal.",
|
||||||
"",
|
"",
|
||||||
"Task Options (Options specific to each task):",
|
"Task Options (Options specific to each task):",
|
||||||
" --extdir <dir> - Add the jar files in the directory to the classpath.",
|
" --extdir <dir> - Add the jar files in the directory to the classpath.",
|
||||||
|
@ -106,6 +109,8 @@ public class ShellCommand extends AbstractCommand {
|
||||||
String taskToken = (String)tokens.remove(0);
|
String taskToken = (String)tokens.remove(0);
|
||||||
if (taskToken.equals("start")) {
|
if (taskToken.equals("start")) {
|
||||||
command = new StartCommand();
|
command = new StartCommand();
|
||||||
|
} else if (taskToken.equals("create")) {
|
||||||
|
command = new CreateCommand();
|
||||||
} else if (taskToken.equals("stop")) {
|
} else if (taskToken.equals("stop")) {
|
||||||
command = new ShutdownCommand();
|
command = new ShutdownCommand();
|
||||||
} else if (taskToken.equals("list")) {
|
} else if (taskToken.equals("list")) {
|
||||||
|
@ -118,6 +123,8 @@ public class ShellCommand extends AbstractCommand {
|
||||||
command = new AmqBrowseCommand();
|
command = new AmqBrowseCommand();
|
||||||
} else if (taskToken.equals("purge")) {
|
} else if (taskToken.equals("purge")) {
|
||||||
command = new PurgeCommand();
|
command = new PurgeCommand();
|
||||||
|
} else if (taskToken.equals("journal-audit")) {
|
||||||
|
command = new AMQJournalToolCommand();
|
||||||
} else if (taskToken.equals("help")) {
|
} else if (taskToken.equals("help")) {
|
||||||
printHelp();
|
printHelp();
|
||||||
} else {
|
} else {
|
||||||
|
@ -134,7 +141,7 @@ public class ShellCommand extends AbstractCommand {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print the help messages for the browse command
|
* Print the help messages for the browse command
|
||||||
*/
|
*/
|
||||||
protected void printHelp() {
|
protected void printHelp() {
|
||||||
|
|
|
@ -0,0 +1,353 @@
|
||||||
|
/**
|
||||||
|
* 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.store.amq;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
import org.apache.activemq.command.ActiveMQBlobMessage;
|
||||||
|
import org.apache.activemq.command.ActiveMQBytesMessage;
|
||||||
|
import org.apache.activemq.command.ActiveMQMapMessage;
|
||||||
|
import org.apache.activemq.command.ActiveMQMessage;
|
||||||
|
import org.apache.activemq.command.ActiveMQObjectMessage;
|
||||||
|
import org.apache.activemq.command.ActiveMQStreamMessage;
|
||||||
|
import org.apache.activemq.command.ActiveMQTextMessage;
|
||||||
|
import org.apache.activemq.command.DataStructure;
|
||||||
|
import org.apache.activemq.command.JournalQueueAck;
|
||||||
|
import org.apache.activemq.command.JournalTopicAck;
|
||||||
|
import org.apache.activemq.command.JournalTrace;
|
||||||
|
import org.apache.activemq.command.JournalTransaction;
|
||||||
|
import org.apache.activemq.kaha.impl.async.Location;
|
||||||
|
import org.apache.activemq.kaha.impl.async.ReadOnlyAsyncDataManager;
|
||||||
|
import org.apache.activemq.openwire.OpenWireFormat;
|
||||||
|
import org.apache.activemq.util.ByteSequence;
|
||||||
|
import org.apache.activemq.wireformat.WireFormat;
|
||||||
|
import org.apache.velocity.Template;
|
||||||
|
import org.apache.velocity.VelocityContext;
|
||||||
|
import org.apache.velocity.app.Velocity;
|
||||||
|
import org.apache.velocity.app.VelocityEngine;
|
||||||
|
import org.josql.Query;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows you to view the contents of a Journal.
|
||||||
|
*
|
||||||
|
* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
|
||||||
|
*/
|
||||||
|
public class AMQJournalTool {
|
||||||
|
|
||||||
|
private final ArrayList<File> dirs = new ArrayList<File>();
|
||||||
|
private final WireFormat wireFormat = new OpenWireFormat();
|
||||||
|
private final HashMap<String, String> resources = new HashMap<String, String>();
|
||||||
|
|
||||||
|
private String messageFormat = "${location.dataFileId},${location.offset}|${type}|${record.destination}|${record.messageId}|${record.properties}|${body}";
|
||||||
|
private String topicAckFormat = "${location.dataFileId},${location.offset}|${type}|${record.destination}|${record.clientId}|${record.subscritionName}|${record.messageId}";
|
||||||
|
private String queueAckFormat = "${location.dataFileId},${location.offset}|${type}|${record.destination}|${record.messageAck.lastMessageId}";
|
||||||
|
private String transactionFormat = "${location.dataFileId},${location.offset}|${type}|${record.transactionId}";
|
||||||
|
private String traceFormat = "${location.dataFileId},${location.offset}|${type}|${record.message}";
|
||||||
|
private String unknownFormat = "${location.dataFileId},${location.offset}|${type}|${record.class.name}";
|
||||||
|
private String where;
|
||||||
|
private VelocityContext context;
|
||||||
|
private VelocityEngine velocity;
|
||||||
|
private boolean help;
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
AMQJournalTool consumerTool = new AMQJournalTool();
|
||||||
|
String[] directories = CommandLineSupport
|
||||||
|
.setOptions(consumerTool, args);
|
||||||
|
if (directories.length < 1) {
|
||||||
|
System.out
|
||||||
|
.println("Please specify the directories with journal data to scan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < directories.length; i++) {
|
||||||
|
consumerTool.getDirs().add(new File(directories[i]));
|
||||||
|
}
|
||||||
|
consumerTool.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute() throws Exception {
|
||||||
|
|
||||||
|
if( help ) {
|
||||||
|
showHelp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getDirs().size() < 1) {
|
||||||
|
System.out.println("");
|
||||||
|
System.out.println("Invalid Usage: Please specify the directories with journal data to scan");
|
||||||
|
System.out.println("");
|
||||||
|
showHelp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (File dir : getDirs()) {
|
||||||
|
if( !dir.exists() ) {
|
||||||
|
System.out.println("");
|
||||||
|
System.out.println("Invalid Usage: the directory '"+dir.getPath()+"' does not exist");
|
||||||
|
System.out.println("");
|
||||||
|
showHelp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( !dir.isDirectory() ) {
|
||||||
|
System.out.println("");
|
||||||
|
System.out.println("Invalid Usage: the argument '"+dir.getPath()+"' is not a directory");
|
||||||
|
System.out.println("");
|
||||||
|
showHelp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
context = new VelocityContext();
|
||||||
|
List keys = Arrays.asList(context.getKeys());
|
||||||
|
|
||||||
|
for (Iterator iterator = System.getProperties().entrySet()
|
||||||
|
.iterator(); iterator.hasNext();) {
|
||||||
|
Map.Entry kv = (Map.Entry) iterator.next();
|
||||||
|
String name = (String) kv.getKey();
|
||||||
|
String value = (String) kv.getValue();
|
||||||
|
|
||||||
|
if (!keys.contains(name)) {
|
||||||
|
context.put(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
velocity = new VelocityEngine();
|
||||||
|
velocity.setProperty(Velocity.RESOURCE_LOADER, "all");
|
||||||
|
velocity.setProperty("all.resource.loader.class", CustomResourceLoader.class.getName());
|
||||||
|
velocity.init();
|
||||||
|
|
||||||
|
|
||||||
|
resources.put("message", messageFormat);
|
||||||
|
resources.put("topicAck", topicAckFormat);
|
||||||
|
resources.put("queueAck", queueAckFormat);
|
||||||
|
resources.put("transaction", transactionFormat);
|
||||||
|
resources.put("trace", traceFormat);
|
||||||
|
resources.put("unknown", unknownFormat);
|
||||||
|
|
||||||
|
Query query = null;
|
||||||
|
if (where != null) {
|
||||||
|
query = new Query();
|
||||||
|
query.parse("select * from "+Entry.class.getName()+" where "+where);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlyAsyncDataManager manager = new ReadOnlyAsyncDataManager(getDirs());
|
||||||
|
manager.start();
|
||||||
|
try {
|
||||||
|
Location curr = manager.getFirstLocation();
|
||||||
|
while (curr != null) {
|
||||||
|
|
||||||
|
ByteSequence data = manager.read(curr);
|
||||||
|
DataStructure c = (DataStructure) wireFormat.unmarshal(data);
|
||||||
|
|
||||||
|
Entry entry = new Entry();
|
||||||
|
entry.setLocation(curr);
|
||||||
|
entry.setRecord(c);
|
||||||
|
entry.setData(data);
|
||||||
|
entry.setQuery(query);
|
||||||
|
process(entry);
|
||||||
|
|
||||||
|
curr = manager.getNextLocation(curr);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
manager.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showHelp() {
|
||||||
|
InputStream is = AMQJournalTool.class.getResourceAsStream("help.txt");
|
||||||
|
Scanner scanner = new Scanner(is);
|
||||||
|
while (scanner.hasNextLine()) {
|
||||||
|
String line = scanner.nextLine();
|
||||||
|
System.out.println(line);
|
||||||
|
}
|
||||||
|
scanner.close(); }
|
||||||
|
|
||||||
|
private void process(Entry entry) throws Exception {
|
||||||
|
|
||||||
|
Location location = entry.getLocation();
|
||||||
|
DataStructure record = entry.getRecord();
|
||||||
|
|
||||||
|
switch (record.getDataStructureType()) {
|
||||||
|
case ActiveMQMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
entry.setType("ActiveMQMessage");
|
||||||
|
entry.setFormater("message");
|
||||||
|
display(entry);
|
||||||
|
break;
|
||||||
|
case ActiveMQBytesMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
entry.setType("ActiveMQBytesMessage");
|
||||||
|
entry.setFormater("message");
|
||||||
|
display(entry);
|
||||||
|
break;
|
||||||
|
case ActiveMQBlobMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
entry.setType("ActiveMQBlobMessage");
|
||||||
|
entry.setFormater("message");
|
||||||
|
display(entry);
|
||||||
|
break;
|
||||||
|
case ActiveMQMapMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
entry.setType("ActiveMQMapMessage");
|
||||||
|
entry.setFormater("message");
|
||||||
|
display(entry);
|
||||||
|
break;
|
||||||
|
case ActiveMQObjectMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
entry.setType("ActiveMQObjectMessage");
|
||||||
|
entry.setFormater("message");
|
||||||
|
display(entry);
|
||||||
|
break;
|
||||||
|
case ActiveMQStreamMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
entry.setType("ActiveMQStreamMessage");
|
||||||
|
entry.setFormater("message");
|
||||||
|
display(entry);
|
||||||
|
break;
|
||||||
|
case ActiveMQTextMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
entry.setType("ActiveMQTextMessage");
|
||||||
|
entry.setFormater("message");
|
||||||
|
display(entry);
|
||||||
|
break;
|
||||||
|
case JournalQueueAck.DATA_STRUCTURE_TYPE:
|
||||||
|
entry.setType("Queue Ack");
|
||||||
|
entry.setFormater("queueAck");
|
||||||
|
display(entry);
|
||||||
|
break;
|
||||||
|
case JournalTopicAck.DATA_STRUCTURE_TYPE:
|
||||||
|
entry.setType("Topic Ack");
|
||||||
|
entry.setFormater("topicAck");
|
||||||
|
display(entry);
|
||||||
|
break;
|
||||||
|
case JournalTransaction.DATA_STRUCTURE_TYPE:
|
||||||
|
entry.setType(getType((JournalTransaction) record));
|
||||||
|
entry.setFormater("transaction");
|
||||||
|
display(entry);
|
||||||
|
break;
|
||||||
|
case JournalTrace.DATA_STRUCTURE_TYPE:
|
||||||
|
entry.setType("Trace");
|
||||||
|
entry.setFormater("trace");
|
||||||
|
display(entry);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
entry.setType("Unknown");
|
||||||
|
entry.setFormater("unknown");
|
||||||
|
display(entry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getType(JournalTransaction record) {
|
||||||
|
switch (record.getType()) {
|
||||||
|
case JournalTransaction.XA_PREPARE:
|
||||||
|
return "XA Prepare";
|
||||||
|
case JournalTransaction.XA_COMMIT:
|
||||||
|
return "XA Commit";
|
||||||
|
case JournalTransaction.XA_ROLLBACK:
|
||||||
|
return "XA Rollback";
|
||||||
|
case JournalTransaction.LOCAL_COMMIT:
|
||||||
|
return "Commit";
|
||||||
|
case JournalTransaction.LOCAL_ROLLBACK:
|
||||||
|
return "Rollback";
|
||||||
|
}
|
||||||
|
return "Unknown Transaction";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void display(Entry entry) throws Exception {
|
||||||
|
|
||||||
|
if (entry.getQuery() != null) {
|
||||||
|
List list = Collections.singletonList(entry);
|
||||||
|
List results = entry.getQuery().execute(list).getResults();
|
||||||
|
if (results.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomResourceLoader.setResources(resources);
|
||||||
|
try {
|
||||||
|
|
||||||
|
context.put("location", entry.getLocation());
|
||||||
|
context.put("record", entry.getRecord());
|
||||||
|
context.put("type", entry.getType());
|
||||||
|
if (entry.getRecord() instanceof ActiveMQMessage) {
|
||||||
|
context.put("body", new MessageBodyFormatter(
|
||||||
|
(ActiveMQMessage) entry.getRecord()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Template template = velocity.getTemplate(entry.getFormater());
|
||||||
|
PrintWriter writer = new PrintWriter(System.out);
|
||||||
|
template.merge(context, writer);
|
||||||
|
writer.println();
|
||||||
|
writer.flush();
|
||||||
|
} finally {
|
||||||
|
CustomResourceLoader.setResources(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessageFormat(String messageFormat) {
|
||||||
|
this.messageFormat = messageFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopicAckFormat(String ackFormat) {
|
||||||
|
this.topicAckFormat = ackFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransactionFormat(String transactionFormat) {
|
||||||
|
this.transactionFormat = transactionFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTraceFormat(String traceFormat) {
|
||||||
|
this.traceFormat = traceFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnknownFormat(String unknownFormat) {
|
||||||
|
this.unknownFormat = unknownFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQueueAckFormat(String queueAckFormat) {
|
||||||
|
this.queueAckFormat = queueAckFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQuery() {
|
||||||
|
return where;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWhere(String query) {
|
||||||
|
this.where = query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHelp() {
|
||||||
|
return help;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHelp(boolean help) {
|
||||||
|
this.help = help;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the dirs
|
||||||
|
*/
|
||||||
|
public ArrayList<File> getDirs() {
|
||||||
|
return dirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* 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.store.amq;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.activemq.console.CommandContext;
|
||||||
|
import org.apache.activemq.console.command.Command;
|
||||||
|
|
||||||
|
public class AMQJournalToolCommand implements Command {
|
||||||
|
|
||||||
|
private CommandContext context;
|
||||||
|
|
||||||
|
public void execute(List<String> tokens) throws Exception {
|
||||||
|
AMQJournalTool consumerTool = new AMQJournalTool();
|
||||||
|
String args[] = new String[tokens.size()];
|
||||||
|
tokens.toArray(args);
|
||||||
|
String[] directories = CommandLineSupport.setOptions(consumerTool, args);
|
||||||
|
for (int i = 0; i < directories.length; i++) {
|
||||||
|
consumerTool.getDirs().add(new File(directories[i]));
|
||||||
|
}
|
||||||
|
consumerTool.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCommandContext(CommandContext context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
/**
|
||||||
|
* 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.store.amq;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.apache.activemq.util.IntrospectionSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper utility that can be used to set the properties on any object using
|
||||||
|
* command line arguments.
|
||||||
|
*
|
||||||
|
* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
|
||||||
|
*/
|
||||||
|
public final class CommandLineSupport {
|
||||||
|
|
||||||
|
private CommandLineSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the properties of an object given the command line args.
|
||||||
|
*
|
||||||
|
* if args contains: --ack-mode=AUTO --url=tcp://localhost:61616 --persistent
|
||||||
|
*
|
||||||
|
* then it will try to call the following setters on the target object.
|
||||||
|
*
|
||||||
|
* target.setAckMode("AUTO");
|
||||||
|
* target.setURL(new URI("tcp://localhost:61616") );
|
||||||
|
* target.setPersistent(true);
|
||||||
|
*
|
||||||
|
* Notice the the proper conversion for the argument is determined by examining the
|
||||||
|
* setter arguement type.
|
||||||
|
*
|
||||||
|
* @param target the object that will have it's properties set
|
||||||
|
* @param args the commline options
|
||||||
|
* @return any arguments that are not valid options for the target
|
||||||
|
*/
|
||||||
|
public static String[] setOptions(Object target, String[] args) {
|
||||||
|
ArrayList<String> rc = new ArrayList<String>();
|
||||||
|
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
if (args[i] == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[i].startsWith("--")) {
|
||||||
|
|
||||||
|
// --options without a specified value are considered boolean
|
||||||
|
// flags that are enabled.
|
||||||
|
String value = "true";
|
||||||
|
String name = args[i].substring(2);
|
||||||
|
|
||||||
|
// if --option=value case
|
||||||
|
int p = name.indexOf("=");
|
||||||
|
if (p > 0) {
|
||||||
|
value = name.substring(p + 1);
|
||||||
|
name = name.substring(0, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// name not set, then it's an unrecognized option
|
||||||
|
if (name.length() == 0) {
|
||||||
|
rc.add(args[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String propName = convertOptionToPropertyName(name);
|
||||||
|
if (!IntrospectionSupport.setProperty(target, propName, value)) {
|
||||||
|
rc.add(args[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rc.add(args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
String r[] = new String[rc.size()];
|
||||||
|
rc.toArray(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* converts strings like: test-enabled to testEnabled
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static String convertOptionToPropertyName(String name) {
|
||||||
|
String rc = "";
|
||||||
|
|
||||||
|
// Look for '-' and strip and then convert the subsequent char to
|
||||||
|
// uppercase
|
||||||
|
int p = name.indexOf("-");
|
||||||
|
while (p > 0) {
|
||||||
|
// strip
|
||||||
|
rc += name.substring(0, p);
|
||||||
|
name = name.substring(p + 1);
|
||||||
|
|
||||||
|
// can I convert the next char to upper?
|
||||||
|
if (name.length() > 0) {
|
||||||
|
rc += name.substring(0, 1).toUpperCase();
|
||||||
|
name = name.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = name.indexOf("-");
|
||||||
|
}
|
||||||
|
return rc + name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
/**
|
||||||
|
* 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.store.amq;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.apache.commons.collections.ExtendedProperties;
|
||||||
|
import org.apache.velocity.exception.ResourceNotFoundException;
|
||||||
|
import org.apache.velocity.runtime.RuntimeServices;
|
||||||
|
import org.apache.velocity.runtime.resource.Resource;
|
||||||
|
import org.apache.velocity.runtime.resource.loader.FileResourceLoader;
|
||||||
|
import org.apache.velocity.runtime.resource.loader.ResourceLoader;
|
||||||
|
|
||||||
|
public class CustomResourceLoader extends ResourceLoader {
|
||||||
|
|
||||||
|
private final static ThreadLocal<HashMap<String, String>> resourcesTL = new ThreadLocal<HashMap<String, String>>();
|
||||||
|
private final FileResourceLoader fileResourceLoader = new FileResourceLoader();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commonInit(RuntimeServices rs, ExtendedProperties configuration) {
|
||||||
|
super.commonInit(rs, configuration);
|
||||||
|
fileResourceLoader.commonInit(rs, configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init( ExtendedProperties configuration)
|
||||||
|
{
|
||||||
|
fileResourceLoader.init(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public synchronized InputStream getResourceStream( String name )
|
||||||
|
throws ResourceNotFoundException
|
||||||
|
{
|
||||||
|
InputStream result = null;
|
||||||
|
|
||||||
|
if (name == null || name.length() == 0)
|
||||||
|
{
|
||||||
|
throw new ResourceNotFoundException ("No template name provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = null;
|
||||||
|
HashMap<String, String> resources = resourcesTL.get();
|
||||||
|
if( resources!=null ) {
|
||||||
|
value = resources.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( value == null ) {
|
||||||
|
result = this.fileResourceLoader.getResourceStream(name);
|
||||||
|
} else {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = new ByteArrayInputStream(value.getBytes());
|
||||||
|
}
|
||||||
|
catch( Exception e )
|
||||||
|
{
|
||||||
|
throw new ResourceNotFoundException( e.getMessage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSourceModified(Resource resource)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastModified(Resource resource)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public HashMap<String, String> getResources() {
|
||||||
|
return resourcesTL.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void setResources(HashMap<String, String> arg0) {
|
||||||
|
resourcesTL.set(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/**
|
||||||
|
* 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.store.amq;
|
||||||
|
|
||||||
|
import org.apache.activemq.command.DataStructure;
|
||||||
|
import org.apache.activemq.kaha.impl.async.Location;
|
||||||
|
import org.apache.activemq.util.ByteSequence;
|
||||||
|
import org.josql.Query;
|
||||||
|
|
||||||
|
public class Entry {
|
||||||
|
|
||||||
|
Location location;
|
||||||
|
DataStructure record;
|
||||||
|
private ByteSequence data;
|
||||||
|
private String type;
|
||||||
|
private String formater;
|
||||||
|
private Query query;
|
||||||
|
|
||||||
|
public Location getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
public void setLocation(Location location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
public DataStructure getRecord() {
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
public void setRecord(DataStructure record) {
|
||||||
|
this.record = record;
|
||||||
|
}
|
||||||
|
public void setData(ByteSequence data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
public ByteSequence getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
public void setFormater(String formater) {
|
||||||
|
this.formater = formater;
|
||||||
|
}
|
||||||
|
public String getFormater() {
|
||||||
|
return formater;
|
||||||
|
}
|
||||||
|
public void setQuery(Query query) {
|
||||||
|
this.query = query;
|
||||||
|
}
|
||||||
|
public Query getQuery() {
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* 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.store.amq;
|
||||||
|
|
||||||
|
import javax.jms.JMSException;
|
||||||
|
|
||||||
|
import org.apache.activemq.command.ActiveMQBlobMessage;
|
||||||
|
import org.apache.activemq.command.ActiveMQBytesMessage;
|
||||||
|
import org.apache.activemq.command.ActiveMQMapMessage;
|
||||||
|
import org.apache.activemq.command.ActiveMQMessage;
|
||||||
|
import org.apache.activemq.command.ActiveMQObjectMessage;
|
||||||
|
import org.apache.activemq.command.ActiveMQStreamMessage;
|
||||||
|
import org.apache.activemq.command.ActiveMQTextMessage;
|
||||||
|
import org.apache.activemq.util.ByteSequence;
|
||||||
|
|
||||||
|
public class MessageBodyFormatter {
|
||||||
|
final ActiveMQMessage message;
|
||||||
|
|
||||||
|
public MessageBodyFormatter(ActiveMQMessage message) {
|
||||||
|
this.message=message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
try {
|
||||||
|
switch (message.getDataStructureType()) {
|
||||||
|
case ActiveMQMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
return "";
|
||||||
|
case ActiveMQBlobMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
ActiveMQBlobMessage blob = (ActiveMQBlobMessage) message;
|
||||||
|
return blob.getRemoteBlobUrl();
|
||||||
|
case ActiveMQMapMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
ActiveMQMapMessage map = (ActiveMQMapMessage)message;
|
||||||
|
return map.getContentMap().toString();
|
||||||
|
case ActiveMQTextMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
ActiveMQTextMessage text = (ActiveMQTextMessage)message;
|
||||||
|
return text.getText();
|
||||||
|
case ActiveMQBytesMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
case ActiveMQObjectMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
case ActiveMQStreamMessage.DATA_STRUCTURE_TYPE:
|
||||||
|
ByteSequence data = message.getContent();
|
||||||
|
return "binary payload {length="+data.getLength()+", compressed="+message.isCompressed()+"}";
|
||||||
|
}
|
||||||
|
} catch (JMSException e) {
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/**
|
||||||
|
* 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.store.amq.reader;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import javax.jms.InvalidSelectorException;
|
||||||
|
import javax.jms.Message;
|
||||||
|
import org.apache.activemq.broker.region.MessageReference;
|
||||||
|
import org.apache.activemq.filter.BooleanExpression;
|
||||||
|
import org.apache.activemq.filter.MessageEvaluationContext;
|
||||||
|
import org.apache.activemq.selector.SelectorParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Iterator for the AMQReader
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class AMQIterator implements Iterator<Message>{
|
||||||
|
private AMQReader reader;
|
||||||
|
private BooleanExpression expression;
|
||||||
|
private MessageLocation currentLocation;
|
||||||
|
private MessageLocation nextLocation;
|
||||||
|
private boolean valid=true;
|
||||||
|
|
||||||
|
|
||||||
|
AMQIterator(AMQReader reader, BooleanExpression expression){
|
||||||
|
this.reader=reader;
|
||||||
|
this.expression=expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
try {
|
||||||
|
this.nextLocation = reader.getNextMessage(currentLocation);
|
||||||
|
Message next = nextLocation != null ? nextLocation.getMessage()
|
||||||
|
: null;
|
||||||
|
if (expression == null) {
|
||||||
|
return next != null;
|
||||||
|
} else {
|
||||||
|
while (next != null) {
|
||||||
|
MessageEvaluationContext context = new MessageEvaluationContext();
|
||||||
|
context.setMessageReference((MessageReference) next);
|
||||||
|
if (expression.matches(context)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
this.nextLocation = reader.getNextMessage(currentLocation);
|
||||||
|
next = nextLocation != null ? nextLocation.getMessage()
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
valid=false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Failed to get next message from reader ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Message next() {
|
||||||
|
if (valid && (nextLocation != null || hasNext())) {
|
||||||
|
this.currentLocation=nextLocation;
|
||||||
|
return nextLocation.getMessage();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
throw new IllegalStateException("Not supported");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
/**
|
||||||
|
* 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.store.amq.reader;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.jms.InvalidSelectorException;
|
||||||
|
import javax.jms.Message;
|
||||||
|
|
||||||
|
import org.apache.activemq.command.DataStructure;
|
||||||
|
import org.apache.activemq.filter.BooleanExpression;
|
||||||
|
import org.apache.activemq.kaha.impl.async.AsyncDataManager;
|
||||||
|
import org.apache.activemq.kaha.impl.async.Location;
|
||||||
|
import org.apache.activemq.openwire.OpenWireFormat;
|
||||||
|
import org.apache.activemq.selector.SelectorParser;
|
||||||
|
import org.apache.activemq.util.ByteSequence;
|
||||||
|
import org.apache.activemq.wireformat.WireFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads and iterates through data log files for the AMQMessage Store
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AMQReader implements Iterable<Message> {
|
||||||
|
|
||||||
|
private AsyncDataManager dataManager;
|
||||||
|
private WireFormat wireFormat = new OpenWireFormat();
|
||||||
|
private File file;
|
||||||
|
private BooleanExpression expression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all the data files in a directory
|
||||||
|
* @param directory
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static Set<File> listDataFiles(File directory) throws IOException{
|
||||||
|
Set<File>result = new HashSet<File>();
|
||||||
|
if (directory == null || !directory.exists() || !directory.isDirectory()) {
|
||||||
|
throw new IOException("Invalid Directory " + directory);
|
||||||
|
}
|
||||||
|
AsyncDataManager dataManager = new AsyncDataManager();
|
||||||
|
dataManager.setDirectory(directory);
|
||||||
|
dataManager.start();
|
||||||
|
Set<File> set = dataManager.getFiles();
|
||||||
|
if (set != null) {
|
||||||
|
result.addAll(set);
|
||||||
|
}
|
||||||
|
dataManager.close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Create the AMQReader to read a directory of amq data logs - or an
|
||||||
|
* individual data log file
|
||||||
|
*
|
||||||
|
* @param file the directory - or file
|
||||||
|
* @throws IOException
|
||||||
|
* @throws InvalidSelectorException
|
||||||
|
* @throws IOException
|
||||||
|
* @throws InvalidSelectorException
|
||||||
|
*/
|
||||||
|
public AMQReader(File file) throws InvalidSelectorException, IOException {
|
||||||
|
this(file,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the AMQReader to read a directory of amq data logs - or an
|
||||||
|
* individual data log file
|
||||||
|
*
|
||||||
|
* @param file the directory - or file
|
||||||
|
* @param selector the JMS selector or null to select all
|
||||||
|
* @throws IOException
|
||||||
|
* @throws InvalidSelectorException
|
||||||
|
*/
|
||||||
|
public AMQReader(File file, String selector) throws IOException, InvalidSelectorException {
|
||||||
|
String str = selector != null ? selector.trim() : null;
|
||||||
|
if (str != null && str.length() > 0) {
|
||||||
|
this.expression=SelectorParser.parse(str);
|
||||||
|
}
|
||||||
|
dataManager = new AsyncDataManager();
|
||||||
|
dataManager.setArchiveDataLogs(false);
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
dataManager.setDirectory(file);
|
||||||
|
} else {
|
||||||
|
dataManager.setDirectory(file.getParentFile());
|
||||||
|
dataManager.setDirectoryArchive(file);
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
dataManager.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Message> iterator() {
|
||||||
|
return new AMQIterator(this,this.expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected MessageLocation getNextMessage(MessageLocation lastLocation)
|
||||||
|
throws IllegalStateException, IOException {
|
||||||
|
if (this.file != null) {
|
||||||
|
return getInternalNextMessage(this.file, lastLocation);
|
||||||
|
}
|
||||||
|
return getInternalNextMessage(lastLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MessageLocation getInternalNextMessage(MessageLocation lastLocation)
|
||||||
|
throws IllegalStateException, IOException {
|
||||||
|
return getInternalNextMessage(null, lastLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MessageLocation getInternalNextMessage(File file,
|
||||||
|
MessageLocation lastLocation) throws IllegalStateException,
|
||||||
|
IOException {
|
||||||
|
MessageLocation result = lastLocation;
|
||||||
|
if (result != null) {
|
||||||
|
result.setMessage(null);
|
||||||
|
}
|
||||||
|
Message message = null;
|
||||||
|
Location pos = lastLocation != null ? lastLocation.getLocation() : null;
|
||||||
|
while ((pos = getNextLocation(file, pos)) != null) {
|
||||||
|
message = getMessage(pos);
|
||||||
|
if (message != null) {
|
||||||
|
if (result == null) {
|
||||||
|
result = new MessageLocation();
|
||||||
|
}
|
||||||
|
result.setMessage(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.setLocation(pos);
|
||||||
|
if (pos == null && message == null) {
|
||||||
|
result = null;
|
||||||
|
} else {
|
||||||
|
result.setLocation(pos);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Location getNextLocation(File file, Location last)
|
||||||
|
throws IllegalStateException, IOException {
|
||||||
|
if (file != null) {
|
||||||
|
return dataManager.getNextLocation(file, last, true);
|
||||||
|
}
|
||||||
|
return dataManager.getNextLocation(last);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Message getMessage(Location location) throws IOException {
|
||||||
|
ByteSequence data = dataManager.read(location);
|
||||||
|
DataStructure c = (DataStructure) wireFormat.unmarshal(data);
|
||||||
|
if (c instanceof Message) {
|
||||||
|
return (Message) c;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/**
|
||||||
|
* 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.store.amq.reader;
|
||||||
|
|
||||||
|
import javax.jms.Message;
|
||||||
|
|
||||||
|
import org.apache.activemq.kaha.impl.async.Location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A holder for a message
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class MessageLocation {
|
||||||
|
private Message message;
|
||||||
|
private Location location;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the location
|
||||||
|
*/
|
||||||
|
public Location getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param location
|
||||||
|
*/
|
||||||
|
public void setLocation(Location location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the message
|
||||||
|
*/
|
||||||
|
public Message getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
public void setMessage(Message message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
Usage:
|
||||||
|
java org.apache.activemq.console.command.store.amq.AMQJournalTool [options]* (directory) *
|
||||||
|
|
||||||
|
Displays the records stored in the Journal log files used by ActiveMQ. This
|
||||||
|
tool supports loading the journal data files from multiple directories. Normally
|
||||||
|
it is run against the journal archive directory and the active journal directory.
|
||||||
|
|
||||||
|
This tool supports controlling the output format using Velocity [1] templates.
|
||||||
|
It also supports filtering out records using a SQL like WHERE syntax implemented
|
||||||
|
using JoSQL.
|
||||||
|
|
||||||
|
Options to control output format:
|
||||||
|
|
||||||
|
Any valid Velocity Template Language (VTL) expression can be used to control the
|
||||||
|
display of the record.
|
||||||
|
|
||||||
|
--message-format=VTL The format used to display message records. Message
|
||||||
|
records get created every time a producer sends a persistent message to the broker.
|
||||||
|
The message gets recorded in the journal even if it's transaction is rolled back.
|
||||||
|
Default VTL: ${location.dataFileId},${location.offset}|${type}|${record.destination}|${record.messageId}|${record.properties}|${body}
|
||||||
|
|
||||||
|
--topic-ack-format=VTL The format used to display topic ack records. A topic
|
||||||
|
ack records that a durable subscription for a topic has acknowleged a set of messages.
|
||||||
|
Default VTL: ${location.dataFileId},${location.offset}|${type}|${record.destination}|${record.clientId}|${record.subscritionName}|${record.messageId}
|
||||||
|
|
||||||
|
--queue-ack-format=VTL The format used to display queue ack records. A queue
|
||||||
|
ack records that a consumer for a quue has acknowleged a message.
|
||||||
|
Default VTL: ${location.dataFileId},${location.offset}|${type}|${record.destination}|${record.messageAck.lastMessageId}
|
||||||
|
|
||||||
|
--transaction-format=VTL The format used to display transaction records. Transaction records
|
||||||
|
are used to record transaction related actions like commit and rollback.
|
||||||
|
Default VTL: ${location.dataFileId},${location.offset}|${type}|${record.transactionId}
|
||||||
|
|
||||||
|
--trace-format=VTL The format used to display trace records.
|
||||||
|
Trace records are informational messages stored in the journal that assist in Auditing.
|
||||||
|
For example a trace message is recorded whenever the broker is restarted or when the
|
||||||
|
long term store is checkpointed.
|
||||||
|
Default VTL: ${location.dataFileId},${location.offset}|${type}|${record.message}
|
||||||
|
|
||||||
|
Options to control the selection of records displayed:
|
||||||
|
--where=VALUE The where clause used to control the records selected
|
||||||
|
for display. It can select on all the fields available in the velocity context.
|
||||||
|
example: --where="type='ActiveMQTextMessage' and location.dataFileId > 2"
|
||||||
|
|
||||||
|
Other Options:
|
||||||
|
--help Show this help screen.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
java org.apache.activemq.console.command.store.amq.AMQJournalTool /path/to/archive /path/to/journal
|
||||||
|
|
||||||
|
|
|
@ -221,6 +221,8 @@
|
||||||
<include>org.codehaus.woodstox:wstx-asl</include>
|
<include>org.codehaus.woodstox:wstx-asl</include>
|
||||||
<include>org.springframework.ws:spring-oxm-tiger</include>
|
<include>org.springframework.ws:spring-oxm-tiger</include>
|
||||||
<include>org.codehaus.jettison:jettison</include>
|
<include>org.codehaus.jettison:jettison</include>
|
||||||
|
<include>velocity:velocity</include>
|
||||||
|
<include>net.sf.josql:josql</include>
|
||||||
</includes>
|
</includes>
|
||||||
</dependencySet>
|
</dependencySet>
|
||||||
<dependencySet>
|
<dependencySet>
|
||||||
|
|
Loading…
Reference in New Issue