summaryrefslogtreecommitdiff
path: root/qpid/java/broker/src/velocity
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/java/broker/src/velocity')
-rw-r--r--qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java527
-rw-r--r--qpid/java/broker/src/velocity/templates/org/apache/qpid/server/logging/messages/LogMessages.vm200
2 files changed, 727 insertions, 0 deletions
diff --git a/qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java b/qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java
new file mode 100644
index 0000000000..a39799a6b6
--- /dev/null
+++ b/qpid/java/broker/src/velocity/java/org/apache/qpid/server/logging/GenerateLogMessages.java
@@ -0,0 +1,527 @@
+/*
+ * 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.server.logging;
+
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.ResourceBundle;
+
+public class GenerateLogMessages
+{
+ private boolean DEBUG = false;
+ private String _tmplDir;
+ private String _outputDir;
+ private List<String> _logMessages = new LinkedList<String>();
+ private String _packageSource;
+
+ public static void main(String[] args)
+ {
+ GenerateLogMessages generator = null;
+ try
+ {
+ generator = new GenerateLogMessages(args);
+ }
+ catch (IllegalAccessException iae)
+ {
+ // This occurs when args does not contain Template and output dirs.
+ System.exit(-1);
+ }
+ catch (Exception e)
+ {
+ //This is thrown by the Velocity Engine initialisation
+ e.printStackTrace();
+ System.exit(-1);
+ }
+
+ try
+ {
+ System.out.println("Running LogMessage Generator");
+ generator.run();
+ }
+ catch (InvalidTypeException e)
+ {
+ // This occurs when a type other than 'number' appears in the
+ // paramater config {0, number...}
+ System.err.println(e.getMessage());
+ System.exit(-1);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ System.exit(-1);
+ }
+ }
+
+ GenerateLogMessages(String[] args) throws Exception
+ {
+ processArgs(args);
+
+ // We need the template and input files to run.
+ if (_tmplDir == null || _outputDir == null || _logMessages.size() == 0 || _packageSource == null)
+ {
+ showUsage();
+ throw new IllegalAccessException();
+ }
+
+ // Initialise the Velocity Engine, Telling it where our macro lives
+ Properties props = new Properties();
+ props.setProperty("file.resource.loader.path", _tmplDir);
+ Velocity.init(props);
+ }
+
+ private void showUsage()
+ {
+ System.out.println("Broker LogMessageGenerator v.2.0");
+ System.out.println("Usage: GenerateLogMessages: [-d] -t <Template Dir> -o <Output Root> -s <Source Directory> <List of _logmessage.property files to process>");
+ System.out.println(" where -d : Additional debug loggin.\n" +
+ " Template Dir: Is the base template to use.");
+ System.out.println(" Output Root: The root form where the LogMessage Classes will be placed.");
+ System.out.println(" Source Dir : The root form where the logmessasge.property files can be found.");
+ System.out.println(" _logmessage.property files must include the full package structure.");
+ }
+
+ public void run() throws InvalidTypeException, Exception
+ {
+ for (String file : _logMessages)
+ {
+ debug("Processing File:" + file);
+
+ createMessageClass(file);
+ }
+ }
+
+ /**
+ * Process the args for:
+ * -t|T value for the template location
+ * -o|O value for the output directory
+ *
+ * @param args the commandline arguments
+ */
+ private void processArgs(String[] args)
+ {
+ // Crude but simple...
+ for (int i = 0; i < args.length; i++)
+ {
+ String arg = args[i];
+ if (args[i].endsWith("_logmessages.properties"))
+ {
+ _logMessages.add(args[i]);
+ }
+ else if (arg.charAt(0) == '-')
+ {
+ switch (arg.charAt(1))
+ {
+ case 'o':
+ case 'O':
+ if (++i < args.length)
+ {
+ _outputDir = args[i];
+ }
+ break;
+ case 't':
+ case 'T':
+ if (++i < args.length)
+ {
+ _tmplDir = args[i];
+ }
+ break;
+ case 's':
+ case 'S':
+ if (++i < args.length)
+ {
+ _packageSource = args[i];
+ }
+ break;
+ case 'd':
+ case 'D':
+ DEBUG=true;
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * This is the main method that generates the _Messages.java file.
+ * The class is generated by extracting the list of messges from the
+ * available LogMessages Resource.
+ *
+ * The extraction is done based on typeIdentifier which is a 3-digit prefix
+ * on the messages e.g. BRK for Broker.
+ *
+ * @throws InvalidTypeException when an unknown parameter type is used in the properties file
+ * @throws Exception thrown by velocity if there is an error
+ */
+ private void createMessageClass(String file)
+ throws InvalidTypeException, Exception
+ {
+ VelocityContext context = new VelocityContext();
+
+ String bundle = file.replace(File.separator, ".");
+
+ int packageStartIndex = bundle.indexOf(_packageSource) + _packageSource.length() + 2;
+
+ bundle = bundle.substring(packageStartIndex, bundle.indexOf(".properties"));
+
+ System.out.println("Creating Class for bundle:" + bundle);
+
+ ResourceBundle fileBundle = ResourceBundle.getBundle(bundle, Locale.US);
+
+ // Pull the bit from /os/path/<className>.logMessages from the bundle name
+ String className = file.substring(file.lastIndexOf(File.separator) + 1, file.lastIndexOf("_"));
+ debug("Creating ClassName form file:" + className);
+
+ String packageString = bundle.substring(0, bundle.indexOf(className));
+ String packagePath = packageString.replace(".", File.separator);
+
+ debug("Package path:" + packagePath);
+
+ File outputDirectory = new File(_outputDir + File.separator + packagePath);
+ if (!outputDirectory.exists())
+ {
+ if (!outputDirectory.mkdirs())
+ {
+ throw new IllegalAccessException("Unable to create package structure:" + outputDirectory);
+ }
+ }
+
+ // Get the Data for this class and typeIdentifier
+ HashMap<String, Object> typeData = prepareType(className, fileBundle);
+
+ context.put("package", packageString.substring(0, packageString.lastIndexOf('.')));
+ //Store the resource Bundle name for the macro
+ context.put("resource", bundle);
+
+ // Store this data in the context for the macro to access
+ context.put("type", typeData);
+
+ // Create the file writer to put the finished file in
+ String outputFile = _outputDir + File.separator + packagePath + className + "Messages.java";
+ debug("Creating Java file:" + outputFile);
+ FileWriter output = new FileWriter(outputFile);
+
+ // Run Velocity to create the output file.
+ // Fix the default file encoding to 'ISO-8859-1' rather than let
+ // Velocity fix it. This is the encoding format for the macro.
+ Velocity.mergeTemplate("LogMessages.vm", "ISO-8859-1", context, output);
+
+ //Close our file.
+ output.flush();
+ output.close();
+ }
+
+ /**
+ * This method does the processing and preparation of the data to be added
+ * to the Velocity context so that the macro can access and process the data
+ *
+ * The given messageKey (e.g. 'BRK') uses a 3-digit code used to match
+ * the property key from the loaded 'LogMessages' ResourceBundle.
+ *
+ * This gives a list of messages which are to be associated with the given
+ * messageName (e.g. 'Broker')
+ *
+ * Each of the messages in the list are then processed to identify how many
+ * parameters the MessageFormat call is expecting. These parameters are
+ * identified by braces ('{}') so a quick count of these can then be used
+ * to create a defined parameter list.
+ *
+ * Rather than defaulting all parameters to String a check is performed to
+ * see if a 'number' value has been requested. e.g. {0. number}
+ * {@see MessageFormat}. If a parameter has a 'number' type then the
+ * parameter will be defined as an Number value. This allows for better
+ * type checking during compilation whilst allowing the log message to
+ * maintain formatting controls.
+ *
+ * OPTIONS
+ *
+ * The returned hashMap contains the following structured data:
+ *
+ * - name - ClassName ('Broker')
+ * - list[logEntryData] - methodName ('BRK_1001')
+ * - name ('BRK-1001')
+ * - format ('Startup : Version: {0} Build: {1}')
+ * - parameters (list)
+ * - type ('String'|'Number')
+ * - name ('param1')
+ * - options (list)
+ * - name ('opt1')
+ * - value ('AutoDelete')
+ *
+ * @param messsageName the name to give the Class e.g. 'Broker'
+ *
+ * @return A HashMap with data for the macro
+ *
+ * @throws InvalidTypeException when an unknown parameter type is used in the properties file
+ */
+ private HashMap<String, Object> prepareType(String messsageName, ResourceBundle messages) throws InvalidTypeException
+ {
+ // Load the LogMessages Resource Bundle
+ Enumeration<String> messageKeys = messages.getKeys();
+
+ //Create the return map
+ HashMap<String, Object> messageTypeData = new HashMap<String, Object>();
+ // Store the name to give to this Class <name>Messages.java
+ messageTypeData.put("name", messsageName);
+
+ // Prepare the list of log messages
+ List<HashMap> logMessageList = new LinkedList<HashMap>();
+ messageTypeData.put("list", logMessageList);
+
+ //Process each of the properties
+ while (messageKeys.hasMoreElements())
+ {
+ HashMap<String, Object> logEntryData = new HashMap<String, Object>();
+
+ //Add MessageName to amp
+ String message = messageKeys.nextElement();
+
+ // Process the log message if it matches the specified key e.g.'BRK_'
+ if (!message.equals("package"))
+ {
+ // Method names can't have a '-' in them so lets make it '_'
+ // e.g. RECOVERY-STARTUP -> RECOVERY_STARTUP
+ logEntryData.put("methodName", message.replace('-', '_'));
+ // Store the real name so we can use that in the actual log.
+ logEntryData.put("name", message);
+
+ //Retrieve the actual log message string.
+ String logMessage = messages.getString(message);
+
+ // Store the value of the property so we can add it to the
+ // Javadoc of the method.
+ logEntryData.put("format", logMessage);
+
+ // Add the parameters for this message
+ logEntryData.put("parameters", extractParameters(logMessage));
+
+ //Add the options for this messages
+ logEntryData.put("options", extractOptions(logMessage));
+
+ //Add this entry to the list for this class
+ logMessageList.add(logEntryData);
+ }
+ }
+
+ return messageTypeData;
+ }
+
+ /**
+ * This method is responsible for extracting the options form the given log
+ * message and providing a HashMap with the expected data:
+ * - options (list)
+ * - name ('opt1')
+ * - value ('AutoDelete')
+ *
+ * The options list that this method provides must contain HashMaps that
+ * have two entries. A 'name' and a 'value' these strings are important as
+ * they are used in LogMessage.vm to extract the stored String during
+ * processing of the template.
+ *
+ * The 'name' is a unique string that is used to name the boolean parameter
+ * and refer to it later in the method body.
+ *
+ * The 'value' is used to provide documentation in the generated class to
+ * aid readability.
+ *
+ * @param logMessage the message from the properties file
+ *
+ * @return list of option data
+ */
+ private List<HashMap<String, String>> extractOptions(String logMessage)
+ {
+ // Split the string on the start brace '{' this will give us the
+ // details for each parameter that this message contains.
+ // NOTE: Simply splitting on '[' prevents the use of nested options.
+ // Currently there is no demand for nested options
+ String[] optionString = logMessage.split("\\[");
+ // Taking an example of:
+ // 'Text {n,type,format} [option] text {m} [option with param{p}] more'
+ // This would give us:
+ // 0 - Text {n,type,format}
+ // 1 - option] text {m}
+ // 2 - option with param{p}] more
+
+ // Create the parameter list for this item
+ List<HashMap<String, String>> options = new LinkedList<HashMap<String, String>>();
+
+ // Check that we have some parameters to process
+ // Skip 0 as that will not be the first entry
+ // Text {n,type,format} [option] text {m} [option with param{p}] more
+ if (optionString.length > 1)
+ {
+ for (int index = 1; index < optionString.length; index++)
+ {
+ // Use a HashMap to store the type,name of the parameter
+ // for easy retrieval in the macro template
+ HashMap<String, String> option = new HashMap<String, String>();
+
+ // Locate the end of the Option
+ // NOTE: it is this simple matching on the first ']' that
+ // prevents the nesting of options.
+ // Currently there is no demand for nested options
+ int end = optionString[index].indexOf("]");
+
+ // The parameter type
+ String value = optionString[index].substring(0, end);
+
+ // Simply name the parameters by index.
+ option.put("name", "opt" + index);
+
+ //Store the value e.g. AutoDelete
+ // We trim as we don't need to include any whitespace that is
+ // used for formating. This is only used to aid readability of
+ // of the generated code.
+ option.put("value", value.trim());
+
+ options.add(option);
+ }
+ }
+
+ return options;
+ }
+
+ /**
+ * This method is responsible for extract the parameters that are requried
+ * for this log message. The data is returned in a HashMap that has the
+ * following structure:
+ * - parameters (list)
+ * - type ('String'|'Number')
+ * - name ('param1')
+ *
+ * The parameters list that is provided must contain HashMaps that have the
+ * two named entries. A 'type' and a 'name' these strings are importans as
+ * they are used in LogMessage.vm to extract and the stored String during
+ * processing of the template
+ *
+ * The 'type' and 'name' values are used to populate the method signature.
+ * This is what gives us the compile time validation of log messages.
+ *
+ * The 'name' must be unique as there may be many parameters. The value is
+ * also used in the method body to pass the values through to the
+ * MessageFormat class for formating the log message.
+ *
+ * @param logMessage the message from the properties file
+ *
+ * @return list of option data
+ *
+ * @throws InvalidTypeException if the FormatType is specified and is not 'number'
+ */
+ private List<HashMap<String, String>> extractParameters(String logMessage)
+ throws InvalidTypeException
+ {
+ // Split the string on the start brace '{' this will give us the
+ // details for each parameter that this message contains.
+ String[] parametersString = logMessage.split("\\{");
+ // Taking an example of 'Text {n[,type]} text {m} more text {p}'
+ // This would give us:
+ // 0 - Text
+ // 1 - n[,type]} text
+ // 2 - m} more text
+ // 3 - p}
+
+ // Create the parameter list for this item
+ List<HashMap<String, String>> parameters = new LinkedList<HashMap<String, String>>();
+
+ // Check that we have some parameters to process
+ // Skip 0 as that will not be the first entry
+ // Text {n[,type]} text {m} more text {p}
+ if (parametersString.length > 1)
+ {
+ for (int index = 1; index < parametersString.length; index++)
+ {
+ // Use a HashMap to store the type,name of the parameter
+ // for easy retrieval in the macro template
+ HashMap<String, String> parameter = new HashMap<String, String>();
+
+ // Check for any properties of the parameter :
+ // e.g. {0} vs {0,number} vs {0,number,xxxx}
+ int typeIndex = parametersString[index].indexOf(",");
+
+ // The parameter type
+ String type;
+
+ //Be default all types are Strings
+ if (typeIndex == -1)
+ {
+ type = "String";
+ }
+ else
+ {
+ //Check string ',....}' for existence of number
+ // to identify this parameter as an integer
+ // This allows for a style value to be present
+ // Only check the text inside the braces '{}'
+ int typeIndexEnd = parametersString[index].indexOf("}", typeIndex);
+ String typeString = parametersString[index].substring(typeIndex, typeIndexEnd);
+ if (typeString.contains("number") || typeString.contains("choice"))
+ {
+ type = "Number";
+ }
+ else
+ {
+ throw new InvalidTypeException("Invalid type(" + typeString + ") index (" + parameter.size() + ") in message:" + logMessage);
+ }
+
+ }
+
+ //Store the data
+ parameter.put("type", type);
+ // Simply name the parameters by index.
+ parameter.put("name", "param" + index);
+
+ parameters.add(parameter);
+ }
+ }
+
+ return parameters;
+ }
+
+ /**
+ * Just a inner exception to be able to identify when a type that is not
+ * 'number' occurs in the message parameter text.
+ */
+ private static class InvalidTypeException extends Exception
+ {
+ public InvalidTypeException(String message)
+ {
+ super(message);
+ }
+ }
+
+ public void debug(String msg)
+ {
+ if (DEBUG)
+ {
+ System.out.println(msg);
+ }
+ }
+
+}
diff --git a/qpid/java/broker/src/velocity/templates/org/apache/qpid/server/logging/messages/LogMessages.vm b/qpid/java/broker/src/velocity/templates/org/apache/qpid/server/logging/messages/LogMessages.vm
new file mode 100644
index 0000000000..fd847fd513
--- /dev/null
+++ b/qpid/java/broker/src/velocity/templates/org/apache/qpid/server/logging/messages/LogMessages.vm
@@ -0,0 +1,200 @@
+/*
+ * 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 ${package};
+
+import static org.apache.qpid.server.logging.AbstractRootMessageLogger.DEFAULT_LOG_HIERARCHY_PREFIX;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * Generated Using GeneratedLogMessages and LogMessages.vm
+ *
+ * This file is based on the content of LogMessages.properties
+ *
+ * It is generated so that we can provide compile time validation of the
+ * message parameters.
+ *
+ * DO NOT EDIT DIRECTLY THIS FILE IS GENERATED.
+ *
+ */
+public class ${type.name}Messages
+{
+ static ResourceBundle _messages;
+ static Locale _currentLocale;
+
+ public static final String ${type.name.toUpperCase()}_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "${type.name.toLowerCase()}";
+#foreach( $message in ${type.list} )
+ public static final String ${message.methodName.toUpperCase()}_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "${type.name.toLowerCase()}.${message.methodName.toLowerCase()}";
+#end
+
+ static
+ {
+ Logger.getLogger(${type.name.toUpperCase()}_LOG_HIERARCHY);
+#foreach( $message in ${type.list} )
+ Logger.getLogger(${message.methodName.toUpperCase()}_LOG_HIERARCHY);
+#end
+
+ reload();
+ }
+
+ public static void reload()
+ {
+ if (ApplicationRegistry.isConfigured())
+ {
+ _currentLocale = ApplicationRegistry.getInstance().getConfiguration().getLocale();
+ }
+ else
+ {
+ _currentLocale = Locale.getDefault();
+ }
+
+ _messages = ResourceBundle.getBundle("${resource}", _currentLocale);
+ }
+
+
+##
+## The list stored under key 'list' in the 'type' HashMap contains all the
+## log messages that this class should contain. So for each entry in the list
+## this template will create a new log method.
+##
+#foreach( $message in ${type.list} )
+ /**
+ * Log a ${type.name} message of the Format:
+ * <pre>${message.format}</pre>
+ * Optional values are contained in [square brackets] and are numbered
+ * sequentially in the method call.
+ *
+ */
+## There is a lot in the method header here. To make it more readable/understandable
+## This is the same text laid out to be easier to read:
+## public static LogMessage ${message.methodName} (
+## #foreach($parameter in ${message.parameters})
+## ${parameter.type} ${parameter.name}
+## #if (${velocityCount} != ${message.parameters.size()} )
+## ,
+## #end
+## #end
+## #if(${message.parameters.size()} > 0 && ${message.options.size()} > 0)
+## ,
+## #end
+## #foreach($option in ${message.options})
+## boolean ${option.name}
+## #if (${velocityCount} != ${message.options.size()} )
+## ,
+## #end
+## #end
+## )
+##
+## What is going on is that we set the method name based on the HashMap lookup
+## for 'methodName' Then for each entry(another HashMap) in the list stored
+## in the HashMap under 'parameters' build the argument list of from the 'type'
+## and 'name' values. Ensuring that we add a ', ' between each entry.
+##
+## However, check that we are not at the last entry of the list as we don't
+## want to add ', ' at then end.
+##
+## Before we go on to the options we perform a check to see if we had any
+## parameters. If we did and we have options to add then we add ', ' to keep
+## the syntax correct.
+##
+## We then go on to the options that are again retrieved from the top HashMap
+## with key 'options'. For each option a boolean argument is created and the
+## name is retrieved from the option HashMap with key 'name'
+##
+ public static LogMessage ${message.methodName}(#foreach($parameter in ${message.parameters})${parameter.type} ${parameter.name}#if (${velocityCount} != ${message.parameters.size()} ), #end
+#end#if(${message.parameters.size()} > 0 && ${message.options.size()} > 0), #end#foreach($option in ${message.options})boolean ${option.name}#if (${velocityCount} != ${message.options.size()} ), #end#end)
+ {
+ String rawMessage = _messages.getString("${message.name}");
+## If we have some options then we need to build the message based
+## on those values so only provide that logic if we need it.
+#if(${message.options.size()} > 0)
+ StringBuffer msg = new StringBuffer();
+
+ // Split the formatted message up on the option values so we can
+ // rebuild the message based on the configured options.
+ String[] parts = rawMessage.split("\\[");
+ msg.append(parts[0]);
+
+ int end;
+ if (parts.length > 1)
+ {
+## For Each Optional value check if it has been enabled and then
+## append it to the log.
+#foreach($option in ${message.options})
+
+ // Add Option : ${option.value}
+ end = parts[${velocityCount}].indexOf(']');
+ if (${option.name})
+ {
+ msg.append(parts[${velocityCount}].substring(0, end));
+ }
+
+ // Use 'end + 1' to remove the ']' from the output
+ msg.append(parts[${velocityCount}].substring(end + 1));
+#end
+ }
+
+ rawMessage = msg.toString();
+#end
+
+##
+## If we don't have any parameters then we don't need the overhead of using the
+## message formatter so we can just set our return message to the retreived
+## fixed string. So we don't need to create a new MessageFormat
+##
+## Here we setup rawMessage to be the formatted message ready for direct return
+## with the message.name or further processing to remove options.
+##
+#if(${message.parameters.size()} > 0)
+ final Object[] messageArguments = {#foreach($parameter in ${message.parameters})${parameter.name}#if (${velocityCount} != ${message.parameters.size()} ), #end#end};
+ // Create a new MessageFormat to ensure thread safety.
+ // Sharing a MessageFormat and using applyPattern is not thread safe
+ MessageFormat formatter = new MessageFormat(rawMessage, _currentLocale);
+
+ final String message = formatter.format(messageArguments);
+#else
+## If we have no parameters then we can skip the formating and set the log
+ final String message = rawMessage;
+#end
+
+ return new LogMessage()
+ {
+ public String toString()
+ {
+ return message;
+ }
+
+ public String getLogHierarchy()
+ {
+ return ${message.methodName.toUpperCase()}_LOG_HIERARCHY;
+ }
+ };
+ }
+
+#end
+
+}