/*
* 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 legal-notices/CDDLv1_0.txt
* 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 legal-notices/CDDLv1_0.txt.
* 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-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2012 ForgeRock AS
*/
/**
* Generates a Java class containing representations of messages
* found in a properties file.
*/
private boolean overwrite;
private boolean writeLogRef;
/*
* The registry filename is the result of the concatenation of the
* location of where the source are generated, the package name and the
* DESCRIPTORS_REG value.
*/
/**
* 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.
*/
"global.use.message.jar.if.webstart";
static {
}
"%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])";
/**
* Message giving formatting rules for string keys.
*/
static {
KEY_FORM_MSG = new StringBuilder()
.append(".\n\nOpenDJ 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();
}
/*
* ISO_LANGUAGES contains all official supported languages for i18n
*/
/*
* ISO_COUNTRIES contains all official supported countries for i18n
*/
/*
* A Pattern instance that matches "<label>_<language>_<country>.properties"
* where <label> can be anything including '_'
* <language> a two characters code contained in the ISO_LANGUAGES list
* <country> a two characters code contained in the ISO_COUNTRIES list
*/
/*
* A Pattern instance that matches "<label>_<language>.properties"
* where <label> and <language> have same definition as above.
*/
/**
* 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 argument
* 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 argument used
* as a replacement for this specifier.
*/
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 {
/**
* 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
*/
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
*/
if (c != null) {
}
}
}
}
}
/**
* Gets the javadoc comments that will appear above the messages declaration
* in the messages file.
* @return String comment
*/
// 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
*/
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
*/
try {
if (REGISTRY_FILE_NAME != null) {
// if REGISTRY_FILE_NAME is already set, ensure that we computed the
// same one
+ ": all messages must be located in the same package thus "
+ "name of the source file should be "
}
} else {
}
} catch (Exception e) {
throw (new BuildException(e));
}
}
/**
* 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;
}
/**
* Indicates when true that an XML log message reference should be generated
* instead of a Java messages file.
*
* @param xml
* true means write an XML log message reference
*/
this.writeLogRef = xml;
}
/**
* Represents a log reference entry for an individual message.
*/
{
/**
* Build log reference entry for an log message.
*
* @param category
* @param severity
* @param ordinal
* @param formatString
*/
{
this.formatString = formatString;
}
{
}
/**
* Return a DocBook XML <varlistentry> of this log reference entry.
* This implementation copies the message string verbatim, and does not
* interpret format specifiers.
*
* @return DocBook XML <varlistentry>.
*/
{
return
+ " <listitem>" + EOL
}
/**
* Calls {@link #toString()}.
*/
{
return toString();
}
/**
* The unique message identifier is calculated using the category, severity,
* and message ordinal.
*
* @return unique message identifier
*/
{
return this.id;
}
/**
* Compare message entries by unique identifier.
*
* @return See {@link java.lang.Comparable#compareTo(Object)}.
*/
{
}
}
/**
* One-line descriptions for log reference categories
*/
static {
+ " installer and uninstaller.");
+ " extended operations, SASL mechanisms, password storage"
+ " schemes, password validators, and so on).");
+ " (for example, ASN.1 and LDAP).");
+ " information.");
+ " user-defined) modules.");
}
/**
* Represents a log reference list of messages for a category.
*/
private class MessageRefCategory
{
{
}
{
return "<para>This category concerns messages associated with "
}
/**
* Return a DocBook XML <variablelist> of this log reference category.
*
* @return DocBook XML <variablelist>
*/
{
{
}
}
/**
* Calls {@link #toString()}.
*/
{
return toString();
}
{
return new StringBuilder()
.append(" ! enclosed by brackets \"[]\" replaced with your own identifying information:").append(EOL)
.toString();
}
{
return "xmlns='http://docbook.org/ns/docbook'"
+ " version='5.0' xml:lang='en'"
+ " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'"
+ " xsi:schemaLocation='http://docbook.org/ns/docbook"
+ " xmlns:xlink='http://www.w3.org/1999/xlink'"
+ " xmlns:xinclude='http://www.w3.org/2001/XInclude'";
}
{
return getXMLPreamble() + " <variablelist xml:id=\"log-ref-"
}
{
return " </variablelist>" + EOL;
}
}
/**
* {@inheritDoc}
*/
// this is an example-plugin call:
// - check the source file is not a localization
// - guess the destination filename from source filename
/*
* Make sure only <label>.properties are generated thus avoiding to
* generate messages for localized properties files.
*/
// do not generate message for <label>_<language>_<country>.properties
return;
}
}
// do not generate message for <label>_<language>.properties
return;
}
}
// filename without ".properties"
// change to src-generated directory keeping package name
if (writeLogRef) {
} else {
}
// append characters from filename to pathname starting with an uppercase
// letter, ignoring '_' and uppering all characters prefixed with "_"
boolean upperCaseNextChar = true;
for(char c : filename.toCharArray()) {
if ( c == '_' || c == '-' ) {
upperCaseNextChar = true;
continue;
}
if ( upperCaseNextChar ) {
upperCaseNextChar = false;
} else {
}
}
if (writeLogRef) {
} else {
}
}
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();
}
}
"UTF-8"));
new TreeSet<MessageRefEntry>();
}
} 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 (s == 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 {
}
}
if (writeLogRef) {
// Document only FATAL_ERROR and SEVERE_ERROR messages.
new MessageRefEntry(
c,
s,
globalOrdinal != null ?
key.getOrdinal(),
}
} 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()) {
}
}
if (writeLogRef) {
if (messageRefEntries.isEmpty()) {
} else {
}
}
} else if (!writeLogRef) {
".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
}
}
}
}
}
}
return base;
}
if (writeLogRef) { return "dummy.package.name"; }
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;
}
return getProject().getBaseDir();
}
}
/*
* Returns the stub file ("resource/Messages.java.stub") from the appropriate
* location: ant or jar file.
*/
// this is the OpenDS's ant project calling
// Stub is located at OPENDS_ROOT/resource/Messages.java.stub
try {
} catch (FileNotFoundException e) {
// should neven happen
throw new BuildException("Unable to load template " +
}
} else {
// this is the example plugin's ant project calling
// Stub is located at build-tools.jar:resource/Messages.java.stub
}
return result;
}
/**
* For testing.
* @param args from command line
*/
{
gmf.setWriteLogRef(true);
}
gmf.setOverwrite(true);
}
}