GenerateMessageFile.java revision a395dd575518d9e5280fc5d5d5ef47c61b174647
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2008 Sun Microsystems, Inc.
*/
/**
* Generates a Java class containing representations of messages
* found in a properties file.
*/
public class GenerateMessageFile extends Task {
private boolean overwrite;
static private final String MESSAGES_FILE_STUB =
static private final String REGISTRY_FILE_NAME =
/**
* Used to set a category for all messages in the property file.
* If set, the category for each message need not be encoded in
* the message's property file key.
*/
/**
* Used to set a severity for all messages in the property file.
* If set, the severity for each message need not be encoded in
* the message's property file key.
*/
/**
* Used to set a category mask for all messages in the property
* file. If set, the category will automatically be assigned
* USER_DEFINED and the value of <code>GLOBAL_CATEGORY</code>
* will be ignored.
*/
/**
* When true generates messages that have no ordinals.
*/
/**
* When true and if the Java Web Start property is set use the class loader of
* the jar where the MessageDescriptor is contained to retrieve the
* ResourceBundle.
*/
static private final String GLOBAL_USE_MESSAGE_JAR_IF_WEBSTART =
"global.use.message.jar.if.webstart";
static {
}
static private final String SPECIFIER_REGEX =
"%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])";
/**
* Message giving formatting rules for string keys.
*/
static public String KEY_FORM_MSG;
static {
KEY_FORM_MSG = new StringBuilder()
.append(".\n\nOpenDS message property keys must be of the form\n\n")
.append("\t\'[CATEGORY]_[SEVERITY]_[DESCRIPTION]_[ORDINAL]\'\n\n")
.append("where\n\n")
.append("CATEGORY is one of ")
.append("\n\nSEVERITY is one of ")
.append("\n\nDESCRIPTION is a descriptive string composed ")
.append("of uppercase character, digits and underscores ")
.append("describing the purpose of the message ")
.append("\n\nORDINAL is an integer between 0 and 65535 that is ")
.append("unique to other messages defined in this file.\n\n")
.append("You can relax the mandate for including the CATEGORY, ")
.append("of the following respective property directives in your ")
.append("properties file: ")
.append(", ")
.append(", ")
.append("and setting their value appropriately.")
.toString();
}
/**
* Representation of a format specifier (for example %s).
*/
private class FormatSpecifier {
/**
* Creates a new specifier.
* @param sa specifier components
*/
}
/**
* Indicates whether or not the specifier uses arguement
* indexes (for example 2$).
* @return boolean true if this specifier uses indexing
*/
public boolean specifiesArgumentIndex() {
}
/**
* Returns a java class associated with a particular formatter
* based on the conversion type of the specifier.
* @return Class for representing the type of arguement used
* as a replacement for this specifier.
*/
public Class getSimpleConversionClass() {
c = Calendar.class;
} else if (
c = Boolean.class;
} else if (
c = Integer.class;
} else if (
c = CharSequence.class;
} else if (
c = Character.class;
} else if (
c = Number.class;
} else if (
// ignore literals
}
return c;
}
}
/**
* Represents a message to be written into the messages files.
*/
private class MessageDescriptorDeclaration {
private MessagePropertyKey key;
private String formatString;
private String[] constructorArgs;
/**
* Creates a parameterized instance.
* @param key of the message
* @param formatString of the message
*/
this.formatString = formatString;
for (FormatSpecifier f : specifiers) {
Class c = f.getSimpleConversionClass();
if (c != null) {
classTypes.add(c);
}
}
}
/**
* Gets the name of the Java class that will be used to represent
* this message's type.
* @return String representing the Java class name
*/
public String getDescriptorClassDeclaration() {
if (useGenericMessageTypeClass()) {
} else {
}
}
/**
* Gets a string representing the message type class' variable
* information (for example '<String,Integer>') that is based on
* the type of arguments specified by the specifiers in this message.
* @return String representing the message type class parameters
*/
public String getClassTypeVariables() {
if (c != null) {
}
}
}
}
}
/**
* Gets the javadoc comments that will appear above the messages declaration
* in the messages file.
* @return String comment
*/
public String getComment() {
// Unwrapped so that you can search through the descriptor
// file for a message and not have to worry about line breaks
}
}
/**
* Sets the arguments that will be supplied in the declaration
* of the message.
* @param s array of string arguments that will be passed
* in the constructor
*/
public void setConstructorArguments(String... s) {
this.constructorArgs = s;
}
/**
* {@inheritDoc}
*/
if (constructorArgs != null) {
}
}
}
}
/**
* Indicates whether the generic message type class should
* be used. In general this is when a format specifier is
* more complicated than we support or when the number of
* arguments exceeeds the number of specific message type
* classes (MessageType0, MessageType1 ...) that are defined.
* @return boolean indicating
*/
private boolean useGenericMessageTypeClass() {
return true;
} else if (specifiers != null) {
for (FormatSpecifier s : specifiers) {
if (s.specifiesArgumentIndex()) {
return true;
}
}
}
return false;
}
/**
* Look for format specifiers in the format string.
* @param s format string
* @return list of format specifiers
*/
int i = 0;
while (i < s.length()) {
if (m.find(i)) {
// Anything between the start of the string and the beginning
// of the format specifier is either fixed text or contains
// an invalid format string.
if (m.start() != i) {
// Make sure we didn't miss any invalid format specifiers
// Assume previous characters were fixed text
//al.add(new FixedString(s.substring(i, m.start())));
}
// Expect 6 groups in regular expression
for (int j = 0; j < m.groupCount(); j++) {
}
i = m.end();
} else {
// No more valid format specifiers. Check for possible invalid
// format specifiers.
// The rest of the string is fixed text
//al.add(new FixedString(s.substring(i)));
break;
}
}
return sl;
}
int idx;
// If there are any '%' in the given string, we got a bad format
// specifier.
}
}
}
/**
* Sets the source of the messages.
* @param source File representing the properties
* file containing messages
*/
}
/**
* Sets the file that will be generated containing
* declarations of messages from <code>source</code>.
* @param dest File destination
*/
}
/**
* Indicates when true that an existing destination
* file will be overwritten.
* @param o boolean where true means overwrite
*/
public void setOverwrite(boolean o) {
this.overwrite = o;
}
/**
* {@inheritDoc}
*/
public void execute() throws BuildException {
try {
// Decide whether to generate messages based on modification
// times and print status messages.
" does not exist");
}
} else {
return;
}
} else {
if (!javaGenDir.exists()) {
javaGenDir.mkdirs();
}
}
}
} else {
}
}
// Determine the value of the global severity
}
try {
globalCategory == null,
globalSeverity == null,
globalOrdinal == null);
}
} catch (IllegalArgumentException iae) {
throw new BuildException(
"ERROR: invalid property key " + propKey +
}
}
int usesOfGenericDescriptor = 0;
// Check that this category is the same as all the
// others in this file. Maybe this should be an error?
if (firstCategory != null) {
if (!firstCategory.equals(c)) {
}
} else {
firstCategory = c;
}
if (c == null) {
throw new BuildException(
"No category could be assigned to message " +
key + ". The category " +
"must either be encoded in the property key or " +
"or must be set by including the property " +
GLOBAL_CATEGORY + " in the properties file" +
}
if (c == null) {
throw new BuildException(
"No severity could be assigned to message " +
key + ". The severity " +
"must either be encoded in the property key or " +
"or must be set by including the property " +
GLOBAL_SEVERITY + " in the properties file" +
}
if (globalOrdinal == null) {
throw new BuildException(
key + " has been previously defined in " +
source + KEY_FORM_MSG);
} else {
}
}
"BASE",
s.name(),
globalOrdinal != null ?
);
// Keep track of when we use the generic descriptor
// so that we can report it later
if (message.useGenericMessageTypeClass()) {
}
}
} else {
".java".length()));
if ((useMessageJarIfWebstart != null) &&
{
useMessageJarIfWebstart = "true";
}
else
{
useMessageJarIfWebstart = "false";
}
}
}
stubReader.close();
destWriter.close();
} catch (Exception e) {
// Don't leave a malformed file laying around. Delete
// it so it will be forced to be regenerated.
dest.deleteOnExit();
}
e.printStackTrace();
": " + e.getMessage());
} finally {
if (stubReader != null) {
try {
stubReader.close();
} catch (Exception e){
// ignore
}
}
if (destWriter != null) {
try {
destWriter.close();
} catch (Exception e){
// ignore
}
}
}
}
private String getMessageDescriptorFullClassName() {
}
private String getMessageDescriptorClassName() {
}
}
return base;
}
private String getPackage() {
return c;
}
return new String(blankArray);
}
return new StringBuilder()
.append("\"")
.append(s)
.append("\"")
.toString();
}
if (i > 0) {
} else {
}
return name;
}
/**
* Writes a record in the messages registry for the specifed
* class name.
* @param descClassName name of the message descriptor class
* @return true if the class was acutally added to the registry;
* false indicates that the class was already present.
* @throws IOException if there is a problem with the file I/O
*/
throws IOException
{
boolean classAdded = false;
if (!isDescriptorRegistered(descClassName)) {
}
return classAdded;
}
throws IOException
{
boolean isRegistered = false;
new FileReader(getRegistryFile()));
isRegistered = true;
break;
}
}
return isRegistered;
}
}
}
return registry;
}
private File getProjectBase() {
// Get the path to build.xml and return the parent
// directory else just return the working directory.
Location l = getLocation();
projectBase = f.getParentFile();
} else {
}
return projectBase;
}
}
private File getStubFile() {
}
/**
* For testing.
* @param args from command line
*/
gmf.setOverwrite(true);
}
}