resgen/0000755000175000017500000000000011543216467012246 5ustar drazzibdrazzibresgen/build.xml0000444000175000017500000001771711543216467014102 0ustar drazzibdrazzib
resgen/misc/0000755000175000017500000000000011543216467013201 5ustar drazzibdrazzibresgen/misc/Meta.xsl0000444000175000017500000004702311543216467014623 0ustar drazzibdrazzib

XOM Meta Model Instance

DTD Name:
Class Name: TODO.java
Root Element: #
Version:

Overview

Imports

Element Summary

Classes

Element

Class

#

Attributes

AttributeTypeDefault Description
String none none
none

Content

ElementJava NameConstraintsDescription
# Required Array [ .. ] Array Optional none
Any Text empty
; keep DOM node

Plugin

Class

#

Attributes

AttributeTypeDefault Description
String none none
defPackageString TODO The defPackage attribute, available to all Plugins, specifies the package of the Java Class used to parse all plugin contents.
defClassString TODO The defClass attribute, available to all Plugins, specifies the class name of the Java Class used to parse all plugin contents.

Content

Any from defClass

Class

Superclass

#

Attributes

AttributeTypeDefault Description
String none none
none

Content

ElementJava NameConstraintsDescription
# Required Array [ .. ] Array Optional none
Any Text empty

StringElement

Attributes

none

Content

Text

Import

Package:
Class:
DTD:

resgen/lib/0000755000175000017500000000000011543216467013014 5ustar drazzibdrazzibresgen/COPYING0000444000175000017500000006347611543216467013317 0ustar drazzibdrazzib GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! resgen/src/0000755000175000017500000000000011543216467013035 5ustar drazzibdrazzibresgen/src/org/0000755000175000017500000000000011543216467013624 5ustar drazzibdrazzibresgen/src/org/eigenbase/0000755000175000017500000000000011543216467015546 5ustar drazzibdrazzibresgen/src/org/eigenbase/resgen/0000755000175000017500000000000011543216467017031 5ustar drazzibdrazzibresgen/src/org/eigenbase/resgen/JavaLocaleGenerator.java0000444000175000017500000000547211543216467023552 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/JavaLocaleGenerator.java#2 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import java.util.Locale; import java.io.PrintWriter; import java.io.File; /** * Generates a Java class for a locale. * * @author jhyde * @since 19 September, 2005 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/JavaLocaleGenerator.java#2 $ */ public class JavaLocaleGenerator extends AbstractJavaGenerator { private final Locale locale; JavaLocaleGenerator( File srcFile, File file, String className, ResourceDef.ResourceBundle resourceBundle, Locale locale, String baseClassName) { super(srcFile, file, className, resourceBundle, baseClassName); this.locale = locale; } public void generateModule(ResourceGen generator, ResourceDef.ResourceBundle resourceList, PrintWriter pw) { generateHeader(pw); // e.g. "happy.BirthdayResource_en_US" String className = getClassName(); // e.g. "BirthdayResource_en_US" String classNameSansPackage = Util.removePackage(className); // e.g. "happy.BirthdayResource" final String baseClass = getBaseClassName(); // e.g. "BirthdayResource" String baseClassSansPackage = Util.removePackage(baseClass); pw.println("public class " + classNameSansPackage + " extends " + baseClassSansPackage + " {"); pw.println(" public " + classNameSansPackage + "() throws IOException {"); pw.println(" }"); pw.println("}"); pw.println(""); generateFooter(pw, classNameSansPackage); } public void generateResource(ResourceDef.Resource resource, PrintWriter pw) { throw new UnsupportedOperationException(); } } // End JavaLocaleGenerator.java resgen/src/org/eigenbase/resgen/Util.java0000444000175000017500000004075111543216467020616 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/Util.java#6 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import org.eigenbase.xom.*; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Locale; /** * Miscellaneous utility methods for the org.eigenbase.resgen * package, all them static and package-private. * * @author jhyde * @since 3 December, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/Util.java#6 $ **/ abstract class Util { private static final Throwable[] emptyThrowableArray = new Throwable[0]; /** loads URL into Document and returns set of resources **/ static ResourceDef.ResourceBundle load(URL url) throws IOException { return load(url.openStream()); } /** loads InputStream and returns set of resources **/ static ResourceDef.ResourceBundle load(InputStream inStream) throws IOException { try { Parser parser = XOMUtil.createDefaultParser(); DOMWrapper def = parser.parse(inStream); ResourceDef.ResourceBundle xmlResourceList = new ResourceDef.ResourceBundle(def); return xmlResourceList; } catch (XOMException err) { throw new IOException(err.toString()); } } /** * Left-justify a block of text. Line breaks are preserved, but long lines * are broken. * * @param pw where to output the formatted text * @param text the text to be written * @param linePrefix a string to prepend to each output line * @param lineSuffix a string to append to each output line * @param maxTextPerLine the maximum number of characters to place on * each line, not counting the prefix and suffix. If this is -1, * never break lines. **/ static void fillText( PrintWriter pw, String text, String linePrefix, String lineSuffix, int maxTextPerLine) { int i = 0; for (;;) { int end = text.length(); if (end <= i) { // Nothing left. We're done. break; } if (i > 0) { // End the previous line and start another. pw.println(lineSuffix); pw.print(linePrefix); } int nextCR = text.indexOf("\r", i); if (nextCR >= 0 && nextCR < end) { end = nextCR; } int nextLF = text.indexOf("\n", i); if (nextLF >= 0 && nextLF < end) { end = nextLF; } if (maxTextPerLine > 0 && i + maxTextPerLine <= end) { // More than a line left. Break at the last space before the // line limit. end = text.lastIndexOf(" ",i + maxTextPerLine); if (end < i) { // No space exists before the line limit; look beyond it. end = text.indexOf(" ",i); if (end < 0) { // No space anywhere in the line. Take the whole line. end = text.length(); } } } pw.print(text.substring(i, end)); // The line is short enough. Print it, and find where the next one // starts. i = end; while (i < text.length() && (text.charAt(i) == ' ' || text.charAt(i) == '\r' || text.charAt(i) == '\n')) { i++; } } } static URL stringToUrl(String strFile) throws IOException { try { File f = new File(strFile); return convertPathToURL(f); } catch (Throwable err) { throw new IOException(err.toString()); } } /** * Creates a file-protocol URL for the given filename. **/ static URL convertPathToURL(File file) { try { String path = file.getAbsolutePath(); // This is a bunch of weird code that is required to // make a valid URL on the Windows platform, due // to inconsistencies in what getAbsolutePath returns. String fs = System.getProperty("file.separator"); if (fs.length() == 1) { char sep = fs.charAt(0); if (sep != '/') path = path.replace(sep, '/'); if (path.charAt(0) != '/') path = '/' + path; } path = "file://" + path; return new URL(path); } catch (MalformedURLException e) { throw new java.lang.Error(e.getMessage()); } } static String formatError(String template, Object[] args) { String s = template; for (int i = 0; i < args.length; i++) { String arg = args[i].toString(); s = replace(s, "%" + (i + 1), arg); s = replace(s, "%i" + (i + 1), arg); } return s; } /** Returns s with every instance of find * converted to replace. */ static String replace(String s,String find,String replace) { // let's be optimistic int found = s.indexOf(find); if (found == -1) { return s; } StringBuffer sb = new StringBuffer(s.length()); int start = 0; for (;;) { for (; start < found; start++) { sb.append(s.charAt(start)); } if (found == s.length()) { break; } sb.append(replace); start += find.length(); found = s.indexOf(find,start); if (found == -1) { found = s.length(); } } return sb.toString(); } /** Return val in double-quotes, suitable as a string in a * Java or JScript program. * * @param val the value * @param nullMeansNull whether to print a null value as null * (the default), as opposed to "" */ static String quoteForJava(String val,boolean nullMeansNull) { if (val == null) { return nullMeansNull ? "null" : ""; } String s0; s0 = replace(val, "\\", "\\\\"); s0 = replace(val, "\"", "\\\""); s0 = replace(s0, "\n\r", "\\n"); s0 = replace(s0, "\n", "\\n"); s0 = replace(s0, "\r", "\\r"); return "\"" + s0 + "\""; } static String quoteForJava(String val) { return quoteForJava(val,true); } /** * Returns a string quoted so that it can appear in a resource file. */ static String quoteForProperties(String val) { String s0; s0 = replace(val, "\\", "\\\\"); // s0 = replace(val, "\"", "\\\""); // s0 = replace(s0, "'", "''"); s0 = replace(s0, "\n\r", "\\n"); s0 = replace(s0, "\n", "\\n"); s0 = replace(s0, "\r", "\\r"); s0 = replace(s0, "\t", "\\t"); return s0; } static final char fileSep = System.getProperty("file.separator").charAt(0); static String fileNameToClassName(String fileName, String suffix) { String s = fileName; s = removeSuffix(s, suffix); s = s.replace(fileSep, '.'); s = s.replace('/', '.'); int score = s.indexOf('_'); if (score >= 0) { s = s.substring(0,score); } return s; } static String fileNameToCppClassName(String fileName, String suffix) { String s = fileName; s = removeSuffix(s, suffix); int pos = s.lastIndexOf(fileSep); if (pos >= 0) { s = s.substring(pos + 1); } int score = s.indexOf('_'); if (score >= 0) { s = s.substring(0, score); } return s; } static String removeSuffix(String s, final String suffix) { if (s.endsWith(suffix)) { s = s.substring(0,s.length()-suffix.length()); } return s; } /** * Given happy/BirthdayResource_en_US.xml, * returns the locale "en_US". */ static Locale fileNameToLocale(String fileName, String suffix) { String s = removeSuffix(fileName, suffix); int score = s.indexOf('_'); if (score <= 0) { return null; } else { String localeName = s.substring(score + 1); return parseLocale(localeName); } } /** * Parses 'localeName' into a locale. */ static Locale parseLocale(String localeName) { int score1 = localeName.indexOf('_'); String language, country = "", variant = ""; if (score1 < 0) { language = localeName; } else { language = localeName.substring(0, score1); if (language.length() != 2) { return null; } int score2 = localeName.indexOf('_',score1 + 1); if (score2 < 0) { country = localeName.substring(score1 + 1); if (country.length() != 2) { return null; } } else { country = localeName.substring(score1 + 1, score2); if (country.length() != 2) { return null; } variant = localeName.substring(score2 + 1); } } return new Locale(language,country,variant); } /** * Given "happy/BirthdayResource_fr_FR.properties" and ".properties", * returns "happy/BirthdayResource". */ static String fileNameSansLocale(String fileName, String suffix) { String s = removeSuffix(fileName, suffix); // If there are directory names, start reading after the last one. int from = s.lastIndexOf(fileSep); if (from < 0) { from = 0; } while (from < s.length()) { // See whether the rest of the filename after the current // underscore is a valid locale name. If it is, return the // segment of the filename before the current underscore. int score = s.indexOf('_', from); Locale locale = parseLocale(s.substring(score+1)); if (locale != null) { return s.substring(0,score); } from = score + 1; } return s; } /** * Converts a chain of {@link Throwable}s into an array. **/ static Throwable[] toArray(Throwable err) { ArrayList list = new ArrayList(); while (err != null) { list.add(err); err = getCause(err); } return (Throwable[]) list.toArray(emptyThrowableArray); } private static final Class[] emptyClassArray = new Class[0]; private static Throwable getCause(Throwable err) { if (err instanceof InvocationTargetException) { return ((InvocationTargetException) err).getTargetException(); } try { Method method = err.getClass().getMethod( "getCause", emptyClassArray); if (Throwable.class.isAssignableFrom(method.getReturnType())) { return (Throwable) method.invoke(err, new Object[0]); } } catch (NoSuchMethodException e) { } catch (SecurityException e) { } catch (IllegalAccessException e) { } catch (IllegalArgumentException e) { } catch (InvocationTargetException e) { } try { Method method = err.getClass().getMethod( "getNestedThrowable", emptyClassArray); if (Throwable.class.isAssignableFrom(method.getReturnType())) { return (Throwable) method.invoke(err, new Object[0]); } } catch (NoSuchMethodException e) { } catch (SecurityException e) { } catch (IllegalAccessException e) { } catch (IllegalArgumentException e) { } catch (InvocationTargetException e) { } return null; } /** * Formats an error, which may have chained errors, as a string. */ static String toString(Throwable err) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); Throwable[] throwables = toArray(err); for (int i = 0; i < throwables.length; i++) { Throwable throwable = throwables[i]; if (i > 0) { pw.println(); pw.print("Caused by: "); } pw.print(throwable.toString()); } return sw.toString(); } static void printStackTrace(Throwable throwable, PrintWriter s) { Throwable[] stack = Util.toArray(throwable); PrintWriter pw = new DummyPrintWriter(s); for (int i = 0; i < stack.length; i++) { if (i > 0) { pw.println("caused by"); } stack[i].printStackTrace(pw); } pw.flush(); } static void printStackTrace(Throwable throwable, PrintStream s) { Throwable[] stack = Util.toArray(throwable); PrintStream ps = new DummyPrintStream(s); for (int i = 0; i < stack.length; i++) { if (i > 0) { ps.println("caused by"); } stack[i].printStackTrace(ps); } ps.flush(); } static void generateCommentBlock( PrintWriter pw, String name, String text, String comment) { final String indent = " "; pw.println(indent + "/**"); if (comment != null) { fillText(pw, comment, indent + " * ", "", 70); pw.println(); pw.println(indent + " *"); } pw.print(indent + " * "); fillText( pw, "" + name + " is '" + StringEscaper.xmlEscaper.escapeString(text) + "'", indent + " * ", "", -1); pw.println(); pw.println(indent + " */"); } /** * Returns the class name without its package name but with a locale * extension, if applicable. * For example, if class name is happy.BirthdayResource, * and locale is en_US, * returns BirthdayResource_en_US. */ static String getClassNameSansPackage(String className, Locale locale) { String s = className; int lastDot = className.lastIndexOf('.'); if (lastDot >= 0) { s = s.substring(lastDot + 1); } if (locale != null) { s += '_' + locale.toString(); } return s; } protected static String removePackage(String s) { int lastDot = s.lastIndexOf('.'); if (lastDot >= 0) { s = s.substring(lastDot + 1); } return s; } /** * So we know to avoid recursively calling * {@link Util#printStackTrace(Throwable,java.io.PrintWriter)}. */ static class DummyPrintWriter extends PrintWriter { public DummyPrintWriter(Writer out) { super(out); } } /** * So we know to avoid recursively calling * {@link Util#printStackTrace(Throwable,PrintStream)}. */ static class DummyPrintStream extends PrintStream { public DummyPrintStream(OutputStream out) { super(out); } } } // End Util.java resgen/src/org/eigenbase/resgen/AbstractGenerator.java0000444000175000017500000001411611543216467023307 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/AbstractGenerator.java#3 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import java.io.PrintWriter; import java.io.File; import java.util.Date; import java.text.Format; import java.text.MessageFormat; import java.text.NumberFormat; import java.text.DateFormat; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; /** * Abstract base for all generators. * * @author jhyde * @since 19 September, 2005 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/AbstractGenerator.java#3 $ */ abstract class AbstractGenerator implements Generator { private final File srcFile; private final File file; private Boolean scmSafeComments = null; public AbstractGenerator(File srcFile, File file) { this.srcFile = srcFile; this.file = file; } public void setScmSafeComments(boolean enabled) { if (scmSafeComments != null) { throw new AssertionError( "SCM safe comment style may only be configured once."); } scmSafeComments = enabled ? Boolean.TRUE : Boolean.FALSE; } protected boolean useScmSafeComments() { return scmSafeComments != null && scmSafeComments.booleanValue(); } /** * Generates code for a particular resource. */ protected abstract void generateResource( ResourceDef.Resource resource, PrintWriter pw); protected void generateDoNotModifyHeader(PrintWriter pw) { if (useScmSafeComments()) { pw.println( "// This class is generated. Do NOT modify it manually."); } else { pw.println("// This class is generated. Do NOT modify it, or"); pw.println("// add it to source control."); } pw.println(); } protected void generateGeneratedByBlock(PrintWriter pw) { pw.println("/**"); pw.println(" * This class was generated"); pw.println(" * by " + ResourceGen.class); String file = getSrcFileForComment(); pw.println(" * from " + file); if (!useScmSafeComments()) { pw.println(" * on " + new Date().toString() + "."); } pw.println(" * It contains a list of messages, and methods to"); pw.println(" * retrieve and format those messages."); pw.println(" */"); pw.println(); } /** * Returns the generator's output file. e.g., "BirthdayResource.java" */ protected File getFile() { return file; } /** * Returns the XML or .properties source file, in a manner suitable * for use in source code comments. Path information is stripped if * SCM-safe comment style is enabled. * * @see #setScmSafeComments(boolean) */ protected String getSrcFileForComment() { String filename = srcFile.toString().replace('\\', '/'); if (useScmSafeComments()) { int slashPos = filename.lastIndexOf('/'); if (slashPos > 0) { filename = "..." + filename.substring(slashPos); } } return filename; } /** * Returns the fully-qualified name of the class being generated, * for example "happy.BirthdayResource_en_US". */ protected abstract String getClassName(); /** * Returns the fully-qualified name of the base class. */ protected abstract String getBaseClassName(); /** * Returns a parameter list string, e.g. "String p0, int p1". */ protected String getParameterList(String message) { final String [] types = getArgTypes(message); if (types.length == 0) { return ""; } StringBuffer sb = new StringBuffer(); for (int i = 0; i < types.length; i++) { String type = types[i]; if (i > 0) { sb.append(", "); } sb.append(type); // If this is a C++ pointer type, say "const char *", don't put // a space between it and the variable name. if (!type.endsWith("&") && !type.endsWith("*")) { sb.append(" "); } sb.append("p"); sb.append(Integer.toString(i)); } return sb.toString(); } /** * Returns the number and types of parameters in the given error message, * expressed as an array of Strings (legal values are * currently "String", "Number", "java.util.Date", and null) ordered by * parameter number. */ protected abstract String [] getArgTypes(String message); protected String getArgumentList(String message) { final String [] types = getArgTypes(message); if (types.length == 0) { return ""; } StringBuffer sb = new StringBuffer(); for (int i = 0; i < types.length; i++) { if (i > 0) { sb.append(", "); } sb.append("p"); sb.append(Integer.toString(i)); } return sb.toString(); } } // End AbstractGenerator.java resgen/src/org/eigenbase/resgen/CppHeaderGenerator.java0000444000175000017500000002037111543216467023377 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/CppHeaderGenerator.java#3 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import java.io.File; import java.io.PrintWriter; /** * Generates a C++ header file containing resource definitions. * * @author jhyde * @since 19 September, 2005 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/CppHeaderGenerator.java#3 $ */ public class CppHeaderGenerator extends CppGenerator { /** * Creates a C++ header generator. * * @param srcFile * @param file * @param className * @param baseClassName Name of base class, must not be null, typically * @param defaultExceptionClassName */ public CppHeaderGenerator( File srcFile, File file, String className, String baseClassName, String defaultExceptionClassName) { super(srcFile, file, className, baseClassName, defaultExceptionClassName, null); } public void generateModule( ResourceGen generator, ResourceDef.ResourceBundle resourceList, PrintWriter pw) { generateDoNotModifyHeader(pw); generateGeneratedByBlock(pw); StringBuffer ifndef = new StringBuffer(); String fileName = getFile().getName(); ifndef.append(fileName.substring(0, fileName.length() - 2)); ifndef.append("_Included"); if (resourceList.cppNamespace != null) { ifndef.insert(0, '_'); ifndef.insert(0, resourceList.cppNamespace.substring(1)); ifndef.insert(0, Character.toUpperCase(resourceList .cppNamespace .charAt(0))); } pw.println("#ifndef " + ifndef.toString()); pw.println("#define " + ifndef.toString()); pw.println(); pw.println("#include "); pw.println("#include "); pw.println(); pw.println("#include \"Locale.h\""); pw.println("#include \"ResourceDefinition.h\""); pw.println("#include \"ResourceBundle.h\""); pw.println(); pw.println("// begin includes specified by " + getSrcFileForComment()); if (resourceList.cppExceptionClassLocation != null) { pw.println("#include \"" + resourceList.cppExceptionClassLocation + "\""); } for(int i = 0; i < resourceList.resources.length; i++) { ResourceDef.Resource resource = resourceList.resources[i]; if (resource instanceof ResourceDef.Exception) { ResourceDef.Exception exception = (ResourceDef.Exception)resource; if (exception.cppClassLocation != null) { pw.println("#include \"" + exception.cppClassLocation + "\""); } } } pw.println("// end includes specified by " + getSrcFileForComment()); pw.println(); if (resourceList.cppNamespace != null) { pw.println("namespace " + resourceList.cppNamespace + " {"); pw.println(); } pw.println(); String baseClass = getBaseClassName(); String className = getClassName(); String bundleCacheClassName = className + "BundleCache"; pw.println("class " + className + ";"); pw.println("typedef map " + bundleCacheClassName + ";"); pw.println(); pw.println("class " + className + " : " + baseClass); pw.println("{"); pw.println(" protected:"); pw.println(" explicit " + className + "(Locale locale);"); pw.println(); pw.println(" public:"); pw.println(" virtual ~" + className + "() { }"); pw.println(); pw.println(" static const " + className + " &instance();"); pw.println(" static const " + className + " &instance(const Locale &locale);"); pw.println(); pw.println(" static void setResourceFileLocation(const std::string &location);"); pw.println(); for(int i = 0; i < resourceList.resources.length; i++) { ResourceDef.Resource resource = resourceList.resources[i]; String text = resource.text.cdata; String comment = ResourceGen.getComment(resource); String parameterList = getParameterList(text); // e.g. "Internal" final String resourceInitCap = ResourceGen.getResourceInitcap(resource); Util.generateCommentBlock(pw, resource.name, text, comment); pw.println(" std::string " + resource.name + "(" + parameterList + ") const;"); if (resource instanceof ResourceDef.Exception) { ResourceDef.Exception exception = (ResourceDef.Exception)resource; String exceptionClass = exception.cppClassName; if (exceptionClass == null) { exceptionClass = resourceList.cppExceptionClassName; } pw.println(" " + exceptionClass + "* new" + resourceInitCap + "(" + parameterList + ") const;"); boolean chainExceptions = (exception.cppChainExceptions != null && exception.cppChainExceptions.equalsIgnoreCase("true")); if (chainExceptions) { if (parameterList.length() > 0) { pw.println(" " + exceptionClass + "* new" + resourceInitCap + "(" + parameterList + ", const " + exceptionClass + " * const prev) const;"); } else { pw.println(" " + exceptionClass + " new" + resourceInitCap + "(" + "const " + exceptionClass + " * const prev) const;"); } } } pw.println(); } pw.println(" private:"); for(int i = 0; i < resourceList.resources.length; i++) { ResourceDef.Resource resource = resourceList.resources[i]; pw.println(" ResourceDefinition _" + resource.name + ";"); } pw.println(); pw.println(" template"); pw.println(" friend _GRB *makeInstance(_BC &bundleCache, const Locale &locale);"); pw.println("};"); if (resourceList.cppNamespace != null) { pw.println(); pw.println("} // end namespace " + resourceList.cppNamespace); } pw.println(); pw.println("#endif // " + ifndef.toString()); } } // End CppHeaderGenerator.java resgen/src/org/eigenbase/resgen/ResourceGenTask.java0000444000175000017500000003321711543216467022744 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/ResourceGenTask.java#7 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2002-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, Oct 8, 2002 */ package org.eigenbase.resgen; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import java.io.File; import java.io.IOException; import java.util.ArrayList; /** * A ResourceGenTask is an ANT task to invoke the Eigenbase * Resource Generator. * *

Example:

* *
<resgen srcdir="source" locales="en_US">
 *    <include name="happy/BirthdayResource.xml"/>
 *</resgen>
* *
generates
* *
source/happy/BirthdayResource.properties
 *source/happy/BirthdayResource_en_US.properties
 *source/happy/BirthdayResource.java
 *source/happy/BirthdayResource_en_US.java
* *
* *

C++ Example:

* *
<resgen mode="c++" srcdir="source" locales="en_US">
 *    <include name="happy/BirthdayResource.xml"/>
 *</resgen>
* *
generates
* *
source/happy/BirthdayResource.resources
 *source/happy/BirthdayResource_en_US.resources
 *source/happy/BirthdayResource.h
 *source/happy/BirthdayResource.cpp
* *

Files are not generated if there is an existing newer one.

* *

The output path is determined by 'destdir' (or 'resdir' for .properties * files) and the package-name (derived from the XML file's path relative to * 'srcdir'). Since the Java runtime environment searches for resource bundles * on the classpath, it is typical to set srcdir="src", destdir="src", * resdir="classes".

* *

Element <resourceGen>

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
modeGeneration mode. Acceptable values are "java", "c++" or "all". * The default is "java".No
srcdirSource directory. The paths of resource files, and hence the * package names of generated Java classes, are relative to this * directory.Yes
destdirDestination directory. Output .java files are generated relative to this * directory. If not specified, has the same value as * srcdir.No
resdirResource directory. Output .properties files are generated relative to * this directory. If not specified, has the same value as * destdir.No
localesComma-separated list of locales to generate files for. * If not specified, uses the locale of the resource file.No
styleCode-generation style. Values are "dynamic" or "functor". * Default is "dynamic": generate several non-static methods for each * resource. * In the "functor" style, there is one member per resource, which has * several methods.No
forceWhether to generate files even if they do not appear to be out of * date. Default is false.No
commentstyleGenerated comment style. Values are "normal" and "scm-safe". The * default is "normal": generates comments that indicate the source file's * original path and states that the file should not be checked into source * control systems. The "scm-safe" comment style modifies the comments * to make storage of the output files in an SCM more palatable. It omits * the source file's path and states that the file was generated and should * not be edited manually.No
* * Nested element: <{@link Include include}>. * * @author jhyde * @since Oct 8, 2002 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/ResourceGenTask.java#7 $ **/ public class ResourceGenTask extends Task { private ArrayList resources = new ArrayList(); int mode = MODE_JAVA; File src; File dest; File res; int style = STYLE_DYNAMIC; String locales; boolean force; int commentStyle = COMMENT_STYLE_NORMAL; private static final int MODE_UNKNOWN = -1; private static final int MODE_JAVA = 1; private static final int MODE_CPP = 2; private static final int MODE_ALL = 3; public static final int STYLE_DYNAMIC = 1; public static final int STYLE_FUNCTOR = 2; public static final int COMMENT_STYLE_NORMAL = 1; public static final int COMMENT_STYLE_SCM_SAFE = 2; public ResourceGenTask() { } public void execute() throws BuildException { validate(); try { new ResourceGen().run(this); } catch (IOException e) { throw new BuildException(e); } } /** Called by ANT. **/ public void addInclude(Include resourceArgs) { resources.add(resourceArgs); resourceArgs.root = this; } void validate() { if (mode != MODE_JAVA && mode != MODE_CPP && mode != MODE_ALL) { throw new BuildException("You must specify a value mode: java, c++, or all"); } if (src == null) { throw new BuildException("You must specify 'srcdir'"); } if (dest == null) { dest = src; } if (res == null) { res = dest; } final Include[] args = getIncludes(); for (int i = 0; i < args.length; i++) { args[i].validate(); } } Include[] getIncludes() { return (Include[]) resources.toArray(new Include[0]); } /** Sets mode. **/ public void setMode(String mode) throws BuildException { if ("java".equals(mode)) { this.mode = MODE_JAVA; } else if ("c++".equals(mode)) { this.mode = MODE_CPP; } else if ("all".equals(mode)) { this.mode = MODE_ALL; } else { this.mode = MODE_UNKNOWN; } } /** Sets srcdir. **/ public void setSrcdir(File srcDir) { this.src = srcDir; } /** Returns srcdir. **/ public File getSrcdir() { return src; } /** Sets destdir. **/ public void setDestdir(File destDir) { this.dest = destDir; } /** Returns destdir. **/ public File getDestdir() { return dest; } /** Sets resdir. **/ public void setResdir(File resDir) { this.res = resDir; } /** Sets style. */ public void setStyle(String style) throws BuildException { if (style.equals("dynamic")) { this.style = STYLE_DYNAMIC; } else if (style.equals("functor")) { this.style = STYLE_FUNCTOR; } else { throw new BuildException("Invalid style '" + style + "'"); } } /** Sets locales. **/ public void setLocales(String locales) throws BuildException { this.locales = locales; } /** Sets force. **/ public void setForce(boolean force) { this.force = force; } /** Sets commentstyle. */ public void setCommentStyle(String commentStyle) throws BuildException { if (commentStyle.equals("normal")) { this.commentStyle = COMMENT_STYLE_NORMAL; } else if (commentStyle.equals("scm-safe")) { this.commentStyle = COMMENT_STYLE_SCM_SAFE; } else { throw new BuildException( "Invalid commentstyle '" + commentStyle + "'"); } } /** * Include implements <include> element nested * within a <resgen> task (see {@link ResourceGenTask}). * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
nameThe name, relative to srcdir, of the XML file * which defines the resources.Yes
classNameThe name of the class to be generated, including the package, but * not including any locale suffix. By default, the class name is * derived from the name of the source file, for example * happy/BirthdayResource_en_US.xml becomes class * happy.BirthdayResource.No
cppClassNameThe name of the C++ class to be generated. By default, the class * name is derived from the name of the source file, for example * happy/BirthdayResource_en_US.xml becomes class * happy.BirthdayResource.No
baseClassNameThe fully-qualified name of the base class of the resource bundle. * Defaults to "org.eigenbase.resgen.ShadowResourceBundle".No
cppBaseClassNameThe fully-qualified name of the base class of the resource bundle * for C++. Defaults to "ResourceBundle".No
*/ public static class Include { public Include() { } ResourceGenTask root; /** Name of source file, relative to 'srcdir'. **/ String fileName; /** Class name. **/ String className; /** Base class. */ String baseClassName; /** C++ Class name. **/ String cppClassName; /** C++ Base class. */ String cppBaseClassName; void validate() throws BuildException { if (fileName == null) { throw new BuildException("You must specify attribute 'name'"); } } void process(ResourceGen generator) throws BuildException { boolean outputJava = (root.mode != ResourceGenTask.MODE_CPP); boolean outputCpp = (root.mode != ResourceGenTask.MODE_JAVA); FileTask task; if (fileName.endsWith(".xml")) { task = generator.createXmlTask(this, fileName, className, baseClassName, outputJava, cppClassName, cppBaseClassName, outputCpp); } else if (fileName.endsWith(".properties")) { task = generator.createPropertiesTask(this, fileName); } else { throw new BuildException( "File '" + fileName + "' is not of a supported " + "type (.java or .properties)"); } try { task.process(generator); } catch (IOException e) { e.printStackTrace(); throw new BuildException( "Failed while processing '" + fileName + "'", e); } } /** Sets name. **/ public void setName(String name) { this.fileName = name; } /** Sets className. **/ public void setClassName(String className) { this.className = className; } /** Sets baseClassName. **/ public void setBaseClassName(String baseClassName) { this.baseClassName = baseClassName; } String getBaseClassName() { return baseClassName; } /** Sets cppClassName. **/ public void setCppClassName(String className) { this.cppClassName = className; } /** Sets cppBaseClassName. **/ public void setCppBaseClassName(String baseClassName) { this.cppBaseClassName = baseClassName; } String getCppBaseClassName() { return cppBaseClassName; } } } // End ResourceGenTask.java resgen/src/org/eigenbase/resgen/XmlFileTask.java0000444000175000017500000003540111543216467022060 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/XmlFileTask.java#12 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2008 The Eigenbase Project // Copyright (C) 2005-2008 Disruptive Tech // Copyright (C) 2005-2008 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import org.apache.tools.ant.BuildException; import java.io.*; import java.net.URL; import java.util.*; /** * Ant task which processes an XML file and generates a C++ or Java class from * the resources in it. * * @author jhyde * @since 19 September, 2005 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/XmlFileTask.java#12 $ */ class XmlFileTask extends FileTask { final String baseClassName; final String cppBaseClassName; XmlFileTask(ResourceGenTask.Include include, String fileName, String className, String baseClassName, boolean outputJava, String cppClassName, String cppBaseClassName, boolean outputCpp) { this.include = include; this.fileName = fileName; this.outputJava = outputJava; if (className == null) { className = Util.fileNameToClassName(fileName, ".xml"); } this.className = className; if (baseClassName == null) { baseClassName = "org.eigenbase.resgen.ShadowResourceBundle"; } this.baseClassName = baseClassName; this.outputCpp = outputCpp; if (cppClassName == null) { cppClassName = Util.fileNameToCppClassName(fileName, ".xml"); } this.cppClassName = cppClassName; if (cppBaseClassName == null) { cppBaseClassName = "ResourceBundle"; } this.cppBaseClassName = cppBaseClassName; } void process(ResourceGen generator) throws IOException { URL url = Util.convertPathToURL(getFile()); ResourceDef.ResourceBundle resourceList = Util.load(url); if (resourceList.locale == null) { throw new BuildException( "Resource file " + url + " must have locale"); } ArrayList localeNames = new ArrayList(); if (include.root.locales == null) { localeNames.add(resourceList.locale); } else { StringTokenizer tokenizer = new StringTokenizer(include.root.locales,","); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); localeNames.add(token); } } if (!localeNames.contains(resourceList.locale)) { throw new BuildException( "Resource file " + url + " has locale '" + resourceList.locale + "' which is not in the 'locales' list"); } Locale[] locales = new Locale[localeNames.size()]; for (int i = 0; i < locales.length; i++) { String localeName = (String) localeNames.get(i); locales[i] = Util.parseLocale(localeName); if (locales[i] == null) { throw new BuildException( "Invalid locale " + localeName); } } if (outputJava) { generateJava(generator, resourceList, null); } generateProperties(generator, resourceList, null); for (int i = 0; i < locales.length; i++) { Locale locale = locales[i]; if (outputJava) { generateJava(generator, resourceList, locale); } generateProperties(generator, resourceList, locale); } if (outputCpp) { generateCpp(generator, resourceList); } } private void generateProperties( ResourceGen generator, ResourceDef.ResourceBundle resourceList, Locale locale) { String fileName = Util.getClassNameSansPackage(className, locale) + ".properties"; File file = new File(getResourceDirectory(), fileName); File srcFile = locale == null ? getFile() : new File(getSrcDirectory(), fileName); if (file.exists()) { if (locale != null) { if (file.equals(srcFile)) { // The locale.properties file already exists, and the // source and target locale.properties files are the // same. No need to create it, or even to issue a warning. // We were only going to create an empty file, anyway. return; } } if (file.lastModified() >= srcFile.lastModified()) { generator.comment(file + " is up to date"); return; } if (!file.canWrite()) { generator.comment(file + " is read-only"); return; } } generator.comment("Generating " + file); final FileOutputStream out; try { if (file.getParentFile() != null) { file.getParentFile().mkdirs(); } out = new FileOutputStream(file); } catch (FileNotFoundException e) { throw new BuildException("Error while writing " + file, e); } PrintWriter pw = new PrintWriter(out); try { if (locale == null) { generateBaseProperties(resourceList, pw); } else { generateProperties(pw, file, srcFile, locale); } } finally { pw.close(); } } /** * Generates a properties file containing a line for each resource. */ private void generateBaseProperties( ResourceDef.ResourceBundle resourceList, PrintWriter pw) { String fullClassName = getClassName(null); pw.println("# This file contains the resources for"); pw.println("# class '" + fullClassName + "'; the base locale is '" + resourceList.locale + "'."); pw.println("# It was generated by " + ResourceGen.class); pw.println("# from " + getFileForComments()); if (include.root.commentStyle != ResourceGenTask.COMMENT_STYLE_SCM_SAFE) { pw.println("# on " + new Date().toString() + "."); } pw.println(); for (int i = 0; i < resourceList.resources.length; i++) { ResourceDef.Resource resource = resourceList.resources[i]; final String name = resource.name; if (resource.text == null) { throw new BuildException( "Resource '" + name + "' has no message"); } final String message = resource.text.cdata; if (message == null) { continue; } if (count(resource.text.cdata, '\'') % 2 != 0) { System.out.println( "WARNING: The message for resource '" + resource.name + "' has an odd number of single-quotes. These should" + " probably be doubled (to include an single-quote in" + " a message) or closed (to include a literal string" + " in a message)."); } pw.println(name + "=" + Util.quoteForProperties(message)); } pw.println("# End " + fullClassName + ".properties"); } /** * Returns the number of occurrences of a given character in a string. * *

For example, {@code count("foobar", 'o')} returns 2. * * @param s String * @param c Character * @return Number of occurrences */ private int count(String s, char c) { int count = 0; for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == c) { ++count; } } return count; } /** * Generates a properties file for a given locale. If there is a source * file for the locale, it is copied. Otherwise generates a file with * headers but no resources. * * @param pw Output file writer * @param targetFile the locale-specific output file * @param srcFile The locale-specific properties file, e.g. * "source/happy/BirthdayResource_fr-FR.properties". It may not exist, * but if it does, we copy it. * @param locale Locale, never null * @pre locale != null */ private void generateProperties( PrintWriter pw, File targetFile, File srcFile, Locale locale) { if (srcFile.exists() && srcFile.canRead() && !targetFile.equals(srcFile)) { try { final FileReader reader = new FileReader(srcFile); final char[] cbuf = new char[1000]; int charsRead; while ((charsRead = reader.read(cbuf)) > 0) { pw.write(cbuf, 0, charsRead); } return; } catch (IOException e) { throw new BuildException("Error while copying from '" + srcFile + "'"); } } // Generate an empty file. String fullClassName = getClassName(locale); pw.println("# This file contains the resources for"); pw.println("# class '" + fullClassName + "' and locale '" + locale + "'."); pw.println("# It was generated by " + ResourceGen.class); pw.println("# from " + getFileForComments()); if (include.root.commentStyle != ResourceGenTask.COMMENT_STYLE_SCM_SAFE) { pw.println("# on " + new Date().toString() + "."); } pw.println(); pw.println("# This file is intentionally blank. Add property values"); pw.println("# to this file to override the translations in the base"); String basePropertiesFileName = Util.getClassNameSansPackage(className, locale) + ".properties"; pw.println("# properties file, " + basePropertiesFileName); pw.println(); pw.println("# End " + fullClassName + ".properties"); } private String getClassName(Locale locale) { String s = className; if (locale != null) { s += '_' + locale.toString(); } return s; } protected void generateCpp( ResourceGen generator, ResourceDef.ResourceBundle resourceList) { String defaultExceptionClass = resourceList.cppExceptionClassName; String defaultExceptionLocation = resourceList.cppExceptionClassLocation; if (defaultExceptionClass != null && defaultExceptionLocation == null) { throw new BuildException( "C++ exception class is defined without a header file location in " + getFile()); } for (int i = 0; i < resourceList.resources.length; i++) { ResourceDef.Resource resource = resourceList.resources[i]; if (resource.text == null) { throw new BuildException( "Resource '" + resource.name + "' has no message"); } if (resource instanceof ResourceDef.Exception) { ResourceDef.Exception exception = (ResourceDef.Exception)resource; if (exception.cppClassName != null && (exception.cppClassLocation == null && defaultExceptionLocation == null)) { throw new BuildException( "C++ exception class specified for " + exception.name + " without specifiying a header location in " + getFile()); } if (defaultExceptionClass == null && exception.cppClassName == null) { throw new BuildException( "No exception class specified for " + exception.name + " in " + getFile()); } } } String hFilename = cppClassName + ".h"; String cppFileName = cppClassName + ".cpp"; File hFile = new File(include.root.dest, hFilename); File cppFile = new File(include.root.dest, cppFileName); boolean allUpToDate = true; if (!checkUpToDate(generator, hFile)) { allUpToDate = false; } if (!checkUpToDate(generator, cppFile)) { allUpToDate = false; } if (allUpToDate && !include.root.force) { return; } generator.comment("Generating " + hFile); final FileOutputStream hOut; try { makeParentDirs(hFile); hOut = new FileOutputStream(hFile); } catch (FileNotFoundException e) { throw new BuildException("Error while writing " + hFile, e); } String className = Util.removePackage(this.className); String baseClassName = Util.removePackage(this.cppBaseClassName); PrintWriter pw = new PrintWriter(hOut); try { final CppHeaderGenerator gen = new CppHeaderGenerator(getFile(), hFile, className, baseClassName, defaultExceptionClass); configureCommentStyle(gen); gen.generateModule(generator, resourceList, pw); } finally { pw.close(); } generator.comment("Generating " + cppFile); final FileOutputStream cppOut; try { makeParentDirs(cppFile); cppOut = new FileOutputStream(cppFile); } catch (FileNotFoundException e) { throw new BuildException("Error while writing " + cppFile, e); } pw = new PrintWriter(cppOut); try { final CppGenerator gen = new CppGenerator(getFile(), cppFile, className, baseClassName, defaultExceptionClass, hFilename); configureCommentStyle(gen); gen.generateModule(generator, resourceList, pw); } finally { pw.close(); } } } // End XmlFileTask.java resgen/src/org/eigenbase/resgen/ShadowResourceBundle.java0000444000175000017500000002425311543216467023767 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/ShadowResourceBundle.java#5 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2002-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 19 September, 2002 */ package org.eigenbase.resgen; import java.io.IOException; import java.io.InputStream; import java.util.*; /** * ShadowResourceBundle is an abstract base class for * {@link ResourceBundle} classes which are backed by a properties file. When * the class is created, it loads a properties file with the same name as the * class. * *

In the standard scheme (see {@link ResourceBundle}), * if you call {@link ResourceBundle#getBundle}("foo.MyResource"), * it first looks for a class called foo.MyResource, then * looks for a file called foo/MyResource.properties. If it finds * the file, it creates a {@link PropertyResourceBundle} and loads the class. * The problem is if you want to load the .properties file * into a dedicated class; ShadowResourceBundle helps with this * case. * *

You should create a class as follows:

* *
package foo;
 *class MyResource extends org.eigenbase.resgen.ShadowResourceBundle {
 *    public MyResource() throws java.io.IOException {
 *    }
 *}
* *
Then when you call * {@link ResourceBundle#getBundle ResourceBundle.getBundle("foo.MyResource")}, * it will find the class before the properties file, but still automatically * load the properties file based upon the name of the class. */ public abstract class ShadowResourceBundle extends ResourceBundle { private PropertyResourceBundle bundle; private static final ThreadLocal mapThreadToLocale = new ThreadLocal(); protected static final Object[] emptyObjectArray = new Object[0]; /** * Creates a ShadowResourceBundle, and reads resources from * a .properties file with the same name as the current class. * For example, if the class is called foo.MyResource_en_US, * reads from foo/MyResource_en_US.properties, then * foo/MyResource_en.properties, then * foo/MyResource.properties. */ protected ShadowResourceBundle() throws IOException { super(); Class clazz = getClass(); InputStream stream = openPropertiesFile(clazz); if (stream == null) { throw new IOException("could not open properties file for " + getClass()); } MyPropertyResourceBundle previousBundle = new MyPropertyResourceBundle(stream); bundle = previousBundle; stream.close(); // Now load properties files for parent locales, which we deduce from // the names of our super-class, and its super-class. while (true) { clazz = clazz.getSuperclass(); if (clazz == null || clazz == ShadowResourceBundle.class || !ResourceBundle.class.isAssignableFrom(clazz)) { break; } stream = openPropertiesFile(clazz); if (stream == null) { continue; } MyPropertyResourceBundle newBundle = new MyPropertyResourceBundle(stream); stream.close(); if (previousBundle != null) { previousBundle.setParentTrojan(newBundle); } else { bundle = newBundle; } previousBundle = newBundle; } } static class MyPropertyResourceBundle extends PropertyResourceBundle { public MyPropertyResourceBundle(InputStream stream) throws IOException { super(stream); } void setParentTrojan(ResourceBundle parent) { super.setParent(parent); } } /** * Opens the properties file corresponding to a given class. The code is * copied from {@link ResourceBundle}. */ private static InputStream openPropertiesFile(Class clazz) { final ClassLoader loader = clazz.getClassLoader(); final String resName = clazz.getName().replace('.', '/') + ".properties"; return (InputStream)java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Object run() { if (loader != null) { return loader.getResourceAsStream(resName); } else { return ClassLoader.getSystemResourceAsStream(resName); } } } ); } public Enumeration getKeys() { return bundle.getKeys(); } protected Object handleGetObject(String key) throws MissingResourceException { return bundle.getObject(key); } /** * Returns the instance of the baseName resource bundle for * the current thread's locale. For example, if called with * "mondrian.olap.MondrianResource", from a thread which has called {@link * #setThreadLocale}({@link Locale#FRENCH}), will get an instance of * "mondrian.olap.MondrianResource_FR" from the cache. * *

This method should be called from a derived class, with the proper * casting:

* *
class MyResource extends ShadowResourceBundle {
     *    ...
     *    /**
     *      * Retrieves the instance of {@link MyResource} appropriate
     *      * to the current locale. If this thread has specified a locale
     *      * by calling {@link #setThreadLocale}, this locale is used,
     *      * otherwise the default locale is used.
     *      **/
     *    public static MyResource instance() {
     *       return (MyResource) instance(MyResource.class.getName());
     *    }
     *    ...
     * }
* * @deprecated This method does not work correctly in dynamically * loaded jars. */ protected static ResourceBundle instance(String baseName) { return instance(baseName, getThreadLocale()); } /** * Returns the instance of the baseName resource bundle * for the given locale. * *

This method should be called from a derived class, with the proper * casting:

* *
class MyResource extends ShadowResourceBundle {
     *    ...
     *
     *    /**
     *      * Retrieves the instance of {@link MyResource} appropriate
     *      * to the given locale.
     *      **/
     *    public static MyResource instance(Locale locale) {
     *       return (MyResource) instance(MyResource.class.getName(), locale);
     *    }
     *    ...
     * }
* * @deprecated This method does not work correctly in dynamically * loaded jars. */ protected static ShadowResourceBundle instance( String baseName, Locale locale) { if (locale == null) { locale = Locale.getDefault(); } ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale); return instance(baseName, locale, bundle); } /** * Returns the instance of the baseName resource bundle * for the given locale. * *

This method should be called from a derived class, with the proper * casting:

* *
class MyResource extends ShadowResourceBundle {
     *    ...
     *
     *    /**
     *      * Retrieves the instance of {@link MyResource} appropriate
     *      * to the given locale.
     *      **/
     *    public static MyResource instance(Locale locale) {
     *       return (MyResource) instance(
     *           MyResource.class.getName(), locale,
     *           ResourceBundle.getBundle(MyResource.class.getName(), locale));
     *    }
     *    ...
     * }
*/ protected static ShadowResourceBundle instance( String baseName, Locale locale, ResourceBundle bundle) { if (bundle instanceof PropertyResourceBundle) { throw new ClassCastException( "ShadowResourceBundle.instance('" + baseName + "','" + locale + "') found " + baseName + "_" + locale + ".properties but not " + baseName + "_" + locale + ".class"); } return (ShadowResourceBundle) bundle; } /** Returns the preferred locale of the current thread, or * the default locale if the current thread has not called {@link * #setThreadLocale}. **/ protected static Locale getThreadOrDefaultLocale() { Locale locale = getThreadLocale(); if (locale == null) { return Locale.getDefault(); } else { return locale; } } /** Sets the locale for the current thread. Used by {@link * #instance(String,Locale)}. **/ public static void setThreadLocale(Locale locale) { mapThreadToLocale.set(locale); } /** Returns the preferred locale of the current thread, or null if the * thread has not called {@link #setThreadLocale}. **/ public static Locale getThreadLocale() { return (Locale) mapThreadToLocale.get(); } } // End ShadowResourceBundle.java resgen/src/org/eigenbase/resgen/CppGenerator.java0000444000175000017500000002205211543216467022264 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/CppGenerator.java#3 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import java.io.File; import java.io.PrintWriter; /** * Generates a C++ class containing resource definitions. * * @author jhyde * @since 19 September, 2005 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/CppGenerator.java#3 $ */ class CppGenerator extends AbstractGenerator { private final String className; private final String defaultExceptionClassName; private final String headerFilename; private final String baseClassName; private static final String CPP_STRING = "const std::string &"; private static final String CPP_NUMBER = "int"; private static final String CPP_DATE_TIME = "time_t"; private static final String[] CPP_TYPE_NAMES = {CPP_STRING, CPP_NUMBER, CPP_DATE_TIME, CPP_DATE_TIME}; /** * Creates a C++ header generator. * * @param srcFile * @param file * @param className * @param baseClassName Name of base class, must not be null, typically * @param defaultExceptionClassName */ CppGenerator( File srcFile, File file, String className, String baseClassName, String defaultExceptionClassName, String headerFilename) { super(srcFile, file); assert className.indexOf('.') < 0 : "C++ class name must not contain '.': " + className; this.className = className; this.defaultExceptionClassName = defaultExceptionClassName; this.headerFilename = headerFilename; assert baseClassName != null; this.baseClassName = baseClassName; } protected String getClassName() { return className; } protected String getBaseClassName() { return baseClassName; } protected String[] getArgTypes(String message) { return ResourceDefinition.getArgTypes(message, CPP_TYPE_NAMES); } public void generateModule(ResourceGen generator, ResourceDef.ResourceBundle resourceList, PrintWriter pw) { generateDoNotModifyHeader(pw); generateGeneratedByBlock(pw); String className = getClassName(); String bundleCacheClassName = className + "BundleCache"; String baseClass = getBaseClassName(); if (resourceList.cppCommonInclude != null) { pw.println( "// begin common include specified by " + getSrcFileForComment()); pw.println("#include \"" + resourceList.cppCommonInclude + "\""); pw.println( "// end common include specified by " + getSrcFileForComment()); } pw.println("#include \"" + headerFilename + "\""); pw.println("#include \"ResourceBundle.h\""); pw.println("#include \"Locale.h\""); pw.println(); pw.println("#include "); pw.println("#include "); pw.println(); if (resourceList.cppNamespace != null) { pw.println("namespace " + resourceList.cppNamespace + " {"); pw.println(); } pw.println("using namespace std;"); pw.println(); pw.println("#define BASENAME (\"" + className + "\")"); pw.println(); pw.println("static " + bundleCacheClassName + " bundleCache;"); pw.println("static string bundleLocation(\"\");"); pw.println(); pw.println("const " + className + " &" + className + "::instance()"); pw.println("{"); pw.println(" return " + className + "::instance(Locale::getDefault());"); pw.println("}"); pw.println(); pw.println("const " + className + " &" + className + "::instance(const Locale &locale)"); pw.println("{"); pw.println(" return *makeInstance<" + className + ", " + bundleCacheClassName + ", " + bundleCacheClassName + "::iterator>(bundleCache, locale);"); pw.println("}"); pw.println(); pw.println("void " + className + "::setResourceFileLocation(const string &location)"); pw.println("{"); pw.println(" bundleLocation = location;"); pw.println("}"); pw.println(); pw.println("" + className + "::" + className + "(Locale locale)"); pw.println(" : " + baseClass + "(BASENAME, locale, bundleLocation),"); for(int i = 0; i < resourceList.resources.length; i++) { ResourceDef.Resource resource = resourceList.resources[i]; pw.print(" _" + resource.name + "(this, \"" + resource.name + "\")"); if (i + 1 < resourceList.resources.length) { pw.println(','); } else { pw.println(); } } pw.println("{ }"); pw.println(); for (int i = 0; i < resourceList.resources.length; i++) { generateResource(resourceList.resources[i], pw); } if (resourceList.cppNamespace != null) { pw.println(); pw.println("} // end namespace " + resourceList.cppNamespace); } } public void generateResource( ResourceDef.Resource resource, PrintWriter pw) { String text = resource.text.cdata; //String comment = ResourceGen.getComment(resource); // e.g. "Internal" final String resourceInitCap = ResourceGen.getResourceInitcap(resource); String parameterList = getParameterList(text); String argumentList = getArgumentList(text); pw.println("string " + className + "::" + resource.name + "(" + parameterList + ") const"); pw.println("{"); pw.println(" return _" + resource.name + ".format(" + argumentList + ");"); pw.println("}"); if (resource instanceof ResourceDef.Exception) { ResourceDef.Exception exception = (ResourceDef.Exception)resource; String exceptionClass = exception.cppClassName; if (exceptionClass == null) { exceptionClass = defaultExceptionClassName; } pw.println(exceptionClass + "* " + className + "::new" + resourceInitCap + "(" + parameterList + ") const"); pw.println("{"); pw.println(" return new " + exceptionClass + "(" + resource.name + "(" + argumentList + "));"); pw.println("}"); pw.println(); boolean chainExceptions = (exception.cppChainExceptions != null && exception.cppChainExceptions.equalsIgnoreCase("true")); if (chainExceptions) { if (parameterList.length() > 0) { pw.println(exceptionClass + "* " + className + "::new" + resourceInitCap + "(" + parameterList + ", const " + exceptionClass + " * const prev) const"); } else { pw.println(exceptionClass + " " + className + "::new" + resourceInitCap + "(const " + exceptionClass + " * const prev) const"); } pw.println("{"); pw.println(" return new " + exceptionClass + "(" + resource.name + "(" + argumentList + "), prev);"); pw.println("}"); pw.println(); } } } } // End CppGenerator.java resgen/src/org/eigenbase/resgen/ResourceDefinition.java0000444000175000017500000002445511543216467023504 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/ResourceDefinition.java#4 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2002-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 19 September, 2002 */ package org.eigenbase.resgen; import java.text.MessageFormat; import java.text.Format; import java.text.NumberFormat; import java.text.DateFormat; import java.util.ResourceBundle; import java.util.Properties; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; /** * Definition of a resource such as a parameterized message or exception. * *

A resource is identified within a {@link ResourceBundle} by a text * key, and has a message in its base locale (which is * usually US-English (en_US)). It may also have a set of properties, which are * represented as name-value pairs. * *

A resource definition is immutable. * * @author jhyde * @since 19 September, 2005 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/ResourceDefinition.java#4 $ */ public class ResourceDefinition { public final String key; public final String baseMessage; private final String[] props; private static final String[] EmptyStringArray = new String[0]; public static final int TYPE_UNKNOWN = -1; public static final int TYPE_STRING = 0; public static final int TYPE_NUMBER = 1; public static final int TYPE_DATE = 2; public static final int TYPE_TIME = 3; private static final String[] TypeNames = {"string", "number", "date", "time"}; /** * Creates a resource definition with no properties. * * @param key Unique name for this resource definition. * @param baseMessage Message for this resource definition in the base * locale. */ public ResourceDefinition(String key, String baseMessage) { this(key, baseMessage, null); } /** * Creates a resource definition. * * @param key Unique name for this resource definition. * @param baseMessage Message for this resource definition in the base * locale. * @param props Array of property name/value pairs. * null means the same as an empty array. */ public ResourceDefinition(String key, String baseMessage, String[] props) { this.key = key; this.baseMessage = baseMessage; if (props == null) { props = EmptyStringArray; } assert props.length % 2 == 0 : "Must have even number of property names/values"; this.props = props; } /** * Returns this resource definition's key. */ public String getKey() { return key; } /** * Returns this resource definition's message in the base locale. * (To find the message in another locale, you will need to load a * resource bundle for that locale.) */ public String getBaseMessage() { return baseMessage; } /** * Returns the properties of this resource definition. */ public Properties getProperties() { final Properties properties = new Properties(); for (int i = 0; i < props.length; i++) { String prop = props[i]; String value = props[++i]; properties.setProperty(prop, value); } return properties; } /** * Returns the types of arguments. */ public String[] getArgTypes() { return getArgTypes(baseMessage, TypeNames); } /** * Creates an instance of this definition with a set of parameters. * This is a factory method, which may be overridden by a derived class. * * @param bundle Resource bundle the resource instance will belong to * (This contains the locale, among other things.) * @param args Arguments to populate the message's parameters. * The arguments must be consistent in number and type with the results * of {@link #getArgTypes}. */ public ResourceInstance instantiate(ResourceBundle bundle, Object[] args) { return new Instance(bundle, this, args); } /** * Parses a message for the arguments inside it, and * returns an array with the types of those arguments. * *

For example, getArgTypes("I bought {0,number} {2}s", * new String[] {"string", "number", "date", "time"}) * yields {"number", null, "string"}. * Note the null corresponding to missing message #1. * * @param message Message to be parsed. * @param typeNames Strings to return for types. * @return Array of type names */ protected static String[] getArgTypes(String message, String[] typeNames) { assert typeNames.length == 4; Format[] argFormats; try { // We'd like to do // argFormats = format.getFormatsByArgumentIndex() // but it doesn't exist until JDK 1.4, and we'd like this code // to work earlier. Method method = MessageFormat.class.getMethod( "getFormatsByArgumentIndex", (Class[]) null); try { MessageFormat format = new MessageFormat(message); argFormats = (Format[]) method.invoke(format, (Object[]) null); String[] argTypes = new String[argFormats.length]; for (int i = 0; i < argFormats.length; i++) { int x = formatToType(argFormats[i]); argTypes[i] = typeNames[x]; } return argTypes; } catch (IllegalAccessException e) { throw new RuntimeException(e.toString()); } catch (IllegalArgumentException e) { throw new RuntimeException(e.toString()); } catch (InvocationTargetException e) { throw new RuntimeException(e.toString()); } } catch (NoSuchMethodException e) { // Fallback pre JDK 1.4 return getArgTypesByHand(message, typeNames); } catch (SecurityException e) { throw new RuntimeException(e.toString()); } } protected static String [] getArgTypesByHand( String message, String[] typeNames) { assert typeNames.length == 4; String[] argTypes = new String[10]; int length = 0; for (int i = 0; i < 10; i++) { final int type = getArgType(i, message); if (type != TYPE_UNKNOWN) { length = i + 1; argTypes[i] = typeNames[type]; } } // Created a truncated copy (but keep intervening nulls). String[] argTypes2 = new String[length]; System.arraycopy(argTypes, 0, argTypes2, 0, length); return argTypes2; } /** * Returns the type of the ith argument inside a message, * or {@link #TYPE_UNKNOWN} if not found. * * @param i Ordinal of argument * @param message Message to parse * @return Type code ({@link #TYPE_STRING} etc.) */ protected static int getArgType(int i, String message) { String arg = "{" + Integer.toString(i); // e.g. "{1" int index = message.lastIndexOf(arg); if (index < 0) { return TYPE_UNKNOWN; } index += arg.length(); int end = message.length(); while (index < end && message.charAt(index) == ' ') { index++; } if (index < end && message.charAt(index) == ',') { index++; while (index < end && message.charAt(index) == ' ') { index++; } if (index < end) { String sub = message.substring(index); if (sub.startsWith("number")) { return TYPE_NUMBER; } else if (sub.startsWith("date")) { return TYPE_DATE; } else if (sub.startsWith("time")) { return TYPE_TIME; } else if (sub.startsWith("choice")) { return TYPE_UNKNOWN; } } } return TYPE_STRING; } /** * Converts a {@link Format} to a type code ({@link #TYPE_STRING} etc.) */ private static int formatToType(Format format) { if (format == null) { return TYPE_STRING; } else if (format instanceof NumberFormat) { return TYPE_NUMBER; } else if (format instanceof DateFormat) { // might be date or time, but assume it's date return TYPE_DATE; } else { return TYPE_STRING; } } /** * Default implementation of {@link ResourceInstance}. */ private static class Instance implements ResourceInstance { ResourceDefinition definition; ResourceBundle bundle; Object[] args; public Instance( ResourceBundle bundle, ResourceDefinition definition, Object[] args) { this.definition = definition; this.bundle = bundle; this.args = args; } public String toString() { String message = bundle.getString(definition.key); MessageFormat format = new MessageFormat(message); format.setLocale(bundle.getLocale()); String formattedMessage = format.format(args); return formattedMessage; } } } // End ResourceDefinition.java resgen/src/org/eigenbase/resgen/JavaFunctorBaseGenerator.java0000444000175000017500000002101211543216467024552 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/JavaFunctorBaseGenerator.java#4 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import org.apache.tools.ant.BuildException; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Generates a Java class for the base locale, * using the 'functor' code-generation style. * *

For each resource, the generated Java class contains one public, final, * non-static member. This member belongs to a class which has a number of * methods for creating strings or exceptions based upon this resource. The * methods are typesafe; that is, they have the same number and type of * parameters as the resource itself. * * @author jhyde * @since 19 September, 2005 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/JavaFunctorBaseGenerator.java#4 $ */ public class JavaFunctorBaseGenerator extends JavaBaseGenerator { private final Map functorMap = new HashMap(); private final StringWriter functorSw = new StringWriter(); private final PrintWriter functorPw = new PrintWriter(functorSw); JavaFunctorBaseGenerator( File srcFile, File file, String className, String baseClassName, ResourceDef.ResourceBundle resourceBundle) { super(srcFile, file, className, baseClassName, resourceBundle); } public void generateResource(ResourceDef.Resource resource, PrintWriter pw) { if (resource.text == null) { throw new BuildException( "Resource '" + resource.name + "' has no message"); } String text = resource.text.cdata; String comment = ResourceGen.getComment(resource); final String resourceInitcap = ResourceGen.getResourceInitcap(resource);// e.g. "Internal" String parameterList = getParameterList(text); String argumentList = getArgumentList(text); String propList = getPropList(resource); String errorClassName; if (resource instanceof ResourceDef.Exception) { ResourceDef.Exception exception = (ResourceDef.Exception) resource; errorClassName = getErrorClass(exception); } else { errorClassName = null; } String functorType = getFunctorType(parameterList, argumentList, errorClassName); pw.println(); Util.generateCommentBlock(pw, resource.name, text, comment); pw.println(" public final " + functorType + " " + resourceInitcap + " = new " + functorType + "(" + Util.quoteForJava(resourceInitcap) + ", " + Util.quoteForJava(text) + ", " + propList + ");"); } private String getPropList(ResourceDef.Resource resource) { if (resource.properties == null || resource.properties.length == 0) { return "null"; } final StringBuffer buf = new StringBuffer("new String[] {"); for (int i = 0; i < resource.properties.length; i++) { if (i > 0) { buf.append(", "); } ResourceDef.Property property = resource.properties[i]; buf.append(Util.quoteForJava(property.name)); buf.append(", "); buf.append(Util.quoteForJava(property.cdata)); } buf.append("}"); return buf.toString(); } private String getFunctorType( String parameterList, String argumentList, String errorClassName) { List key = Arrays.asList(new String[] {parameterList, errorClassName}); String functorType = (String) functorMap.get(key); if (functorType == null) { functorType = "_Def" + functorMap.size(); functorMap.put(key, functorType); genFunctor(functorType, parameterList, argumentList, errorClassName, functorPw); } return functorType; } private void genFunctor(String functorType, String parameterList, String argumentList, String errorClassName, PrintWriter pw) { String definitionClass = "org.eigenbase.resgen.ResourceDefinition"; final String classNameSansPackage = Util.removePackage(className); final String bundleThis = classNameSansPackage + ".this"; String argumentArray = argumentList.equals("") ? "emptyObjectArray" : "new Object[] {" + argumentList + "}"; pw.println(); pw.println(" /**"); pw.println(" * Definition for resources which"); if (errorClassName != null) { pw.println(" * return a {@link " + errorClassName + "} exception and"); } pw.println(" * take arguments '" + parameterList + "'."); pw.println(" */"); pw.println(" public final class " + functorType + " extends " + definitionClass + " {"); pw.println(" " + functorType + "(String key, String baseMessage, String[] props) {"); pw.println(" super(key, baseMessage, props);"); pw.println(" }"); pw.println(" public String str(" + parameterList + ") {"); pw.println(" return instantiate(" + addLists(bundleThis, argumentArray) + ").toString();"); pw.println(" }"); if (errorClassName != null) { final ExceptionDescription ed = new ExceptionDescription(errorClassName); if (ed.hasInstCon) { pw.println(" public " + errorClassName + " ex(" + parameterList + ") {"); pw.println(" return new " + errorClassName + "(instantiate(" + addLists(bundleThis, argumentArray) + "));"); pw.println(" }"); } else if (ed.hasInstThrowCon) { pw.println(" public " + errorClassName + " ex(" + parameterList + ") {"); pw.println(" return new " + errorClassName + "(instantiate(" + addLists(bundleThis, argumentArray) + "), null);"); pw.println(" }"); } else if (ed.hasStringCon) { pw.println(" public " + errorClassName + " ex(" + parameterList + ") {"); pw.println(" return new " + errorClassName + "(instantiate(" + addLists(bundleThis, argumentArray) + ").toString());"); pw.println(" }"); } else if (ed.hasStringThrowCon) { pw.println(" public " + errorClassName + " ex(" + parameterList + ") {"); pw.println(" return new " + errorClassName + "(instantiate(" + addLists(bundleThis, argumentArray) + ").toString(), null);"); pw.println(" }"); } if (ed.hasInstThrowCon) { pw.println(" public " + errorClassName + " ex(" + addLists(parameterList, "Throwable err") + ") {"); pw.println(" return new " + errorClassName + "(instantiate(" + addLists(bundleThis, argumentArray) + "), err);"); pw.println(" }"); } else if (ed.hasStringThrowCon) { pw.println(" public " + errorClassName + " ex(" + addLists(parameterList, "Throwable err") + ") {"); pw.println(" return new " + errorClassName + "(instantiate(" + addLists(bundleThis, argumentArray) + ").toString(), err);"); pw.println(" }"); } } pw.println(" }"); } protected void postModule(PrintWriter pw) { functorPw.flush(); pw.println(functorSw.toString()); } } // End JavaFunctorBaseGenerator.java resgen/src/org/eigenbase/resgen/PropertiesFileTask.java0000444000175000017500000000522111543216467023451 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/PropertiesFileTask.java#4 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Locale; /** * Ant task which processes a properties file and generates a C++ or Java class * from the resources in it. * * @author jhyde * @since 19 September, 2005 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/PropertiesFileTask.java#4 $ */ class PropertiesFileTask extends FileTask { final Locale locale; PropertiesFileTask(ResourceGenTask.Include include, String fileName) { this.include = include; this.fileName = fileName; this.className = Util.fileNameToClassName(fileName, ".properties"); this.locale = Util.fileNameToLocale(fileName, ".properties"); } /** * Given an existing properties file such as * happy/Birthday_fr_FR.properties, generates the * corresponding Java class happy.Birthday_fr_FR.java. * *

todo: Validate. */ void process(ResourceGen generator) throws IOException { // e.g. happy/Birthday_fr_FR.properties String s = Util.fileNameSansLocale(fileName, ".properties"); File file = new File(include.root.src, s + ".xml"); URL url = Util.convertPathToURL(file); ResourceDef.ResourceBundle resourceList = Util.load(url); if (outputJava) { generateJava(generator, resourceList, locale); } if (outputCpp) { // We don't generate any C++ code from .properties file -- yet. } } } // End PropertiesFileTask.java resgen/src/org/eigenbase/resgen/AbstractJavaGenerator.java0000444000175000017500000000761211543216467024114 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/AbstractJavaGenerator.java#3 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import java.io.PrintWriter; import java.io.File; /** * Abstract base for all generators which generate Java code. * * @author jhyde * @since 19 September, 2005 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/AbstractJavaGenerator.java#3 $ */ abstract class AbstractJavaGenerator extends AbstractGenerator { protected final String className; protected final ResourceDef.ResourceBundle resourceBundle; protected final String baseClassName; private static final String JAVA_STRING = "String"; private static final String JAVA_NUMBER = "Number"; private static final String JAVA_DATE_TIME = "java.util.Date"; private static final String[] JAVA_TYPE_NAMES = {JAVA_STRING, JAVA_NUMBER, JAVA_DATE_TIME, JAVA_DATE_TIME}; AbstractJavaGenerator( File srcFile, File file, String className, ResourceDef.ResourceBundle resourceBundle, String baseClassName) { super(srcFile, file); this.className = className; this.baseClassName = baseClassName; this.resourceBundle = resourceBundle; } /** * Returns the type of error which is to be thrown by this resource. * Result is null if this is not an error. */ protected String getErrorClass( ResourceDef.Exception exception) { if (exception.className != null) { return exception.className; } else if (resourceBundle.exceptionClassName != null) { return resourceBundle.exceptionClassName; } else { return "java.lang.RuntimeException"; } } protected String getPackageName() { int lastDot = className.lastIndexOf('.'); if (lastDot < 0) { return null; } else { return className.substring(0,lastDot); } } protected String[] getArgTypes(String message) { return ResourceDefinition.getArgTypes(message, JAVA_TYPE_NAMES); } protected void generateHeader(PrintWriter pw) { generateDoNotModifyHeader(pw); String packageName = getPackageName(); if (packageName != null) { pw.println("package " + packageName + ";"); } pw.println("import java.io.IOException;"); pw.println("import java.util.Locale;"); pw.println("import java.util.ResourceBundle;"); pw.println("import org.eigenbase.resgen.*;"); pw.println(); generateGeneratedByBlock(pw); } protected void generateFooter(PrintWriter pw, String className) { pw.println("// End " + className + ".java"); } protected String getClassName() { return className; } protected String getBaseClassName() { return baseClassName; } } // End AbstractJavaGenerator.java resgen/src/org/eigenbase/resgen/Resource.xml0000444000175000017500000001362611543216467021350 0ustar drazzibdrazzib This model specifies the elements which make up a resource file. See {@link ResourceGenTask} for more information. A ResourceBundle is a collection of resources. The resource generator generates a class from a resource bundle which has an accessor method for each resource. The locale of resources in this resource bundle, for example, "en_US_Boston", "en_US", or "en". Default class for exceptions. C++ Namespace for generated classes. Base classes are assumed to be in the same namespace. C++ common include file. Included at the start of all generated C++ class implementations. Default class for exceptions in generated C++. The location of the C++ header file that contains the definition of the defautl C++ exception class. Required if the default C++ exception class is defined. This location is also used as the default location for resource-specific exception classes. Text within this element is included in the generated class. The name of this message or error, unique within this resource bundle. abstract org.eigenbase.xom.DOMWrapper getDef(); A message. org.eigenbase.xom.DOMWrapper getDef() { return _def; } An exception defines a message which is issued in response to some invalid condition. It has a type, which must be derived from {@link Throwable}. The generated newExceptionName method creates an instance of this exception with the appropriate parameters. The name of the exception class. Must be fully qualified, unless it is in the package java.lang. If not specified, the resource bundle's default exception class is used. The name of the C++ exception class. If not specified, the resource bundle's default C++ exception class is used. The name of the C++ exception class. If not specified, the resource bundle's default C++ exception location is used. One of the two must be specfied if the C++ exception class is given. Set to true if the C++ exception classes support being chained together. The default is false. If true, an extra method will be generated for that takes a const pointer to the C++ exception class. org.eigenbase.xom.DOMWrapper getDef() { return _def; } Name of the property. resgen/src/org/eigenbase/resgen/FileTask.java0000444000175000017500000001523611543216467021403 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/FileTask.java#4 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import org.apache.tools.ant.BuildException; import java.io.*; import java.util.Locale; /** * Abstract base class for an Ant task which processes a file containing * resources. * * @author jhyde * @since 19 September, 2005 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/FileTask.java#4 $ */ abstract class FileTask { ResourceGenTask.Include include; String className; String fileName; String cppClassName; boolean outputJava; boolean outputCpp; abstract void process(ResourceGen generator) throws IOException; /** * Returns the XML source file, e.g. happy/BirthdayResource_en.xml. */ File getFile() { return new File(include.root.src, fileName); } /** * Returns the XML source file, mangled for use in comments. * e.g. .../BirthdayResource_en.xml if SCM-safe comments are enabled. */ String getFileForComments() { String file = getFile().toString().replace('\\', '/'); if (include.root.commentStyle == ResourceGenTask.COMMENT_STYLE_SCM_SAFE) { int slashPos = file.lastIndexOf('/'); if (slashPos > 0) { file = "..." + file.substring(slashPos); } } return file; } boolean checkUpToDate(ResourceGen generator, File file) { if (file.exists() && file.lastModified() >= getFile().lastModified()) { generator.comment(file + " is up to date"); return true; } return false; } void makeParentDirs(File file) { if (file.getParentFile() != null) { file.getParentFile().mkdirs(); } } private String getPackageName() { int lastDot = className.lastIndexOf('.'); if (lastDot < 0) { return null; } else { return className.substring(0, lastDot); } } private File getPackageDirectory(File file) { final String packageName = getPackageName(); if (packageName == null) { return file; } return new File(file, packageName.replace('.', Util.fileSep)); } /** * Returns the directory from which to read source files. */ File getSrcDirectory() { return getPackageDirectory(include.root.src); } /** * Returns the directory to which to generate Java or C++ files. */ File getDestDirectory() { return getPackageDirectory(include.root.dest); } /** * Returns the directory to which to generate .properties and .xml * files. */ File getResourceDirectory() { return getPackageDirectory(include.root.res); } /** * Generates a Java class, e.g. com/foo/MyResource.java or * com/foo/MyResource_en_US.java, depending upon whether locale is * null. */ void generateJava( ResourceGen generator, ResourceDef.ResourceBundle resourceList, Locale locale) { String fileName = Util.getClassNameSansPackage(className, locale) + ".java"; File file = new File(getDestDirectory(), fileName); if (!include.root.force && checkUpToDate(generator, file)) { return; } generator.comment("Generating " + file); final FileOutputStream out; try { makeParentDirs(file); out = new FileOutputStream(file); } catch (FileNotFoundException e) { throw new BuildException("Error while writing " + file, e); } PrintWriter pw = new PrintWriter(out); try { Generator gen; if (locale == null) { String baseClassName = include.baseClassName; if (baseClassName == null) { baseClassName = "org.eigenbase.resgen.ShadowResourceBundle"; } switch (include.root.style) { case ResourceGenTask.STYLE_DYNAMIC: gen = new JavaBaseGenerator(getFile(), file, className, baseClassName, resourceList); break; case ResourceGenTask.STYLE_FUNCTOR: gen = new JavaFunctorBaseGenerator(getFile(), file, className, baseClassName, resourceList); break; default: throw new AssertionError("unexpected style " + include.root.style); } } else { // e.g. "mondrian.resource.MondrianResource_en_US" String className = this.className + "_" + locale.toString(); // e.g. "mondrian.resource.MondrianResource" String baseClassName = this.className; gen = new JavaLocaleGenerator(getFile(), file, className, resourceList, locale, baseClassName); } configureCommentStyle(gen); gen.generateModule(generator, resourceList, pw); } finally { pw.close(); } } protected void configureCommentStyle(Generator gen) { switch(include.root.commentStyle) { case ResourceGenTask.COMMENT_STYLE_NORMAL: gen.setScmSafeComments(false); break; case ResourceGenTask.COMMENT_STYLE_SCM_SAFE: gen.setScmSafeComments(true); break; default: throw new AssertionError( "unexpected comment style " + include.root.commentStyle); } } } resgen/src/org/eigenbase/resgen/Resource.java0000444000175000017500000000615011543216467021463 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/Resource.java#4 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import java.util.Locale; /** * A Resource is a collection of messages for a particular * software component and locale. It is loaded from an XML file whose root * element is <BaflResourceList>. * *

Given such an XML file, {@link ResourceGen} can generate Java a wrapper * class which implements this interface, and also has a method to create an * error for each message.

* * @author jhyde * @since 3 December, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/Resource.java#4 $ **/ public interface Resource { /** * Populates this Resource from a URL. * * @param url The URL of the XML file containing the error messages * @param locale The ISO locale code (e.g. "en", or * "en_US", or "en_US_WIN") of the messages * @throws IOException if url cannot be opened, or if the * format of its contents are invalid **/ void init(java.net.URL url, Locale locale) throws java.io.IOException; /** * Populates this Resource from an XML document. * * @param resourceList The URL of the XML file containing the error messages * @param locale The ISO locale code (e.g. "en", or * "en_US", or "en_US_WIN") of the messages **/ void init(ResourceDef.ResourceBundle resourceList, Locale locale); /** * Returns the locale of the messages. **/ Locale getLocale(); /** * Formats the message corresponding to code with the given * arguments. If an argument is not supplied, the tokens remain in the * returned message string. **/ String formatError(int code, Object[] args); /** * Returns the severity of this message. **/ int getSeverity(int code); int SEVERITY_INFO = 0; int SEVERITY_ERR = 1; int SEVERITY_WARN = 2; int SEVERITY_NON_FATAL_ERR = 3; } // End Resource.java resgen/src/org/eigenbase/resgen/ResourceInstance.java0000444000175000017500000000266011543216467023152 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/ResourceInstance.java#3 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2002-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 19 September, 2002 */ package org.eigenbase.resgen; /** * A ResourceInstance is an occurrence of a {@link * ResourceDefinition} with a set of arguments. It can later be formatted to a * specific locale. */ public interface ResourceInstance { public String toString(); } // End ResourceInstance.java resgen/src/org/eigenbase/resgen/ResourceGen.java0000444000175000017500000001311311543216467022112 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/ResourceGen.java#7 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import org.eigenbase.xom.DOMWrapper; import java.io.File; import java.io.IOException; /** * ResourceGen parses an XML file containing error messages, and * generates .java file to access the errors. Usage:
* *
ResourceGen xmlFile
* *
For example,
* *
java org.eigenbase.resgen.ResourceGen MyResource_en.xml
* *

* *

This will create class MyResource, with a * function corresponding to each error message in * MyResource_en.xml.

* *

See also the ANT Task, {@link ResourceGenTask}.

* * @author jhyde * @since 3 December, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/ResourceGen.java#7 $ */ public class ResourceGen { public static void main(String [] args) throws IOException { ResourceGenTask rootArgs = parse(args); new ResourceGen().run(rootArgs); } static ResourceGenTask parse(String[] args) { ResourceGenTask rootArgs = new ResourceGenTask(); for (int i = 0; i < args.length; i++) { String arg = args[i]; if (arg.equals("-mode") && i + 1 < args.length) { rootArgs.setMode(args[++i]); } else if (arg.equals("-srcdir") && i + 1 < args.length) { rootArgs.setSrcdir(new File(args[++i])); } else if (arg.equals("-destdir") && i + 1 < args.length) { rootArgs.setDestdir(new File(args[++i])); } else if (arg.equals("-resdir") && i + 1 < args.length) { rootArgs.setResdir(new File(args[++i])); } else if (arg.equals("-locales") && i + 1 < args.length) { rootArgs.setLocales(args[++i]); } else if (arg.equals("-style") && i + 1 < args.length) { rootArgs.setStyle(args[++i]); } else if (arg.equals("-force")) { rootArgs.setForce(true); } else if (arg.equals("-commentstyle")) { rootArgs.setCommentStyle(args[++i]); } else { ResourceGenTask.Include resourceArgs = new ResourceGenTask.Include(); rootArgs.addInclude(resourceArgs); resourceArgs.setName(arg); } } if (rootArgs.getIncludes().length == 0) { throw new java.lang.Error("No input file specified."); } if (rootArgs.getDestdir() == null) { rootArgs.setDestdir(rootArgs.getSrcdir()); } return rootArgs; } void run(ResourceGenTask rootArgs) throws IOException { rootArgs.validate(); final ResourceGenTask.Include[] includes = rootArgs.getIncludes(); for (int i = 0; i < includes.length; i++) { includes[i].process(this); } } /** * Prints a message to the output stream. */ void comment(String message) { System.out.println(message); } /** * Returns the name of the resource with the first letter capitalized, * suitable for use in method names. For example, "MyErrorMessage". */ static String getResourceInitcap(ResourceDef.Resource resource) { String name = resource.name; if (name.equals(name.toUpperCase())) { return "_" + name; } else { return name.substring(0,1).toUpperCase() + name.substring(1); } } /** * Returns any comment relating to the message. */ static String getComment(ResourceDef.Resource resource) { DOMWrapper[] children = resource.getDef().getChildren(); for (int i = 0; i < children.length; i++) { DOMWrapper child = children[i]; if (child.getType() == DOMWrapper.COMMENT) { return child.getText(); // first comment only } } return null; // no comment } FileTask createXmlTask( ResourceGenTask.Include include, String fileName, String className, String baseClassName, boolean outputJava, String cppClassName, String cppBaseClassName, boolean outputCpp) { return new XmlFileTask( include, fileName, className, baseClassName, outputJava, cppClassName, cppBaseClassName, outputCpp); } FileTask createPropertiesTask( ResourceGenTask.Include include, String fileName) { return new PropertiesFileTask(include, fileName); } } // End ResourceGen.java resgen/src/org/eigenbase/resgen/Generator.java0000444000175000017500000000401611543216467021621 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/Generator.java#3 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import java.io.PrintWriter; /** * A generator converts a set of resource definitions to a piece of code. * * @author jhyde * @since 19 September, 2005 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/Generator.java#3 $ */ interface Generator { /** * Configures whether this generator will output comments that may be * submitted to a source code management system. In general, it * squelches comments indicating the file should not be checked in as * well as comments change with each generation of the file (thereby * avoiding merge conflicts). * * @param enabled */ void setScmSafeComments(boolean enabled); /** * Generates a class containing a line for each resource. */ void generateModule( ResourceGen generator, ResourceDef.ResourceBundle resourceList, PrintWriter pw); } // End Generator.java resgen/src/org/eigenbase/resgen/JavaBaseGenerator.java0000444000175000017500000002640211543216467023221 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/resgen/JavaBaseGenerator.java#4 $ // Package org.eigenbase.resgen is an i18n resource generator. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.resgen; import org.apache.tools.ant.BuildException; import java.io.PrintWriter; import java.io.File; import java.lang.reflect.Constructor; import java.util.HashSet; import java.util.Set; /** * Generates a Java class for the base locale. * * @author jhyde * @since 19 September, 2005 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/JavaBaseGenerator.java#4 $ */ class JavaBaseGenerator extends AbstractJavaGenerator { protected final Set warnedClasses = new HashSet(); JavaBaseGenerator( File srcFile, File file, String className, String baseClassName, ResourceDef.ResourceBundle resourceBundle) { super(srcFile, file, className, resourceBundle, baseClassName); } public void generateModule( ResourceGen generator, ResourceDef.ResourceBundle resourceList, PrintWriter pw) { generateHeader(pw); String className = getClassName(); final String classNameSansPackage = Util.removePackage(className); pw.print("public class " + classNameSansPackage); final String baseClass = getBaseClassName(); if (baseClass != null) { pw.print(" extends " + baseClass); } pw.println(" {"); pw.println(" public " + classNameSansPackage + "() throws IOException {"); pw.println(" }"); pw.println(" private static final String baseName = " + Util.quoteForJava(getClassName()) + ";"); pw.println(" /**"); pw.println(" * Retrieves the singleton instance of {@link " + classNameSansPackage + "}. If"); pw.println(" * the application has called {@link #setThreadLocale}, returns the"); pw.println(" * resource for the thread's locale."); pw.println(" */"); pw.println(" public static synchronized " + classNameSansPackage + " instance() {"); pw.println(" return (" + classNameSansPackage + ") instance(baseName, getThreadOrDefaultLocale(), ResourceBundle.getBundle(baseName, getThreadOrDefaultLocale()));"); pw.println(" }"); pw.println(" /**"); pw.println(" * Retrieves the instance of {@link " + classNameSansPackage + "} for the given locale."); pw.println(" */"); pw.println(" public static synchronized " + classNameSansPackage + " instance(Locale locale) {"); pw.println(" return (" + classNameSansPackage + ") instance(baseName, locale, ResourceBundle.getBundle(baseName, locale));"); pw.println(" }"); if (resourceList.code != null) { pw.println(" // begin of included code"); pw.print(resourceList.code.cdata); pw.println(" // end of included code"); } for (int j = 0; j < resourceList.resources.length; j++) { ResourceDef.Resource resource = resourceList.resources[j]; generateResource(resource, pw); } pw.println(""); postModule(pw); pw.println("}"); } protected void postModule(PrintWriter pw) { } public void generateResource(ResourceDef.Resource resource, PrintWriter pw) { if (resource.text == null) { throw new BuildException( "Resource '" + resource.name + "' has no message"); } String text = resource.text.cdata; String comment = ResourceGen.getComment(resource); final String resourceInitcap = ResourceGen.getResourceInitcap(resource);// e.g. "Internal" String definitionClass = "org.eigenbase.resgen.ResourceDefinition"; String parameterList = getParameterList(text); String argumentList = getArgumentList(text); // e.g. "p0, p1" String argumentArray = argumentList.equals("") ? "emptyObjectArray" : "new Object[] {" + argumentList + "}"; // e.g. "new Object[] {p0, p1}" pw.println(); Util.generateCommentBlock(pw, resource.name, text, comment); pw.println(" public static final " + definitionClass + " " + resourceInitcap + " = new " + definitionClass + "(\"" + resourceInitcap + "\", " + Util.quoteForJava(text) + ");"); pw.println(" public String get" + resourceInitcap + "(" + parameterList + ") {"); pw.println(" return " + resourceInitcap + ".instantiate(" + addLists("this", argumentArray) + ").toString();"); pw.println(" }"); if (resource instanceof ResourceDef.Exception) { ResourceDef.Exception exception = (ResourceDef.Exception) resource; String errorClassName = getErrorClass(exception); final ExceptionDescription ed = new ExceptionDescription(errorClassName); if (ed.hasInstCon) { pw.println(" public " + errorClassName + " new" + resourceInitcap + "(" + parameterList + ") {"); pw.println(" return new " + errorClassName + "(" + resourceInitcap + ".instantiate(" + addLists("this", argumentArray) + "));"); pw.println(" }"); } else if (ed.hasInstThrowCon) { pw.println(" public " + errorClassName + " new" + resourceInitcap + "(" + parameterList + ") {"); pw.println(" return new " + errorClassName + "(" + resourceInitcap + ".instantiate(" + addLists("this", argumentArray) + "), null);"); pw.println(" }"); } else if (ed.hasStringCon) { pw.println(" public " + errorClassName + " new" + resourceInitcap + "(" + parameterList + ") {"); pw.println(" return new " + errorClassName + "(get" + resourceInitcap + "(" + argumentList + "));"); pw.println(" }"); } else if (ed.hasStringThrowCon) { pw.println(" public " + errorClassName + " new" + resourceInitcap + "(" + parameterList + ") {"); pw.println(" return new " + errorClassName + "(get" + resourceInitcap + "(" + argumentList + "), null);"); pw.println(" }"); } if (ed.hasInstThrowCon) { pw.println(" public " + errorClassName + " new" + resourceInitcap + "(" + addLists(parameterList, "Throwable err") + ") {"); pw.println(" return new " + errorClassName + "(" + resourceInitcap + ".instantiate(" + addLists("this", argumentArray) + "), err);"); pw.println(" }"); } else if (ed.hasStringThrowCon) { pw.println(" public " + errorClassName + " new" + resourceInitcap + "(" + addLists(parameterList, "Throwable err") + ") {"); pw.println(" return new " + errorClassName + "(get" + resourceInitcap + "(" + argumentList + "), err);"); pw.println(" }"); } } } /** * Description of the constructs that an exception class has. */ class ExceptionDescription { boolean hasInstCon; boolean hasInstThrowCon; boolean hasStringCon; boolean hasStringThrowCon; /** * Figures out what constructors the exception class has. We'd * prefer to use * init(ResourceDefinition rd) or * init(ResourceDefinition rd, Throwable e) * if it has them, but we can use * init(String s) and * init(String s, Throwable e) * as a fall-back. * * Prints a warming message if the class cannot be loaded. * * @param errorClassName Name of exception class */ ExceptionDescription(String errorClassName) { hasInstCon = false; hasInstThrowCon = false; hasStringCon = false; hasStringThrowCon = false; try { Class errorClass; try { errorClass = Class.forName(errorClassName); } catch (ClassNotFoundException e) { // Might be in the java.lang package, for which we // allow them to omit the package name. errorClass = Class.forName("java.lang." + errorClassName); } Constructor[] constructors = errorClass.getConstructors(); for (int i = 0; i < constructors.length; i++) { Constructor constructor = constructors[i]; Class[] types = constructor.getParameterTypes(); if (types.length == 1 && ResourceInstance.class.isAssignableFrom(types[0])) { hasInstCon = true; } if (types.length == 1 && String.class.isAssignableFrom(types[0])) { hasStringCon = true; } if (types.length == 2 && ResourceInstance.class.isAssignableFrom(types[0]) && Throwable.class.isAssignableFrom(types[1])) { hasInstThrowCon = true; } if (types.length == 2 && String.class.isAssignableFrom(types[0]) && Throwable.class.isAssignableFrom(types[1])) { hasStringThrowCon = true; } } } catch (ClassNotFoundException e) { if (warnedClasses.add(errorClassName)) { System.out.println("Warning: Could not find exception " + "class '" + errorClassName + "' on classpath. " + "Exception factory methods will not be generated."); } } } } // helper protected static String addLists(String x, String y) { if (x == null || x.equals("")) { if (y == null || y.equals("")) { return ""; } else { return y; } } else if (y == null || y.equals("")) { return x; } else { return x + ", " + y; } } protected static String addLists(String x, String y, String z) { return addLists(x, addLists(y, z)); } } // End JavaBaseGenerator.java resgen/src/org/eigenbase/xom/0000755000175000017500000000000011543216467016351 5ustar drazzibdrazzibresgen/src/org/eigenbase/xom/StringEscaper.java0000444000175000017500000001552411543216467021772 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/StringEscaper.java#6 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2000-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.xom; import java.util.*; /** *

StringEscaper is a utility for replacing special characters * with escape sequences in strings. Initially, a StringEscaper starts out as * an identity transform in the "mutable" state. Call defineEscape as many * times as necessary to set up mappings, and then call makeImmutable() before * using appendEscapedString to actually apply the defined transform. Or, use one of * the global mappings pre-defined here.

**/ public class StringEscaper implements Cloneable { private ArrayList translationVector; private String [] translationTable; public static StringEscaper xmlEscaper; public static StringEscaper xmlNumericEscaper; public static StringEscaper htmlEscaper; public static StringEscaper urlArgEscaper; public static StringEscaper urlEscaper; /** * Identity transform */ public StringEscaper() { translationVector = new ArrayList(); } /** * Map character "from" to escape sequence "to" */ public void defineEscape(char from,String to) { int i = (int) from; if (i >= translationVector.size()) { // Extend list by adding the requisite number of nulls. final int count = i + 1 - translationVector.size(); translationVector.addAll( new AbstractList() { public Object get(int index) { return null; } public int size() { return count; } }); } translationVector.set(i, to); } /** * Call this before attempting to escape strings; after this, * defineEscape may not be called again. */ public void makeImmutable() { translationTable = (String[]) translationVector.toArray( new String[translationVector.size()]); translationVector = null; } /** * Apply an immutable transformation to the given string. */ public String escapeString(String s) { StringBuffer sb = null; int n = s.length(); for (int i = 0; i < n; i++) { char c = s.charAt(i); String escape; // codes >= 128 (e.g. Euro sign) are always escaped if (c > 127) { escape = "&#" + Integer.toString(c) + ";"; } else if (c >= translationTable.length) { escape = null; } else { escape = translationTable[c]; } if (escape == null) { if (sb != null) { sb.append(c); } } else { if (sb == null) { sb = new StringBuffer(n * 2); sb.append(s.substring(0, i)); } sb.append(escape); } } if (sb == null) { return s; } else { return sb.toString(); } } /** * Apply an immutable transformation to the given string, writing the * results to a string buffer. */ public void appendEscapedString(String s, StringBuffer sb) { int n = s.length(); for (int i = 0; i < n; i++) { char c = s.charAt(i); String escape; if (c >= translationTable.length) { escape = null; } else { escape = translationTable[c]; } if (escape == null) { sb.append(c); } else { sb.append(escape); } } } protected Object clone() { StringEscaper clone = new StringEscaper(); if (translationVector != null) { clone.translationVector = new ArrayList(translationVector); } if (translationTable != null) { clone.translationTable = (String[]) translationTable.clone(); } return clone; } /** * Create a mutable escaper from an existing escaper, which may * already be immutable. */ public StringEscaper getMutableClone() { StringEscaper clone = (StringEscaper) clone(); if (clone.translationVector == null) { clone.translationVector = new ArrayList(Arrays.asList(clone.translationTable)); clone.translationTable = null; } return clone; } static { htmlEscaper = new StringEscaper(); htmlEscaper.defineEscape('&', "&"); htmlEscaper.defineEscape('"', """); // htmlEscaper.defineEscape('\'',"'"); htmlEscaper.defineEscape('\'', "'"); htmlEscaper.defineEscape('<', "<"); htmlEscaper.defineEscape('>', ">"); xmlNumericEscaper = new StringEscaper(); xmlNumericEscaper.defineEscape('&',"&"); xmlNumericEscaper.defineEscape('"',"""); xmlNumericEscaper.defineEscape('\'',"'"); xmlNumericEscaper.defineEscape('<',"<"); xmlNumericEscaper.defineEscape('>',">"); urlArgEscaper = new StringEscaper(); urlArgEscaper.defineEscape('?', "%3f"); urlArgEscaper.defineEscape('&', "%26"); urlEscaper = urlArgEscaper.getMutableClone(); urlEscaper.defineEscape('%', "%%"); urlEscaper.defineEscape('"', "%22"); urlEscaper.defineEscape('\r', "+"); urlEscaper.defineEscape('\n', "+"); urlEscaper.defineEscape(' ', "+"); urlEscaper.defineEscape('#', "%23"); htmlEscaper.makeImmutable(); xmlEscaper = htmlEscaper; xmlNumericEscaper.makeImmutable(); urlArgEscaper.makeImmutable(); urlEscaper.makeImmutable(); } } // End StringEscaper.java resgen/src/org/eigenbase/xom/Locator.java0000444000175000017500000000250011543216467020612 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/Locator.java#1 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2008-2008 The Eigenbase Project // Copyright (C) 2008-2008 Disruptive Tech // Copyright (C) 2008-2008 LucidEra, Inc. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.xom; /** * Callback to find the location of a node within its document. * * @author jhyde * @version $Id: //open/util/resgen/src/org/eigenbase/xom/Locator.java#1 $ * @since Jun 6, 2008 */ public interface Locator { Location getLocation(DOMWrapper wrapper); } // End Locator.java resgen/src/org/eigenbase/xom/NodeDef.java0000444000175000017500000000557511543216467020532 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/NodeDef.java#4 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2008 The Eigenbase Project // Copyright (C) 2005-2008 Disruptive Tech // Copyright (C) 2005-2008 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 11 October, 2001 */ package org.eigenbase.xom; import java.io.PrintWriter; /** * NodeDef represents a node in a parse tree. It is a base class * for {@link ElementDef}, {@link TextDef}, etc. * * @author jhyde * @since 11 October, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/NodeDef.java#4 $ **/ public interface NodeDef { /** * Returns the name of this node's tag. **/ String getName(); /** * Returns the type of this element. * Values are as for {@link DOMWrapper#getType}. */ int getType(); /** * Returns the text inside this node. **/ String getText(); /** * Returns the children of this node. **/ NodeDef[] getChildren(); /** * Outputs this element definition in XML to any XMLOutput. * @param out the XMLOutput class to display the XML **/ void displayXML(XMLOutput out, int indent); /** * Outputs this node to any PrintWriter, * in a formatted fashion with automatic indenting. * @param out the PrintWriter to which to write this NodeDef. * @param indent the indentation level for the printout. */ void display(PrintWriter out, int indent); /** * Retrieves the {@link DOMWrapper} which was used to create this * node. Only works if this nodes's {@link MetaDef.Element#keepDef} was * true (or, if it is not set, if the default * {@link MetaDef.Model#defaultKeepDef} is true); * otherwise, returns null. * * @return wrapper underlying this node */ DOMWrapper getWrapper(); /** * Returns the location of this element in its document. * * @return location of this element, or null if location is not available */ Location getLocation(); } // End NodeDef.java resgen/src/org/eigenbase/xom/ParserTester.java0000444000175000017500000001257511543216467021647 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/ParserTester.java#3 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2000-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // KLO, 22 July, 2001 */ package org.eigenbase.xom; import java.io.*; /** * Test the MSParser */ public class ParserTester { // parser determines the type of parser to use. Currently we support // MSXML and XERCES. private int parserType; private static final int MSXML = 1; private static final int XERCES = 2; // These members contain the actual parsers to use. Only one will // ever be set. private Parser parser; // This member contain the model document type String modelDocType; // This member contain the URL for the DTD file String dtdUrl; //Read the XML file public ParserTester(String dtdFile, int parserType) throws XOMException, IOException { this.parserType = parserType; parser = null; File dtdPath = new File(dtdFile); this.modelDocType = dtdFile.substring(0, dtdFile.indexOf(".")); this.dtdUrl = "file:" + dtdPath.getAbsolutePath(); switch (parserType) { // case MSXML: // parser = org.eigenbase.xom.wrappers.MSXMLWrapper.createParser( // modelDocType, dtdPath); // break; case XERCES: parser = new org.eigenbase.xom.wrappers.XercesDOMParser(true); break; default: throw new XOMException("Unknown parser type: " + parserType); } } public void testFile(String testFile) throws XOMException { // parsing directly from an input stream (rather than a reader). String xmlString = null; try { StringWriter sWriter = new StringWriter(); FileReader reader = new FileReader(testFile); if(parserType != MSXML) { PrintWriter out = new PrintWriter(sWriter); out.println(""); if(modelDocType != null) out.println(""); out.flush(); } readerToWriter(reader, sWriter); reader.close(); xmlString = sWriter.toString(); } catch (IOException ex) { throw new XOMException("Unable to read input test " + testFile + ": " + ex.getMessage()); } parser.parse(xmlString); System.out.println("Parsing document succeeded."); } /** * Helper function to copy from a reader to a writer */ private static void readerToWriter(Reader reader, Writer writer) throws IOException { int numChars; final int bufferSize = 16384; char[] buffer = new char[bufferSize]; while((numChars = reader.read(buffer)) != -1) { if(numChars > 0) writer.write(buffer, 0, numChars); } } /** * The ParserTester tests MSXML parser and Xerces Parser. Arguments: *
    *
  1. The DTD file of the XML file *
  2. The XML file for this DTD file *
*

*/ public static void main(String args[]) throws XOMException, IOException { int firstArg = 0; if(args.length > 0 && args[0].equals("-debug")){ System.err.println("parserTest pausing for debugging. " + "Attach your debugger " + "and press return."); try { System.in.read(); firstArg++; } catch(IOException ex) { // Do nothing } } int parserType = MSXML; if (firstArg < args.length && args[firstArg].equals("-msxml")) { parserType = MSXML; firstArg++; } else if (firstArg < args.length && args[firstArg].equals("-xerces")) { parserType = XERCES; firstArg++; } if(args.length < firstArg+2) { System.err.println( "Usage: java ParserTester [-debug] [-msxml | -xerces] " + " "); System.exit(-1); } ParserTester parserTester = new ParserTester(args[firstArg], parserType); firstArg++; parserTester.testFile(args[firstArg]); } } // End ParserTester.java resgen/src/org/eigenbase/xom/package.html0000444000175000017500000001432511543216467020635 0ustar drazzibdrazzib Package org.eigenbase.xom Provides an object layer for reading and writing XML documents.  The XML-Object Mapping layer generates a class for each entity in an XML schema, a member property for each attribute, collections for sub-objects, and methods to serialize to and from XML.

TODO jvs 15-Mar-2005: XOM is nice, but there's no longer a lot of reason for it to exist now that we have JAXB to do the same thing without any tricky bootstrapping issues. So we should phase out XOM.

 

Revision $Id: //open/util/resgen/src/org/eigenbase/xom/package.html#2 $
Copyright Copyright (C) 2005-2005 The Eigenbase Project
Copyright Copyright (C) 2005-2005 Disruptive Tech
Copyright Copyright (C) 2005-2005 Red Square, Inc.
Copyright Portions Copyright (C) 2001-2005 Kana Software, Inc.
Author Dan Sommerfield, Julian Hyde

Schema format

The schema is defined in an XML file, whose format is somewhat similar to an XML Schema.  The (self-describing) meta-schema is meta.xml (as you can see, an XSL style-sheet formats each schema into a javadoc-like web page).

Other schemas include resource.xml

Generated Java Classes

The utilities in this package enable conversion of XML (stored in a DOM-style model) into a typesafe Java representation. Roughly, conversion occurs as follows:

  • Each defined Element becomes a Java Class. The Java Class name matches the Element name. All classes representing Elements descend from {@link org.eigenbase.xom.ElementDef}. All classes from the same model are implemented as static inner classes of a single enclosure class. By convention, enclosure classes always end in "Def".
  • Each Attribute becomes a public member of its enclosing Element class.
  • Text (PCDATA) content becomes a single public String called cdata.
  • Element content becomes a series of public members. The members are of the appropriate types. The members' names are defined in the schema.
  • ANY content becomes a single array of {@link org.eigenbase.xom.ElementDef} called children.

Converting an XML Document to its XOM representation is a two-step process. First, you parse the XML into a DOM representation using your favorite W3C DOM Level 1-compliant parser (note: MSXML is supported as well for backward compatibility). Then, you instantiate the XOM {@link org.eigenbase.xom.ElementDef} subclass corresponding to the root element in the document, passing a portion of the DOM as input to the constructor. After this, the fully-constructed root element provides complete typesafe access to the whole document!

Specific instructions for parsing using a DOM-compliant parser (such as XERCES):

  1. Instantiate your parser, parse the document (validation against the DTD is optional), and retrieve the parsed {@link org.w3c.dom.Document} object.
  2. Call {@link org.w3c.dom.Document#getDocumentElement()} to retrieve the toplevel Node in the document.
  3. Wrap the toplevel node in an instance of {@link org.eigenbase.xom.wrappers.W3CDOMWrapper}.
  4. Construct the appropriate {@link org.eigenbase.xom.ElementDef} subclass from the wrapped node.

Specific instructions for parsing using Microsoft's XML Parser:

  1. Instantiate your parser, parse the document (validation against the DTD is optional), and retrieve {@link com.ms.xml.om.Document} object representing the document.
  2. Call {@link com.ms.xml.om.Document#getRoot()} to retrieve the toplevel Element in the document.
  3. Wrap the toplevel element in an instance of {@link org.eigenbase.xom.wrappers.MSXMLWrapper}.
  4. Construct the appropriate {@link org.eigenbase.xom.ElementDef} subclass from the wrapped node.

Generator

There is now an ANT target, XOMGen, implemented by {@link org.eigenbase.xom.XOMGenTask}.

Tester

There is another helpful utility we use to verify that the stuff we generate works.  It is class {@link MetaTester}, and you invoke it as follows:

jview <classpath_options> org.eigenbase.xom.MetaTester [-debug]
        [-msxml | -xerces] <XML model file> <output dir> [<tests>...]
All the arguments are the same as the ones for {@link org.eigenbase.xom.MetaGenerator}, except for tests.  <tests> is a list of test .xml files that should be valid according to the generated DTD.  The tester will validate the java files against the DTD and also against the java class.  It also runs some basic checks on the java class to make sure that it works.

Generation

For all XML files except meta.xml, we generate corresponding DTD and NameDef.java at build time.  {@link MetaDef} is tricky, because it depends upon itself; use the ant all target to rebuild it.

Guidelines for writing models

  1. Note that within an <Entity>, all <Attribute>s must occur before all <Object>, <Array> or <CData> elements.

Known Issues

Dependencies

This package is dependent upon the following other packages:

  • {@link java.lang}, {@link java.io}, {@link java.util}

Class {@link XOMGenTask} only is dependent upon {@link org.apache.tools.ant}. You therefore require ant.jar to build, but not to run.

Class {@link org.eigenbase.xom.wrappers.XercesDOMParser} only is dependent upon {@link org.xml.sax} and {@link org.apache.xerces.parsers.DOMParser}. You therefore require xerces.jar to build, but not to run.

resgen/src/org/eigenbase/xom/Parser.java0000444000175000017500000000613411543216467020452 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/Parser.java#4 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 2 August, 2001 */ package org.eigenbase.xom; import java.io.InputStream; import java.io.Reader; import java.net.URL; /** * The Parser interface abstracts the behavior which the * org.eigenbase.xom package needs from an XML parser. * *

If you don't care which implementation you get, call {@link * XOMUtil#createDefaultParser} to create a parser.

* * @author jhyde * @since 2 August, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/Parser.java#4 $ **/ public interface Parser { /** * Sets whether to retain position information. * @param keepPositions Whether to keep position information. */ void setKeepPositions(boolean keepPositions); /** * Returns whether the parser is retaining position information. * * @return Whether to keep position information. */ boolean isKeepPositions(); /** * Parses a string and returns a wrapped element. * * @param sXml XML string * @return Wrapped element * @throws XOMException on error */ DOMWrapper parse(String sXml) throws XOMException; /** * Parses an input stream and returns a wrapped element. * * @param is Input stream * @return Wrapped element * @throws XOMException on error */ DOMWrapper parse(InputStream is) throws XOMException; /** * Parses the contents of a URL and returns a wrapped element. * * @param url URL * @return Wrapped element * @throws XOMException on error */ DOMWrapper parse(URL url) throws XOMException; /** * Parses the contents of a reader and returns a wrapped element. * * @param reader Reader * @return Wrapped element * @throws XOMException on error */ DOMWrapper parse(Reader reader) throws XOMException; /** * Creates a wrapper representing an XML element. * * @param tagName Name of element * @return Wrapper element */ DOMWrapper create(String tagName); } // End Parser.java resgen/src/org/eigenbase/xom/CommentDef.java0000444000175000017500000000402711543216467021236 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/CommentDef.java#3 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2000-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 11 October, 2001 */ package org.eigenbase.xom; import java.io.PrintWriter; /** * todo: * * @author jhyde * @since 11 October, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/CommentDef.java#3 $ **/ public class CommentDef extends TextDef { public CommentDef() { super(); } public CommentDef(String s) { super(s); } public CommentDef(DOMWrapper _def) throws XOMException { super(_def); } // override ElementDef public int getType() { return DOMWrapper.COMMENT; } // implement NodeDef public void display(PrintWriter pw, int indent) { pw.print(""); } // implement NodeDef public void displayXML(XMLOutput out, int indent) { out.beginNode(); out.print(""); } } // End CommentDef.java resgen/src/org/eigenbase/xom/Any.java0000444000175000017500000000263511543216467017747 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/Any.java#3 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 31 October, 2001 */ package org.eigenbase.xom; /** * An element which has 'Any' content. * * @author jhyde * @since 31 October, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/Any.java#3 $ **/ public interface Any { NodeDef[] getChildren(); void setChildren(NodeDef[] children); } // End Any.java resgen/src/org/eigenbase/xom/DOMElementParser.java0000444000175000017500000011174111543216467022325 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/DOMElementParser.java#6 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2000-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // dsommerfield, 6 November, 2000 */ package org.eigenbase.xom; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Vector; /** * DOMElementParser is a utility wrapper around DOMWrapper. * Implements a parseable stream of child DOMWrappers and also provides * validation on an XML document beyond the DTD. */ public class DOMElementParser { private DOMWrapper wrapper; private DOMWrapper[] children; private int currentIndex; private DOMWrapper currentChild; private int optionIndex; private String prefix; private Class enclosure; /** * Constructs a new ElementParser based on an Element of the XML parse * tree wrapped in a DOMWrapper, and a prefix (to be applied to all element * tags except the root), and the name of the enclosing class. * @param wrapper a DOMWrapper representing the section of the XML parse tree * to traverse. */ public DOMElementParser(DOMWrapper wrapper, String prefix, Class enclosure) throws XOMException { this.wrapper = wrapper; children = wrapper.getElementChildren(); currentIndex = 0; currentChild = null; getNextElement(); this.prefix = prefix; if (prefix == null) { this.prefix = ""; } this.enclosure = enclosure; } /** * Private helper function to retrieve the next child element in sequence. * @return the next element, or null if the enumerator has no more * elements to return. */ private void getNextElement() { if (currentIndex >= children.length) { currentChild = null; } else { currentChild = children[currentIndex++]; } } /** * Private helper function to verify that the next element matches a * specific name. * @param name name of the element to match. Names are not case-sensitive. * @throws XOMException if there is no current element or the names do * not match. */ private void requiredName(String name) throws XOMException { String augName = prefix + name; if (currentChild == null) { throw new XOMException( "Expected <" + augName + "> but found " + "nothing."); } else if (!augName.equalsIgnoreCase(currentChild.getTagName())) { throw new XOMException( "Expected <" + augName + "> but found <" + currentChild.getTagName() + ">"); } } /** * Private helper function to determine if the next element has the * specified name. * @return true if the next element's name matches name. Matching * is not case-sensitive. Returns false if there is no next element or * if the names don't match. */ private boolean optionalName(String name) { String augName = prefix + name; if (currentChild == null) { return false; } else if (augName.equalsIgnoreCase(currentChild.getTagName())) { return true; } else { return false; } } /** * Returns the enclosure class associated with clazz, or falls back on * the fixed enclosure if none can be found. */ private Class getEnclosureClass(Class clazz) { // Instead of using a fixed enclosure, derive it from the given Class. // If we can't figure it out, just use the given enclosure instead. Class thisEnclosure = enclosure; String className = clazz.getName(); int dollarPos = className.indexOf('$'); if (dollarPos >= 0) { String encName = className.substring(0, dollarPos); try { thisEnclosure = Class.forName(encName); } catch (ClassNotFoundException ex) { throw new AssertFailure("Enclosure class " + encName + " not found."); } } return thisEnclosure; } /** * Private helper function to determine if the next element's corresponding * definition class is a subclass of the given class. This may be used * to detect if a name matches a class. * @param clazz the class to match the next element against. * @return true if the next element's name matches the given class, false * otherwise. * @throws XOMException if the next name is invalid (either doesn't * start with DM or has no associated definition class). */ private boolean nameMatchesClass(Class clazz) throws XOMException { // Get the next name. It must start with the set prefix, and it must // match a definition in the enclosure class. Class thisEnclosure = getEnclosureClass(clazz); Class nextClass = ElementDef.getElementClass(currentChild, thisEnclosure, prefix); // Determine if nextClass is a subclass of clazz. Return true if so. return nextClass != null && clazz.isAssignableFrom(nextClass); } /** * This function retrieves a required String element from this parser, * advancing the parser after the read. * @param elementName the name of the element to retrieve. * @return the String value stored inside the element to retrieve. * @throws XOMException if there is no element with the given name. */ public String requiredString(String elementName) throws XOMException { requiredName(elementName); String retval = currentChild.getText().trim(); getNextElement(); return retval; } /** * This function retrieves an optional String element from this parser, * advancing the parser if the element is found. * If no element of the correct name is found, this function returns null. * @param elementName the name of the element to retrieve. * @return the String value stored inside the element to retrieve. */ public String optionalString(String elementName) throws XOMException { if (optionalName(elementName)) { String retval = currentChild.getText().trim(); getNextElement(); return retval; } else { return null; } } /** * This function retrieves a required Element from this parser, * advancing the parser after the read. * @param elementName the name of the element to retrieve. * @return the DOMWrapper to retrieve. * @throws XOMException if there is no element with the given name. */ public DOMWrapper requiredElement(String elementName) throws XOMException { requiredName(elementName); DOMWrapper prevWrapper = currentChild; getNextElement(); return prevWrapper; } /** * This function is used to return a CDATA section as text. It does * no parsing. * @return the contents of the CDATA element as text. */ public String getText() { return wrapper.getText().trim(); } /** * This function retrieves an optional Element from this parser, * advancing the parser if the element is found. * If no element of the correct name is found, this function returns null. * @param elementName the name of the element to retrieve. * @return the DOMWrapper to retreive, or null if none found. */ public DOMWrapper optionalElement(String elementName) throws XOMException { if (optionalName(elementName)) { DOMWrapper prevChild = currentChild; getNextElement(); return prevChild; } else { return null; } } /** * This private helper function formats a list of element names into * a readable string for error messages. */ private String formatOption(String[] elementNames) { StringBuffer sbuf = new StringBuffer(); for (int i = 0; i < elementNames.length; i++) { sbuf.append(""); if (i < elementNames.length - 1) { sbuf.append(" or "); } } return sbuf.toString(); } /** * This function retrieves a required element which may have one of a * number of names. The parser is advanced after the read. * @param elementNames an array of allowed names. Names are compared in * a case-insensitive fashion. * @return the first element with one of the given names. * @throws XOMException if there are no more elements to read or if * the next element's name is not in the elementNames list. */ public DOMWrapper requiredOption(String[] elementNames) throws XOMException { if (currentChild == null) { throw new XOMException("Expecting " + formatOption(elementNames) + " but found nothing."); } else { for (int i = 0; i < elementNames.length; i++) { String augName = "DM" + elementNames[i]; if (augName.equalsIgnoreCase( currentChild.getTagName().toString())) { DOMWrapper prevWrapper = currentChild; getNextElement(); optionIndex = i; return prevWrapper; } } // If we got here, no names match. throw new XOMException("Expecting " + formatOption(elementNames) + " but found <" + currentChild.getTagName() + ">."); } } /** * This function retrieves a required Element of a specific class * from this parser, advancing the parser after the read. * The class must be derived from ElementDef. */ public NodeDef requiredClass(Class classTemplate) throws XOMException { // The name must match the class. if (!nameMatchesClass(classTemplate)) { throw new XOMException("element <" + currentChild.getTagName() + "> does not match expected class " + classTemplate.getName()); } // Get the class corresponding to the current tag Class currentClass = ElementDef.getElementClass(currentChild, enclosure, prefix); // Get the element DOMWrapper prevWrapper = currentChild; getNextElement(); // Construct an ElementDef of the correct class from the element return ElementDef.constructElement(prevWrapper, currentClass); } /** * Returns the option index of the element returned through the last * requiredOption call. */ public int lastOptionIndex() { return optionIndex; } /** * This function retrieves a required Attribute by name from the * current Element. * @param attrName the name of the attribute. * @return the String value of the attribute. * @throws XOMException if no attribute of this name is set. */ public String requiredAttribute(String attrName) throws XOMException { Object attr = wrapper.getAttribute(attrName); if (attr == null) { throw new XOMException("Required attribute '" + attrName + "' is not set."); } return attr.toString(); } /** * This static version of requiredAttribute uses any element definition * as a basis for the attribute. It is used by Plugin definitions to * return attributes before the parser is created. * @param wrapper the Element in which to find the attribute. * @param attrName the name of the attribute to retrieve. * @param defaultVal the default value of the attribute to retrieve. * @throws XOMException if no attribute of this name is set. */ public static String requiredDefAttribute(DOMWrapper wrapper, String attrName, String defaultVal) throws XOMException { Object attr = wrapper.getAttribute(attrName); if (attr == null) { if (defaultVal == null) { throw new XOMException("Required attribute " + attrName + " is not set."); } else { return defaultVal; } } return attr.toString(); } /** * This function retrieves an optional Attribute by name from the * current Element. * @param attrName the name of the attribute. * @return the String value of the attribute, or null if the * attribute is not set. */ public String optionalAttribute(String attrName) throws XOMException { Object attr = wrapper.getAttribute(attrName); if (attr == null) { return null; } return attr.toString(); } /** * This function retrieves an optional Attribute by name from the * current Element, converting it to an Integer. * @param attrName the name of the attribute. * @return the Integer value of the attribute, or null if the * attribute is not set. * @throws XOMException if the value is set to an illegal * integer value. */ public Integer optionalIntegerAttribute(String attrName) throws XOMException { Object attr = wrapper.getAttribute(attrName); if (attr == null) { return null; } try { return new Integer(attr.toString()); } catch (NumberFormatException ex) { throw new XOMException("Illegal integer value \"" + attr.toString() + "\" for attribute " + attrName + ": " + ex.getMessage()); } } /** * This function retrieves an optional Attribute by name from the * current Element, converting it to a Double. * @param attrName the name of the attribute. * @return the Double value of the attribute, or null if the * attribute is not set. * @throws XOMException if the value is set to an illegal * double value. */ public Double optionalDoubleAttribute(String attrName) throws XOMException { Object attr = wrapper.getAttribute(attrName); if (attr == null) { return null; } try { return new Double(attr.toString()); } catch (NumberFormatException ex) { throw new XOMException("Illegal double value \"" + attr.toString() + "\" for attribute " + attrName + ": " + ex.getMessage()); } } /** * This function retrieves an required Attribute by name from the * current Element, converting it to an Integer. * @param attrName the name of the attribute. * @return the Integer value of the attribute. * @throws XOMException if the value is not set, or is set to * an illegal integer value. */ public Integer requiredIntegerAttribute(String attrName) throws XOMException { Object attr = wrapper.getAttribute(attrName); if (attr == null) { throw new XOMException("Required integer attribute " + attrName + " is not set."); } try { return new Integer(attr.toString()); } catch (NumberFormatException ex) { throw new XOMException("Illegal integer value \"" + attr.toString() + "\" for attribute " + attrName + ": " + ex.getMessage()); } } /** * This function retrieves an optional Attribute by name from the * current Element, converting it to an Boolean. The string value * "true" (in any case) is considered TRUE. Any other value is * considered false. * @param attrName the name of the attribute. * @return the Boolean value of the attribute, or null if the * attribute is not set. * @throws XOMException if the value is set to an illegal * integer value. */ public Boolean optionalBooleanAttribute(String attrName) throws XOMException { Object attr = wrapper.getAttribute(attrName); if (attr == null) { return null; } return new Boolean(attr.toString()); } /** * This function retrieves an required Attribute by name from the * current Element, converting it to a Boolean. The string value * "true" (in any case) is considered TRUE. Any other value is * considered false. * @param attrName the name of the attribute. * @return the Boolean value of the attribute. */ public Boolean requiredBooleanAttribute(String attrName) throws XOMException { Object attr = wrapper.getAttribute(attrName); if (attr == null) { throw new XOMException("Required boolean attribute " + attrName + " is not set."); } return new Boolean(attr.toString()); } /** * This function retrieves a collection of elements with the given name, * returning them as an array. * @param elemName the element name. * @param min the minimum number of elements required in the array. Set * this parameter to 0 to indicate no minimum. * @param max the maximum number of elements allowed in the array. Set * this parameter to 0 to indicate no maximum. * @return an Element array containing the discovered elements. * @throws XOMException if there are fewer than min or more than max * elements with the name elemName. */ public DOMWrapper[] optionalArray(String elemName, int min, int max) throws XOMException { // First, read the appropriate elements into a vector. Vector vec = new Vector(); String augName = "DM" + elemName; while (currentChild != null && augName.equalsIgnoreCase(currentChild.getTagName())) { vec.addElement(currentChild); getNextElement(); } // Now, check for size violations if (min > 0 && vec.size() < min) { throw new XOMException("Expecting at least " + min + " <" + elemName + "> but found " + vec.size()); } if (max > 0 && vec.size() > max) { throw new XOMException("Expecting at most " + max + " <" + elemName + "> but found " + vec.size()); } // Finally, convert to an array and return. DOMWrapper[] retval = new DOMWrapper[vec.size()]; for (int i = 0; i < retval.length; i++) { retval[i] = (DOMWrapper)(vec.elementAt(i)); } return retval; } /** * This function retrieves a collection of elements which are subclasses of * the given class, returning them as an array. The array will contain * ElementDef objects automatically constructed to be of the correct class. * @param elemClass the element class. * @param min the minimum number of elements required in the array. Set * this parameter to 0 to indicate no minimum. * @param max the maximum number of elements allowed in the array. Set * this parameter to 0 to indicate no maximum. * @return an ElementDef array containing the discovered elements. * @throws XOMException if there are fewer than min or more than max * elements with the name elemName. */ public NodeDef[] classArray(Class elemClass, int min, int max) throws XOMException { // Instead of using a fixed enclosure, derive it from the given Class. // If we can't figure it out, just use the given enclosure instead. Class thisEnclosure = getEnclosureClass(elemClass); // First, read the appropriate elements into a vector. Vector vec = new Vector(); while (currentChild != null && nameMatchesClass(elemClass)) { vec.addElement(currentChild); getNextElement(); } // Now, check for size violations if (min > 0 && vec.size() < min) { throw new XOMException("Expecting at least " + min + " <" + elemClass.getName() + "> but found " + vec.size()); } if (max > 0 && vec.size() > max) { throw new XOMException("Expecting at most " + max + " <" + elemClass.getName() + "> but found " + vec.size()); } // Finally, convert to an array and return. NodeDef[] retval = new NodeDef[vec.size()]; for (int i = 0; i < retval.length; i++) { retval[i] = ElementDef.constructElement((DOMWrapper)(vec.elementAt(i)), thisEnclosure, prefix); } return retval; } /** * This function retrieves an Element from this parser, advancing the * parser if the element is found. The Element's corresponding * ElementDef class is looked up and its constructor is called * automatically. If the requested Element is not found the function * returns null unless required is set to true. In this case, * a XOMException is thrown. * @param elementClass the Class of the element to retrieve. * @param required true to throw an exception if the element is not * found, false to simply return null. * @return the element, as an ElementDef, or null if it is not found * and required is false. * @throws XOMException if required is true and the element could not * be found. */ public NodeDef getElement(Class elementClass, boolean required) throws XOMException { // If current element is null, return null immediately if (currentChild == null) { return null; } // Check if the name matches the class if (!nameMatchesClass(elementClass)) { if (required) { throw new XOMException("element <" + currentChild.getTagName() + "> is not of expected type " + elementClass.getName()); } else { return null; } } // Get the class corresponding to the current tag. This will be // equal to elementClass if the current content was declared using // an Element, but not if the current content was declared using // a Class. Class thisEnclosure = getEnclosureClass(elementClass); Class currentClass = ElementDef.getElementClass(currentChild, thisEnclosure, prefix); // Get the element DOMWrapper prevChild = currentChild; getNextElement(); // Construct an ElementDef of the correct class from the element return ElementDef.constructElement(prevChild, currentClass); } /** * This function retrieves a collection of elements which are subclasses of * the given class, returning them as an array. The array will contain * ElementDef objects automatically constructed to be of the correct class. * @param elemClass the element class. * @param min the minimum number of elements required in the array. Set * this parameter to 0 to indicate no minimum. * @param max the maximum number of elements allowed in the array. Set * this parameter to 0 to indicate no maximum. * @return an ElementDef array containing the discovered elements. * @throws XOMException if there are fewer than min or more than max * elements with the name elemName. */ public NodeDef[] getArray(Class elemClass, int min, int max) throws XOMException { return classArray(elemClass, min, max); } /** * This function retrieves a String element from this parser, * advancing the parser if the element is found. * If no element of the correct name is found, this function returns null, * unless required is true, in which case a XOMException is thrown. * @param elementName the name of the element to retrieve. * @param required true to throw an exception if the element is not * found, false to simply return null. * @return the String value stored inside the element to retrieve, or * null if no element with the given elementName could be found. */ public String getString(String elementName, boolean required) throws XOMException { boolean found; if (required) { requiredName(elementName); found = true; } else { found = optionalName(elementName); } if (found) { String retval = currentChild.getText().trim(); getNextElement(); return retval; } else { return null; } } /** * This function returns a collection of String elements of the given * name, returning them as an array. * @param elemName the element name. * @param min the minimum number of elements required in the array. Set * this parameter to 0 to indicate no minimum. * @param max the maximum number of elements allowed in the array. Set * this parameter to 0 to indicate no maximum. * @return a String array containing the discovered elements. * @throws XOMException if there are fewer than min or more than max * elements with the name elemName. */ public String[] getStringArray(String elemName, int min, int max) throws XOMException { // First, read the appropriate elements into a vector. Vector vec = new Vector(); String augName = prefix + elemName; while (currentChild != null && augName.equalsIgnoreCase(currentChild.getTagName().toString())) { vec.addElement(currentChild); getNextElement(); } // Now, check for size violations if (min > 0 && vec.size() < min) { throw new XOMException("Expecting at least " + min + " <" + elemName + "> but found " + vec.size()); } if (max > 0 && vec.size() > max) { throw new XOMException("Expecting at most " + max + " <" + elemName + "> but found " + vec.size()); } // Finally, convert to an array, retrieve the text from each // element, and return. String[] retval = new String[vec.size()]; for (int i = 0; i < retval.length; i++) { retval[i] = ((DOMWrapper)(vec.elementAt(i))).getText().trim(); } return retval; } // Determine if a String is present anywhere in a given array. private boolean stringInArray(String str, String[] array) { for (int i = 0; i < array.length; i++) { if (str.equals(array[i])) { return true; } } return false; } // Convert an array of Strings into a single String for display. private String arrayToString(String[] array) { StringBuffer sbuf = new StringBuffer(); sbuf.append("{"); for (int i = 0; i < array.length; i++) { sbuf.append(array[i]); if (i < array.length - 1) { sbuf.append(", "); } } sbuf.append("}"); return sbuf.toString(); } /** * Get a Class object representing a plugin class, identified either * directly by a Java package and Java class name, or indirectly * by a Java package and Java class which defines a method called * getXMLDefClass() to return the appropriate class. * @param packageName the name of the Java package containing the * plugin class. * @param className the name of the plugin definition class. * @throws XOMException if the plugin class cannot be located * or if the designated class is not suitable as a plugin class. */ public static Class getPluginClass(String packageName, String className) throws XOMException { Class managerClass = null; try { managerClass = Class.forName(packageName + "." + className); } catch (ClassNotFoundException ex) { throw new XOMException("Unable to locate plugin class " + packageName + "." + className + ": " + ex.getMessage()); } return getPluginClass(managerClass); } /** * Get a Class object representing a plugin class, given a manager * class that implements the static method getXMLDefClass(). * @param managerClass any Class that implements getXMLDefClass. * @return the plugin Class. */ public static Class getPluginClass(Class managerClass) throws XOMException { // Look for a static method called getXMLDefClass which returns // type Class. If we find this method, call it to produce the // actual plugin class. Otherwise, throw an exception; the // class we selected is inappropriate. Method[] methods = managerClass.getMethods(); for (int i = 0; i < methods.length; i++) { // Must be static, take no args, and return Class. if (methods[i].getParameterTypes().length != 0) { continue; } if (!(methods[i].getReturnType() == Class.class)) { continue; } if (!(Modifier.isStatic(methods[i].getModifiers()))) { continue; } // Invoke the method here. try { Object[] args = new Object[0]; return (Class)(methods[i].invoke(null, args)); } catch (InvocationTargetException ex) { throw new XOMException("Exception while retrieving " + "plugin class: " + ex.getTargetException().toString()); } catch (IllegalAccessException ex) { throw new XOMException("Illegal access while retrieving " + "plugin class: " + ex.getMessage()); } } // Class is inappropriate. throw new XOMException("Plugin class " + managerClass.getName() + " is not an appropriate plugin class; " + "getXMLDefClass() is not defined."); } /** * Retrieve an Attribute from the parser. The Attribute may be of any * Java class, provided that the class supports a constructor from the * String class. The Attribute's value will be returned as an Object, * which must then be cast to the appropraite type. If the attribute * is not defined and has no default, either null is returned (if * required is false), or a XOMException is thrown (if required is * true). * @param attrName the name of the attribute to retreive. * @param attrType a String naming a Java Class to serve as the type. * If attrType contains a "." character, the class is looked up directly * from the type name. Otherwise, the class is looked up in the * java.lang package. Finally, the class must have a constructor which * takes a String as an argument. * @param defaultValue the default value for this attribute. If values * is set, the defaultValue must also be one of the set of values. * defaultValue may be null. * @param values an array of possible values for the attribute. If * this parameter is not null, then the attribute's value must be one * of the listed set of values or an exception will be thrown. * @param required if set, then this function will throw an exception * if the attribute has no value and defaultValue is null. * @return the Attribute's value as an Object. The actual class of * this object is determined by attrType. */ public Object getAttribute(String attrName, String attrType, String defaultValue, String[] values, boolean required) throws XOMException { // Retrieve the attribute type class if (attrType.indexOf('.') == -1) { attrType = "java.lang." + attrType; } Class typeClass = null; try { typeClass = Class.forName(attrType); } catch (ClassNotFoundException ex) { throw new XOMException("Class could not be found for attribute " + "type: " + attrType + ": " + ex.getMessage()); } // Get a constructor from the type class which takes a String as // input. If one does not exist, throw an exception. Class[] classArray = new Class[1]; classArray[0] = java.lang.String.class; Constructor stringConstructor = null; try { stringConstructor = typeClass.getConstructor(classArray); } catch (NoSuchMethodException ex) { throw new XOMException("Attribute type class " + attrType + " does not have a " + "constructor which takes a String: " + ex.getMessage()); } // Get the Attribute of the given name Object attrVal = wrapper.getAttribute(attrName); if (attrVal == null) { attrVal = defaultValue; } // Check for null if (attrVal == null) { if (required) { throw new XOMException( "Attribute '" + attrName + "' is unset and has no default value."); } else { return null; } } // Make sure it is on the list of acceptable values if (values != null) { if (!stringInArray(attrVal.toString(), values)) { throw new XOMException( "Value '" + attrVal.toString() + "' of attribute '" + attrName + "' has illegal value '" + attrVal + "'. Legal values: " + arrayToString(values)); } } // Invoke the constructor to get the final object Object[] args = new Object[1]; args[0] = attrVal.toString(); try { return stringConstructor.newInstance(args); } catch (InstantiationException ex) { throw new XOMException( "Unable to construct a " + attrType + " from value \"" + attrVal + "\": " + ex.getMessage()); } catch (InvocationTargetException ex) { throw new XOMException( "Unable to construct a " + attrType + " from value \"" + attrVal + "\": " + ex.getMessage()); } catch (IllegalAccessException ex) { throw new XOMException( "Unable to construct a " + attrType + " from value \"" + attrVal + "\": " + ex.getMessage()); } } } // End DOMElementParser.java resgen/src/org/eigenbase/xom/DOMWrapper.java0000444000175000017500000001011111543216467021164 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/DOMWrapper.java#4 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // dsommerfield, 16 July, 2001 */ package org.eigenbase.xom; /** * DOMWrapper implements a Wrapper around the Element class from any DOM-style * XML parser. The wrapper is used to isolate ElementParser, ElementDef, and * all ElementDef subclasses from the specifics of the underlying XML * parser. */ public interface DOMWrapper { /** * UNKNOWN is used for DOM Element types unsupported by the * wrapper. */ public static final int UNKNOWN = 0; /** * FREETEXT is a type of DOM Element representing a piece of text (but not * a CDATA section). For example, Some text. FREETEXT * elements always have a tag name of NULL and have no children. It * maps to a {@link TextDef}. **/ public static final int FREETEXT = 1; /** * ELEMENT is a type of DOM Element representing a named tag, possibly * containing attributes, child elements, and text. It maps to a {@link * ElementDef} (or a generated class derived from it), or a {@link * GenericDef}. **/ public static final int ELEMENT = 2; /** * COMMENT is a type of DOM Element representing an XML comment. It maps * to a {@link CommentDef}. **/ public static final int COMMENT = 3; /** * CDATA is a type of DOM Element representing a piece of text embedded in * a CDATA section, for example, * <![CDATA[Some text]]>. * CDATA elements always have a tag name of NULL and have no children. It * maps to a {@link CdataDef}. **/ public static final int CDATA = 4; /** * Returns the type of this element/node. DOMWrapper supports only four * possibilities: {@link #FREETEXT}, {@link #ELEMENT}, {@link #COMMENT}, * {@link #CDATA}. */ public int getType(); /** * Returns the tag name of this element, or null for TEXT elements. */ public String getTagName(); /** * Returns the value of the attribute with the given attrName. If the * attribute is not defined, this method returns null. */ public String getAttribute(String attrName); /** * Returns a list of attribute names. **/ public String[] getAttributeNames(); /** * Returns a flattened representation of the text inside thie element. * For a TEXT element, this returns the text itself. For an ELEMENT * element, this returns all pieces of text within the element, * with all markup removed. */ public String getText(); /** * Returns this node serialized as XML. **/ public String toXML(); /** * Returns all children of this element, including TEXT elements, as * an array of DOMWrappers. */ public DOMWrapper[] getChildren(); /** * Returns all element children of this element as an array of * DOMWrappers. */ public DOMWrapper[] getElementChildren(); /** * Returns the location of this element. */ public Location getLocation(); } // End DOMWrapper.java resgen/src/org/eigenbase/xom/XMLAttrVector.java0000444000175000017500000001130711543216467021672 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/XMLAttrVector.java#3 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2000-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // dsommerfield, 12 December, 2000 */ package org.eigenbase.xom; import java.io.PrintWriter; import java.util.Vector; /** * XMLAttrVector is an class which assists in writing XML attributes to a * stream. */ public class XMLAttrVector { // Vector to hold all attributes and their values. private Vector attrs; /** * This private helper class holds an attribute-value pair. It is used * as the element of the vector attrs. */ private static class AttrVal { public AttrVal(String attr, String val) { this.attr = attr; this.val = val; } public String attr; public String val; } /** * Construct an empty XMLAttrVector. Attribute/value pairs may be added * with the add() functions below. */ public XMLAttrVector() { attrs = new Vector(); } /** * Returns the number of attributes. **/ public int size() { return attrs.size(); } /** * Add a new attribute/value pair based on a String value. Note that * attrVal may be null, in which case no attribute/value pair is added. * @param attrName the name of the attribute. * @param attrVal the String value of the attribute. * @return this (to allow chaining) */ public XMLAttrVector add(String attrName, Object attrVal) { if(attrVal != null) attrs.addElement(new AttrVal(attrName, attrVal.toString())); return this; } /** * Add a new attribute/value pair based on an int value. * @param attrName the name of the attribute. * @param attrVal the int value of the attribute. * @return this (to allow chaining) */ public XMLAttrVector add(String attrName, int attrVal) { attrs.addElement(new AttrVal(attrName, ""+attrVal)); return this; } /** * Add a new attribute/value pair based on a double value. * @param attrName the name of the attribute. * @param attrVal the double value of the attribute. * @return this (to allow chaining) */ public XMLAttrVector add(String attrName, double attrVal) { attrs.addElement(new AttrVal(attrName, ""+attrVal)); return this; } /** * Add a new attribute/value pair based on a boolean value. * True is represented as "true", and false as "false". * @param attrName the name of the attribute. * @param attrVal the boolean value of the attribute. * @return this (to allow chaining) */ public XMLAttrVector add(String attrName, boolean attrVal) { if(attrVal) attrs.addElement(new AttrVal(attrName, "true")); else attrs.addElement(new AttrVal(attrName, "false")); return this; } /** * Displays the entire attribute/value pair list, given a PrintWriter * to which to display and an indentation level. * This function is typically called from XMLOutput. * @param out PrintWriter to which to write output. * @param indent indentation level. */ public void display(PrintWriter out, int indent) { // The indentation level is not used; all attribute/value pairs // are rendered on the same line. for(int i=0; iCdataDef represents a CDATA element. It allows an * <Any> element to have mixed children. * * @author jhyde * @since 3 October, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/CdataDef.java#3 $ **/ public class CdataDef extends TextDef { public CdataDef() { super(); } public CdataDef(String s) { super(s); } public CdataDef(DOMWrapper _def) throws org.eigenbase.xom.XOMException { super(_def); } // implement NodeDef public int getType() { return DOMWrapper.CDATA; } // override NodeDef public void displayXML(XMLOutput out, int indent) { out.beginNode(); out.cdata(s, true); } } // End CdataDef.java resgen/src/org/eigenbase/xom/XMLOutput.java0000444000175000017500000003210411543216467021073 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/XMLOutput.java#5 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2008 The Eigenbase Project // Copyright (C) 2005-2008 Disruptive Tech // Copyright (C) 2005-2008 LucidEra, Inc. // Portions Copyright (C) 2000-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // dsommerfield, 12 December, 2000 */ package org.eigenbase.xom; import java.io.*; import java.util.Vector; /** * XMLOutput is a class which implements streaming XML output. Use this class * to write XML to any streaming source. While the class itself is * unstructured and doesn't enforce any DTD specification, use of the class * does ensure that the output is syntactically valid XML. */ public class XMLOutput { // This Writer is the underlying output stream to which all XML is // written. private PrintWriter out; // The tagStack is maintained to check that tags are balanced. private Vector tagStack; // The class maintains an indentation level to improve output quality. private int indent; // The class also maintains the total number of tags written. This // is used to monitor changes to the output private int tagsWritten; // This flag is set to true if the output should be compacted. // Compacted output is free of extraneous whitespace and is designed // for easier transport. private boolean compact; /** @see setIndentString **/ private String indentString = "\t"; /** @see setGlob **/ private boolean glob; /** * Whether we have started but not finished a start tag. This only happens * if glob is true. The start tag is automatically closed * when we start a child node. If there are no child nodes, {@link #endTag} * creates an empty tag. **/ private boolean inTag; /** @see #setAlwaysQuoteCData */ private boolean alwaysQuoteCData; /** @see #setIgnorePcdata **/ private boolean ignorePcdata; /** * Private helper function to display a degree of indentation * @param out the PrintWriter to which to display output. * @param indent the degree of indentation. */ private void displayIndent(PrintWriter out, int indent) { if(!compact) { for (int i = 0; i < indent; i++) { out.print(indentString); } } } /** * Constructs a new XMLOutput based on any Writer. * @param out the writer to which this XMLOutput generates results. */ public XMLOutput(Writer out) { this.out = new PrintWriter(out, true); indent = 0; tagsWritten = 0; tagStack = new Vector(); } /** * Sets or unsets the compact mode. Compact mode causes the generated * XML to be free of extraneous whitespace and other unnecessary * characters. * * @param compact true to turn on compact mode, or false to turn it off. */ public void setCompact(boolean compact) { this.compact = compact; } public boolean getCompact() { return compact; } /** * Sets the string to print for each level of indentation. The default is a * tab. The value must not be null. Set this to the empty * string to achieve no indentation (note that {@link * #setCompact}(true) removes indentation and newlines). **/ public void setIndentString(String indentString) { this.indentString = indentString; } /** * Sets whether to detect that tags are empty. **/ public void setGlob(boolean glob) { this.glob = glob; } /** * Sets whether to always quote cdata segments (even if they don't contain * special characters). **/ public void setAlwaysQuoteCData(boolean alwaysQuoteCData) { this.alwaysQuoteCData = alwaysQuoteCData; } /** * Sets whether to ignore unquoted text, such as whitespace. **/ public void setIgnorePcdata(boolean ignorePcdata) { this.ignorePcdata = ignorePcdata; } public boolean getIgnorePcdata() { return ignorePcdata; } /** * Sends a string directly to the output stream, without escaping any * characters. Use with caution! **/ public void print(String s) { out.print(s); } /** * Start writing a new tag to the stream. The tag's name must be given and * its attributes should be specified by a fully constructed AttrVector * object. * @param tagName the name of the tag to write. * @param attributes an XMLAttrVector containing the attributes to include * in the tag. */ public void beginTag(String tagName, XMLAttrVector attributes) { beginBeginTag(tagName); if (attributes != null) { attributes.display(out, indent); } endBeginTag(tagName); } public void beginBeginTag(String tagName) { if (inTag) { // complete the parent's start tag if (compact) { out.print(">"); } else { out.println(">"); } inTag = false; } displayIndent(out, indent); out.print("<"); out.print(tagName); } public void endBeginTag(String tagName) { if (glob) { inTag = true; } else if (compact) { out.print(">"); } else { out.println(">"); } out.flush(); tagStack.addElement(tagName); indent++; tagsWritten++; } /** * Write an attribute. **/ public void attribute(String name, String value) { XMLUtil.printAtt(out, name, value); } /** * If we are currently inside the start tag, finish it off. **/ public void beginNode() { if (inTag) { // complete the parent's start tag if (compact) { out.print(">"); } else { out.println(">"); } inTag = false; } } /** * Complete a tag. This outputs the end tag corresponding to the * last exposed beginTag. The tag name must match the name of the * corresponding beginTag. * @param tagName the name of the end tag to write. */ public void endTag(String tagName) { // Check that the end tag matches the corresponding start tag int stackSize = tagStack.size(); String matchTag = (String)(tagStack.elementAt(stackSize-1)); if(!tagName.equalsIgnoreCase(matchTag)) throw new AssertFailure( "End tag <" + tagName + "> does not match " + " start tag <" + matchTag + ">"); tagStack.removeElementAt(stackSize-1); // Lower the indent and display the end tag indent--; if (inTag) { // we're still in the start tag -- this element had no children if (compact) { out.print("/>"); } else { out.println("/>"); } inTag = false; } else { displayIndent(out, indent); out.print(""); } else { out.println(">"); } } out.flush(); } /** * Write an empty tag to the stream. An empty tag is one with no * tags inside it, although it may still have attributes. * @param tagName the name of the empty tag. * @param attributes an XMLAttrVector containing the attributes to * include in the tag. */ public void emptyTag(String tagName, XMLAttrVector attributes) { if (inTag) { // complete the parent's start tag if (compact) { out.print(">"); } else { out.println(">"); } inTag = false; } displayIndent(out, indent); out.print("<"); out.print(tagName); if(attributes != null) { out.print(" "); attributes.display(out, indent); } if(compact) out.print("/>"); else out.println("/>"); out.flush(); tagsWritten++; } /** * Write a CDATA section. Such sections always appear on their own line. * The nature in which the CDATA section is written depends on the actual * string content with respect to these special characters/sequences: *
    *
  • & *
  • " *
  • ' *
  • < *
  • > *
* Additionally, the sequence ]]> is special. *
    *
  • Content containing no special characters will be left as-is. *
  • Content containing one or more special characters but not the * sequence ]]> will be enclosed in a CDATA section. *
  • Content containing special characters AND at least one * ]]> sequence will be left as-is but have all of its * special characters encoded as entities. *
* These special treatment rules are required to allow cdata sections * to contain XML strings which may themselves contain cdata sections. * Traditional CDATA sections do not nest. */ public void cdata(String data) { cdata(data, false); } /** * Writes a CDATA section (as {@link #cdata(String)}). * * @param data string to write * @param quote if true, quote in a <![CDATA[ * ... ]]> regardless of the content of * data; if false, quote only if the content needs it **/ public void cdata(String data, boolean quote) { if (inTag) { // complete the parent's start tag if (compact) { out.print(">"); } else { out.println(">"); } inTag = false; } if (data == null) { data = ""; } boolean specials = false; boolean cdataEnd = false; // Scan the string for special characters // If special characters are found, scan the string for ']]>' if(XOMUtil.stringHasXMLSpecials(data)) { specials = true; if(data.indexOf("]]>") > -1) cdataEnd = true; } // Display the result displayIndent(out, indent); if (quote || alwaysQuoteCData) { out.print(""); } else if (!specials && !cdataEnd) { out.print(data); } else { XMLUtil.stringEncodeXML(data, out); } out.flush(); tagsWritten++; } /** * Write a String tag; a tag containing nothing but a CDATA section. */ public void stringTag(String name, String data) { beginTag(name, null); cdata(data); endTag(name); } /** * Write content. */ public void content(String content) { if(content != null) { indent++; LineNumberReader in = new LineNumberReader(new StringReader(content)); try { String line; while((line = in.readLine()) != null) { displayIndent(out, indent); out.println(line); } } catch (IOException ex) { throw new AssertFailure(ex); } indent--; out.flush(); } tagsWritten++; } /** * Write header. Use default version 1.0. */ public void header() { out.println(""); out.flush(); tagsWritten++; } /** * Write header, take version as input. */ public void header(String version) { out.print(""); out.flush(); tagsWritten++; } /** * Get the total number of tags written * @return the total number of tags written to the XML stream. */ public int numTagsWritten() { return tagsWritten; } } // End XMLOutput.java resgen/src/org/eigenbase/xom/ElementDef.java0000444000175000017500000010274311543216467021231 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/ElementDef.java#5 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2000-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // dsommerfield, 6 November, 2000 */ package org.eigenbase.xom; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.*; /** * ElementDef is the base class for all element definitions. It specifies the * basic interface as well as provides useful services for all elements. **/ public abstract class ElementDef implements NodeDef, Serializable, Cloneable { /** * getElementClass is a static helper function which finds the XMLDef class * corresponding to an Element. The Element's tag must start with the * given prefix name, and * the remainder of the tag must correspond to a static inner class of * the given enclosing class. * @param wrapper the DOMWrapper whose class to look up. * @param enclosure a Class which encloses the Class to lookup. * @param prefix a prefix which must appear on the tag name. * @return the ElementDef Class corresponding to the element, or null if no * class could be found (possible if this is a String element. */ public static Class getElementClass(DOMWrapper wrapper, Class enclosure, String prefix) throws XOMException { if (enclosure == null) { // don't try to find a class -- they will use GenericDef return null; } // wrapper must be of ELEMENT type. If not, throw a XOMException. if (wrapper.getType() != DOMWrapper.ELEMENT) { throw new XOMException("DOMWrapper must be of ELEMENT type."); } // Retrieve the tag name. It must start with the prefix. String tag = wrapper.getTagName(); if (prefix == null) { prefix = ""; } else if (!tag.startsWith(prefix)) { throw new XOMException( "Element names must start " + "\"" + prefix + "\": " + tag + " is invalid."); } // Remove the prefix and look for the name in the _elements field // of the enclosure class. Note that the lookup is case-sensitive // even though XML tags are not. String className = tag.substring(prefix.length(), tag.length()); className = XOMUtil.capitalize(className); Class elemClass = null; try { elemClass = Class.forName(enclosure.getName() + "$" + className); } catch (ClassNotFoundException ex) { return null; } return elemClass; } /** * constructElement is a helper function which builds the appropriate type * of ElementDef from an XML Element. This version of the function takes * an Element and a Class object specifying the exact class to use in * constructing the element. * * @param wrapper the DOM Element wrapper from which to build this class. * @param elemClass the Class to use to construct this class. It must have * a constructor which takes the Element type. * @return a fully constructed ElementDef of the type specified by * Class. * @throws XOMException if clazz has no constructor which takes Element, * or if construction fails. */ public static NodeDef constructElement(DOMWrapper wrapper, Class elemClass) throws XOMException { // Find a constructor of this class which takes an "Element" object Constructor[] constructors = elemClass.getDeclaredConstructors(); Constructor elemConstructor = null; for (int i = 0; i < constructors.length; i++) { Class[] params = constructors[i].getParameterTypes(); if (params.length == 1 && params[0] == DOMWrapper.class) { elemConstructor = constructors[i]; break; } } if (elemConstructor == null) { throw new XOMException( "No constructor taking class DOMWrapper " + "could be found in class " + elemClass.getName()); } // Call the constructor to instantiate the object Object[] args = new Object[1]; args[0] = wrapper; try { return (ElementDef)(elemConstructor.newInstance(args)); } catch (InstantiationException ex) { throw new XOMException("Unable to instantiate object of class " + elemClass.getName() + ": " + ex.getMessage()); } catch (InvocationTargetException ex) { // the Element constructor can only throw XOMException or // RuntimeException or Error, so cast to whichever type is appropriate // and throw here. Throwable target = ex.getTargetException(); if (target instanceof XOMException) { throw (XOMException) target; } else if (target instanceof RuntimeException) { throw (RuntimeException) target; } else if (target instanceof Error) { throw (Error) target; } else { throw new XOMException( "Unexpected exception while " + "instantiating object: " + target.toString()); } } catch (IllegalAccessException ex) { throw new XOMException("Unable to instantiate object of class " + elemClass.getName() + ": " + ex.getMessage()); } } /** * constructElement is a helper function which builds the appropriate type * of ElementDef from an XML Element. This function should be used when * creating an ElementDef from a list of optional XML element types using * ElementParser.requiredOption. Generally, it is better to call the * constructors of ElementDef subclasses directly if the exact type of * an element is known. * @param wrapper the DOM Element Wrapper from which to build this class. * @return an ElementDef whose exact type depends on the tag name of the * element definition. * @throws XOMException if no subclass of ElementDef can be found, * or if def is malformed. */ public static NodeDef constructElement( DOMWrapper wrapper, Class enclosure, String prefix) throws XOMException { switch (wrapper.getType()) { case DOMWrapper.ELEMENT: Class elemClass = getElementClass(wrapper, enclosure, prefix); if (elemClass == null) { if (true) { return new WrapperElementDef(wrapper, enclosure, prefix); } else { throw new XOMException("No class corresponding to element " + wrapper.getTagName() + " could be found in enclosure " + enclosure.getName()); } } else { return constructElement(wrapper, elemClass); } case DOMWrapper.COMMENT: return new CommentDef(wrapper.getText()); case DOMWrapper.CDATA: return new CdataDef(wrapper.getText()); case DOMWrapper.FREETEXT: return new TextDef(wrapper.getText()); default: throw new XOMException("Unknown type: " + wrapper.getText()); } } // implement NodeDef public void displayXML(XMLOutput out, int indent) {} public void displayXML(XMLOutput out) { displayXML(out, 0); } /** * The displayDiff function compares this element definition against another, * compiling a message containing all diffs. It is used internally by * the equals(), diff(), and verifyEquals() functions. * @param other the ElementDef to which to compare this element. * @param out a PrintWriter to which to display any discovered differences, * or null if just doing an equality check (and no diff report is needed). * @param indent the current indentation level (used for nice display of diffs). * @return true if this and other match exactly, false if not. */ public boolean displayDiff(ElementDef other, PrintWriter out, int indent) { return false; } // implement NodeDef public String getName() { return getClass().getName(); } // implement NodeDef public int getType() { return DOMWrapper.ELEMENT; } // implement NodeDef public String getText() { return null; } /** * This function writes an indentation level to the given PrintWriter. * @param out the PrintWriter to which to write the indent. * @param indent the indentation level */ protected static void displayIndent(PrintWriter out, int indent) { for (int i = 0; i < indent; i++) { out.print(" "); } } /** * This convenience function displays a String value with the given * parameter name at the given indentation level. It is meant to be * called by subclasses of ElementDef. * @param out the PrintWriter to which to write this String. * @param name the parameter name of this string. * @param value the value of the String parameter. * @param indent the indentation level. */ protected static void displayString( PrintWriter out, String name, String value, int indent) { displayIndent(out, indent); if (value == null) { out.println(name + ": null"); } else { out.println(name + ": \"" + value + "\""); } } /** * This convenience function displays an XML attribute value * with the given attribute name at the given indentation level. * It should be called by subclasses of ElementDef. * @param out the PrintWriter to which to write this String. * @param name the attribute name. * @param value the attribute value. * @param indent the indentation level. */ protected static void displayAttribute( PrintWriter out, String name, Object value, int indent) { displayIndent(out, indent); if (value == null) { out.println(name + " = null"); } else { out.println(name + " = \"" + value.toString() + "\""); } } /** * This convenience function displays any ElementDef with the given * parameter name at the given indentation level. * @param out the PrintWriter to which to write this ElementDef. * @param name the parameter name for this ElementDef. * @param value the parameter's value (as an ElementDef). * @param indent the indentation level. */ protected static void displayElement( PrintWriter out, String name, ElementDef value, int indent) { displayIndent(out, indent); if (value == null) { out.println(name + ": null"); } else { out.print(name + ": "); value.display(out, indent); } } /** * This convenience function displays any array of ElementDef values with * the given parameter name (assumed to represent an array) at the given * indentation level. Each value of the array will be written on a * separate line with a new indentation. * @param out the PrintWriter to which to write this ElementDef. * @param name the parameter name for this ElementDef. * @param values the parameter's values (as an ElementDef[] array). * @param indent the indentation level. */ protected static void displayElementArray( PrintWriter out, String name, NodeDef[] values, int indent) { displayIndent(out, indent); if (values == null) { out.println(name + ": null array"); } else { out.println(name + ": array of " + values.length + " values"); for (int i = 0; i < values.length; i++) { displayIndent(out, indent); if (values[i] == null) { out.println(name + "[" + i + "]: null"); } else { out.print(name + "[" + i + "]: "); values[i].display(out, indent); } } } } /** * This convenience function displays any array of String values with * the given parameter name (assumed to represent an array) at the given * indentation level. Each value of the array will be written on a * separate line with a new indentation. * @param out the PrintWriter to which to write this ElementDef. * @param name the parameter name for this ElementDef. * @param values the parameter's values (as a String[] array). * @param indent the indentation level. */ protected static void displayStringArray( PrintWriter out, String name, String[] values, int indent) { displayIndent(out, indent); if (values == null) { out.println(name + ": null array"); } else { out.println(name + ": array of " + values.length + " values"); for (int i = 0; i < values.length; i++) { displayIndent(out, indent); if (values[i] == null) { out.println(name + "[" + i + "]: null"); } else { out.println(name + "[" + i + "]: " + values[i]); } } } } /** * This convenience function displays a String value in XML. * parameter name at the given indentation level. It is meant to be * called by subclasses of ElementDef. * @param out XMLOutput class to which to generate XML. * @param tag the Tag name of this String object. * @param value the String value. */ protected static void displayXMLString( XMLOutput out, String tag, String value) { if (value != null) { out.stringTag(tag, value); } } /** * This convenience function displays any ElementDef in XML. * @param out the XMLOutput class to which to generate XML. * @param value the ElementDef to display. */ protected static void displayXMLElement( XMLOutput out, ElementDef value) { if (value != null) { value.displayXML(out, 0); } } /** * This convenience function displays an array of ElementDef values in XML. * @param out the XMLOutput class to which to generate XML. * @param values the ElementDef to display. */ protected static void displayXMLElementArray( XMLOutput out, NodeDef[] values) { if (values != null) { for (int i = 0; i < values.length; i++) { values[i].displayXML(out, 0); } } } /** * This convenience function displays a String array in XML. * @param out the XMLOutput class to which to generate XML. * @param tag the tag name for the String elements. * @param values the actual string values. */ protected static void displayXMLStringArray( XMLOutput out, String tag, String[] values) { for (int i = 0; i < values.length; i++) { out.stringTag(tag, values[i]); } } /** * This convenience function displays differences in two versions of * the same string object. * @param name the object name. * @param value1 the first string. * @param value2 the second string. * @param out the PrintWriter to which to write differences. * @param indent the indentation level. * @return true if the strings match, false if not. */ protected static boolean displayStringDiff( String name, String value1, String value2, PrintWriter out, int indent) { // True if both values are null. if (value1 == null && value2 == null) { return true; } // Deal with the cases where one value is set but the other is not. if (value2 == null) { if (out != null) { displayIndent(out, indent); out.println("String " + name + ": mismatch: " + value1.toString() + " vs null."); } return false; } if (value1 == null) { if (out != null) { displayIndent(out, indent); out.println("String " + name + ": mismatch: " + "null vs " + value2.toString() + "."); } return false; } // Finally, check the values themselves if (value1.equals(value2)) { return true; } if (out != null) { displayIndent(out, indent); out.println("String " + name + ": mismatch: " + value1.toString() + " vs " + value2.toString() + "."); } return false; } /** * This convenience function displays differences in two versions of * the same XML attribute value. * @param name the attribute name. * @param value1 the first attribute value. * @param value2 the second attribute value. * @param out the PrintWriter to which to write differences. * @param indent the indentation level. * @return true if the values match, false if not. */ protected static boolean displayAttributeDiff( String name, Object value1, Object value2, PrintWriter out, int indent) { // True if both values are null. if (value1 == null && value2 == null) { return true; } // Deal with the cases where one value is set but the other is not. if (value2 == null) { if (out != null) { displayIndent(out, indent); out.println("Attribute " + name + ": mismatch: " + value1.toString() + " vs null."); } return false; } if (value1 == null) { if (out != null) { displayIndent(out, indent); out.println("Attribute " + name + ": mismatch: " + "null vs " + value2.toString() + "."); } return false; } // Verify that types match if (value1.getClass() != value2.getClass()) { if (out != null) { displayIndent(out, indent); out.println("Attribute " + name + ": class mismatch: " + value1.getClass().getName() + " vs " + value2.getClass().getName() + "."); } return false; } // Finally, check the values themselves if (value1.equals(value2)) { return true; } if (out != null) { displayIndent(out, indent); out.println("Attribute " + name + ": mismatch: " + value1.toString() + " vs " + value2.toString() + "."); } return false; } /** * This convenience function displays differences in the values of any * two ElementDefs, returning true if they match and false if not. * @param name the object name. * @param value1 the first value. * @param value2 the second value. * @param out the PrintWriter to which to write differences. * @param indent the indentation level. * @return true if the values match, false if not. */ protected static boolean displayElementDiff( String name, NodeDef value1, NodeDef value2, PrintWriter out, int indent) { // True if both values are null. if (value1 == null && value2 == null) { return true; } // Deal with the cases where one value is set but the other is not. if (value2 == null) { if (out != null) { displayIndent(out, indent); out.println("Object " + name + ": mismatch: " + "(...) vs null."); } return false; } if (value1 == null) { if (out != null) { displayIndent(out, indent); out.println("Object " + name + ": mismatch: " + "null vs (...)."); } return false; } // Verify that types match if (value1.getClass() != value2.getClass()) { if (out != null) { displayIndent(out, indent); out.println("Object " + name + ": class mismatch: " + value1.getClass().getName() + " vs " + value2.getClass().getName() + "."); } return false; } // Do a sub equality check return ((ElementDef) value1).displayDiff( (ElementDef) value2, out, indent); } /** * This convenience function diffs any array of ElementDef values with * the given array name. All differences are written to the given * PrintWriter at the given indentation level. * @param name the array name. * @param values1 the first array. * @param values2 the second array. * @param out the PrintWriter to which to write differences. * @param indent the indentation level. * @return true if the both arrays match, false if there are any differences. */ protected static boolean displayElementArrayDiff( String name, NodeDef[] values1, NodeDef[] values2, PrintWriter out, int indent) { int length1 = 0; int length2 = 0; if (values1 != null) { length1 = values1.length; } if (values2 != null) { length2 = values2.length; } // Check array sizes // a null array does not differ from an empty array if (length1 != length2) { if (out != null) { displayIndent(out, indent); out.println("Array " + name + ": size mismatch: " + length1 + " vs " + length2 + "."); } return false; } // Check each member of the array boolean diff = true; for (int i = 0; i < length1; i++) { diff = diff && displayElementDiff( name + "[" + i + "]", values1[i], values2[i], out, indent); } return diff; } /** * This convenience function diffs any array of strings with * the given array name. All differences are written to the given * PrintWriter at the given indentation level. * @param name the array name. * @param values1 the first array. * @param values2 the second array. * @param out the PrintWriter to which to write differences. * @param indent the indentation level. * @return true if the both arrays match, false if there are any differences. */ protected static boolean displayStringArrayDiff( String name, String[] values1, String[] values2, PrintWriter out, int indent) { // Check array sizes if (values1.length != values2.length) { if (out != null) { displayIndent(out, indent); out.println("Array " + name + ": size mismatch: " + values1.length + " vs " + values2.length + "."); } return false; } // Check each member of the array boolean diff = true; for (int i = 0; i < values1.length; i++) { diff = diff && displayStringDiff( name + "[" + i + "]", values1[i], values2[i], out, indent); } return diff; } /** * The toString function automatically uses display() to produce a string * version of this ElementDef. The indentation level is always zero. */ public String toString() { StringWriter strOut = new StringWriter(); PrintWriter prOut = new PrintWriter(strOut); display(prOut, 0); return strOut.toString(); } /** * The toXML function automatically uses displayXML() to produce an XML * version of this ElementDef as a String. * @return an XML representation of this ElementDef, as a String. */ public String toXML() { StringWriter writer = new StringWriter(); XMLOutput out = new XMLOutput(writer); displayXML(out, 0); return writer.toString(); } /** * The toCompactXML function automatically uses displayXML() to produce an XML * version of this ElementDef as a String. The generated XML is * compact; free of unnecessary whitespace. Compact XML is useful * when embedding XML in a CDATA section or transporting over the network. * @return an XML representation of this ElementDef, as a String. */ public String toCompactXML() { StringWriter writer = new StringWriter(); XMLOutput out = new XMLOutput(writer); out.setCompact(true); displayXML(out, 0); return writer.toString(); } /** * The diff function compares this element against another, determining if * they are exactly equal. If so, the function returns null. If not, * it returns a String describing the differences. */ public String diff(ElementDef other) { StringWriter writer = new StringWriter(); PrintWriter out = new PrintWriter(writer); boolean diff = displayDiff(other, out, 0); if (!diff) { return writer.toString(); } else { return null; } } /** * Determines if this ElementDef is equal to other (deeply), returning true * if the two are equal. * @return true if this equals other, false if not. * @throws ClassCastException if other is not an ElementDef. */ public boolean equals(Object other) { try { return displayDiff((ElementDef)other, null, 0); } catch (ClassCastException ex) { return false; } } /** * Returns a unique hash of this instance. * @return hash of the toXML() return value */ public int hashCode() { return this.toXML().hashCode(); } /** * Verifies that this ElementDef is equal to other, throwing a * XOMException with a lengthy explanation if equality * fails. * @param other the ElementDef to compare to this one. */ public void verifyEqual(ElementDef other) throws XOMException { StringWriter writer = new StringWriter(); PrintWriter out = new PrintWriter(writer); out.println(); boolean diff = displayDiff(other, out, 1); out.println(); if (!diff) { throw new XOMException( "Element definition mismatch: " + writer.toString()); } } /** * Clone an ElementDef. Because all ElementDefs are serializable, we can * clone through a memory buffer. */ protected Object clone() throws CloneNotSupportedException { try { return deepCopy(); } catch (XOMException ex) { throw new CloneNotSupportedException( "Unable to clone " + getClass().getName() + ": " + ex.toString()); } } /** * Public version of clone(); returns a deep copy of this ElementDef. */ public ElementDef deepCopy() throws XOMException { try { ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); ObjectOutputStream objOut = new ObjectOutputStream(byteBuffer); objOut.writeObject(this); objOut.flush(); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteBuffer.toByteArray()); ObjectInputStream objIn = new ObjectInputStream(byteIn); ElementDef def = (ElementDef)(objIn.readObject()); return def; } catch (IOException ex) { throw new XOMException(ex, "Failed to serialize-copy ElementDef"); } catch (ClassNotFoundException ex) { throw new XOMException(ex, "Failed to serialize-copy ElementDef"); } } // implement NodeDef public DOMWrapper getWrapper() { try { Field field = getClass().getField("_def"); return (DOMWrapper) field.get(this); } catch (NoSuchFieldException ex) { return null; } catch (IllegalAccessException ex) { throw new Error(ex.toString() + " in getWrapper"); } } // implement NodeDef public NodeDef[] getChildren() { List childrenList = new ArrayList(); final Field[] fields = getClass().getFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; try { final Class type = field.getType(); if (NodeDef.class.isAssignableFrom(type)) { childrenList.add((NodeDef) field.get(this)); } else if (type.isArray() && NodeDef.class.isAssignableFrom( type.getComponentType())) { NodeDef[] nodes = (NodeDef[]) field.get(this); childrenList.addAll(Arrays.asList(nodes)); } } catch (IllegalAccessException e) { throw new RuntimeException( "Error while accessing field '" + field + "'", e); } } return (NodeDef[]) childrenList.toArray(new NodeDef[childrenList.size()]); } public void addChild(NodeDef child) throws XOMException { XOMUtil.addChild(this, child); } public void addChildren(NodeDef[] children) throws XOMException { XOMUtil.addChildren(this, children); } protected static NodeDef[] getMixedChildren_new( DOMWrapper _def, Class clazz, String prefix) throws XOMException { DOMWrapper[] _elts = _def.getChildren(); int count = 0; for (int i = 0; i < _elts.length; i++) { switch (_elts[i].getType()) { case DOMWrapper.ELEMENT: case DOMWrapper.CDATA: case DOMWrapper.COMMENT: count++; break; case DOMWrapper.FREETEXT: default: break; } } NodeDef[] children = new NodeDef[count]; count = 0; for (int i = 0; i < _elts.length; i++) { switch (_elts[i].getType()) { case DOMWrapper.ELEMENT: case DOMWrapper.CDATA: case DOMWrapper.COMMENT: children[count++] = constructElement(_elts[i], clazz, prefix); break; case DOMWrapper.FREETEXT: default: break; } } return children; } protected static NodeDef[] getMixedChildren( DOMWrapper _def, Class clazz, String prefix) throws XOMException { DOMWrapper[] _elts = _def.getChildren(); NodeDef[] children = new NodeDef[_elts.length]; for (int i = 0; i < _elts.length; i++) { children[i] = constructElement(_elts[i], clazz, prefix); } return children; } protected static ElementDef[] getElementChildren( DOMWrapper _def, Class clazz, String prefix) throws XOMException { DOMWrapper[] _elts = _def.getElementChildren(); ElementDef[] children = new ElementDef[_elts.length]; for (int i = 0; i < children.length; i++) { children[i] = (ElementDef) constructElement( _elts[i], clazz, prefix); } return children; } public Location getLocation() { final DOMWrapper wrapper = getWrapper(); if (wrapper == null) { return null; } else { return wrapper.getLocation(); } } } // End ElementDef.java resgen/src/org/eigenbase/xom/XOMGenTask.java0000444000175000017500000001563711543216467021146 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/XOMGenTask.java#4 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2007 The Eigenbase Project // Copyright (C) 2005-2007 Disruptive Tech // Copyright (C) 2005-2007 LucidEra, Inc. // Portions Copyright (C) 2002-2007 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 1 April, 2002 */ package org.eigenbase.xom; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import java.io.File; import java.io.IOException; /** * XOMGenTask is an ANT task with which to invoke {@link * MetaGenerator}. * * @author jhyde * @since 1 April, 2002 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/XOMGenTask.java#4 $ * *
* *

XOMGen

*

Description

*

* Invokes the {@link MetaGenerator}. *

*

* This task only invokes XOMGen if the grammar file is newer than the * generated Java files. *

* *

Parameters

* * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
modelThe name of the XML file which holds the XOM * model.Yes
destdirThe name of the output directory. Default is the * current directory.No
classnameThe full name of the class to generate.Yes
dtdnameThe name of the DTD file to generate. The path may be * either absolute, or relative to destdir.Yes
* *

Example

*
<xomgen
 *     model="src/org/eigenbase/xom/Meta.xml"
 *     destdir="src"
 *     classname="org.eigenbase.xom.MetaDef"/>
*

* This invokes XOMGen on the model file * src/org/eigenbase/xom/Meta.xml, and generates * src/org/eigenbase/xom/MetaDef.java and * src/org/eigenbase/xom/meta.dtd. *

* *
**/ public class XOMGenTask extends Task { String modelFileName; String destDir; String dtdFileName; String className; public XOMGenTask() {} public void execute() throws BuildException { try { if (modelFileName == null) { throw new BuildException("You must specify model."); } if (className == null) { throw new BuildException("You must specify className."); } File projectBase = getProject().getBaseDir(); File destinationDirectory; if (destDir == null) { destinationDirectory = projectBase; } else { destinationDirectory = new File(projectBase, destDir); } if (!destinationDirectory.exists()) { throw new BuildException( "Destination directory doesn't exist: " + destinationDirectory.toString()); } File modelFile = new File(projectBase, modelFileName); File classFile = classNameToFile(destinationDirectory, className); File outputDir = classFile.getParentFile(); File dtdFile = new File(outputDir, dtdFileName); if (modelFile.exists() && classFile.exists() && dtdFile.exists()) { long modelStamp = modelFile.lastModified(), classStamp = classFile.lastModified(), dtdStamp = dtdFile.lastModified(); if (classStamp > modelStamp && dtdStamp > modelStamp) { // files are up to date return; } } final boolean testMode = false; MetaGenerator generator = new MetaGenerator( modelFile.toString(), testMode, className); generator.writeFiles(destinationDirectory.toString(), dtdFileName); generator.writeOutputs(); } catch (XOMException e) { throw new BuildException("Generation of model failed: " + e); } catch (IOException e) { throw new BuildException("Generation of model failed: " + e); } } // ------------------------------------------------------------------------ // ANT attribute methods /** See parameter model. **/ public void setModel(String model) { this.modelFileName = model; } /** See parameter destdir. **/ public void setDestdir(String destdir) { this.destDir = destdir; } /** See parameter classname. **/ public void setClassname(String classname) { this.className = classname; } /** See parameter dtdname. **/ public void setDtdname(String dtdname) { this.dtdFileName = dtdname; } // ------------------------------------------------------------------------ /** * Creates the File that a java class will live in. For example, * makeJavaFileName("com.myproj", "MyClass") returns * "com/myproj/MyClass.java". **/ static File classNameToFile(File dir, String className) { char fileSep = System.getProperty("file.separator").charAt(0); // e.g. '/' String relativePath = className.replace('.', fileSep) + ".java"; if (dir == null) { return new File(relativePath); } else { return new File(dir, relativePath); } } } // End XOMGenTask.java resgen/src/org/eigenbase/xom/WrapperElementDef.java0000444000175000017500000001014411543216467022563 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/WrapperElementDef.java#3 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 31 October, 2001 */ package org.eigenbase.xom; import java.io.PrintWriter; /** * WrapperElementDef is an {@link ElementDef} which retains the * underlying XML {@link DOMWrapper}. It is used when there is no specific * class for this tag. * * @author jhyde * @since 31 October, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/WrapperElementDef.java#3 $ **/ public class WrapperElementDef extends ElementDef { DOMWrapper _def; Class enclosure; String prefix; public WrapperElementDef( DOMWrapper def, Class enclosure, String prefix) { this._def = def; this.enclosure = enclosure; this.prefix = prefix; } // implement NodeDef public void display(PrintWriter out, int indent) { out.print("<"); out.print(_def.getTagName()); String[] attributeKeys = _def.getAttributeNames(); for (int i = 0; i < attributeKeys.length; i++) { String key = attributeKeys[i]; Object value = _def.getAttribute(key); XOMUtil.printAtt(out, key, value.toString()); } NodeDef[] children = getChildren(); if (children.length == 0) { out.print("/>"); } else { for (int i = 0, count = children.length; i < count; i++) { children[i].display(out, indent + 1); } out.print(""); } } // implement NodeDef public void displayXML(XMLOutput out, int indent) { out.beginNode(); String tagName = _def.getTagName(); out.beginBeginTag(tagName); String[] attributeKeys = _def.getAttributeNames(); for (int i = 0; i < attributeKeys.length; i++) { String key = attributeKeys[i]; Object value = _def.getAttribute(key); out.attribute(key, value.toString()); } out.endBeginTag(tagName); NodeDef[] children = getChildren(); for (int i = 0, count = children.length; i < count; i++) { NodeDef child = children[i]; child.displayXML(out, indent + 1); } out.endTag(tagName); } // implement NodeDef public int getType() { return DOMWrapper.ELEMENT; } // implement NodeDef public String getName() { return _def.getTagName(); } // implement NodeDef public NodeDef[] getChildren() { try { DOMWrapper[] children = _def.getChildren(); NodeDef[] a = new NodeDef[children.length]; for (int i = 0; i < a.length; i++) { a[i] = ElementDef.constructElement( children[i], enclosure, prefix); } return a; } catch (XOMException e) { throw new AssertFailure(e, "in WrapperElementDef.getChildren"); } } // implement NodeDef public DOMWrapper getWrapper() { return _def; } } // End WrapperElementDef.java resgen/src/org/eigenbase/xom/AssertFailure.java0000444000175000017500000000422711543216467021770 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/AssertFailure.java#3 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2000-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 3 December, 2001 */ package org.eigenbase.xom; /** * todo: * * @author jhyde * @since 3 December, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/AssertFailure.java#3 $ **/ public class AssertFailure extends RuntimeException { /** Construct an AssertFailure with no message */ public AssertFailure() { super(); } /** Construct an AssertFailure with a simple detail message. */ public AssertFailure(String s) { super(s); } /** Construct an AssertFailure from an exception. This indicates an * unexpected exception of another type. We'll fill in the stack trace * when printing the message. */ public AssertFailure(Throwable th) { super("unexpected exception:\n" + th.fillInStackTrace().toString()); } /** Similar to the previous constructor, except allows a custom message on * top of the exception */ public AssertFailure(Throwable th, String s) { super(s + ":\n" + th.fillInStackTrace().toString()); } } // End AssertFailure.java resgen/src/org/eigenbase/xom/XMLUtil.java0000444000175000017500000003370611543216467020521 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/XMLUtil.java#5 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 3 October, 2001 */ package org.eigenbase.xom; import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; /** * Utilities for dealing with XML data. These methods must NOT depend upon any * XML parser or object model (MSXML, DOM, SAX, etc.) * * @author jhyde * @since 3 October, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/XMLUtil.java#5 $ **/ public class XMLUtil { /** * Determine if a String contains any XML special characters, return true * if it does. If this function returns true, the string will need to be * encoded either using the stringEncodeXML function above or using a * CDATA section. Note that MSXML has a nasty bug whereby whitespace * characters outside of a CDATA section are lost when parsing. To * avoid hitting this bug, this method treats many whitespace characters * as "special". * @param input the String to scan for XML special characters. * @return true if the String contains any such characters. */ public static boolean stringHasXMLSpecials(String input) { for (int i = 0; i < input.length(); i++) { char c = input.charAt(i); switch (c) { case '<': case '>': case '"': case '\'': case '&': case '\t': case '\n': case '\r': return true; } } return false; } /** * Encode a String for XML output, displaying it to a PrintWriter. * The String to be encoded is displayed, except that * special characters are converted into entities. * @param input a String to convert. * @param out a PrintWriter to which to write the results. */ public static void stringEncodeXML(String input, PrintWriter out) { for (int i = 0; i < input.length(); i++) { char c = input.charAt(i); switch (c) { case '<': case '>': case '"': case '\'': case '&': case '\t': case '\n': case '\r': out.print("&#" + (int)c + ";"); break; default: out.print(c); } } } /** * Quote a string, and write to a {@link PrintWriter}. * *

For example, "a string" becomes <![CDATA[a * string]]>. If the string contains ']]>' (which commonly * occurs when wrapping other XML documents), we give up on using * <![CDATA[ ... ]]>, and just encode the * string. For example, "A string with ]]> in it" becomes * "A string with ]]&gt; in it".

**/ public static void printPCDATA(PrintWriter pw, String data) { if (data.indexOf("]]>") > -1) { String s = StringEscaper.xmlEscaper.escapeString(data); pw.print(s); } else { pw.print(""); } } /** * Quote a string. * * @see #printPCDATA(PrintWriter,String) **/ public static String quotePCDATA(String data) { if (data.indexOf("]]>") > -1) { return StringEscaper.xmlEscaper.escapeString(data); } else { return ""; } } /** * Quote a string in an element and a CDATA, and write to a {@link * PrintWriter}. For example, it tag is "Value", then * "a string" becomes <Value><![CDATA[a * string]]></Value>. * * @param newline whether to print a newline after the element * @see #printPCDATA(PrintWriter,String) **/ public static void printPCDATA( PrintWriter pw, String tag, String data, boolean newline) { if (data == null || data.length() == 0) { return; } pw.print("<"); pw.print(tag); pw.print(">"); printPCDATA(pw,data); pw.print(""); if (newline) { pw.println(); } } public static void printPCDATA(PrintWriter pw, String tag, String data) { boolean newline = false; printPCDATA(pw, tag, data, newline); } private static String escapeForQuoting(String val) { return StringEscaper.xmlNumericEscaper.escapeString(val); } /** Quote a string so that it can be included as an XML attribute value. */ public static String quoteAtt(String val) { return "\"" + escapeForQuoting(val) + "\""; } /** Return an XML attribute/value pair for String val */ public static String quoteAtt(String name, String val) { if ((val == null) || val.equals("")) { return ""; } return " " + name + "=" + quoteAtt(val); } /** Return an XML attribute/value pair for int val */ public static String quoteAtt(String name, int val) { return " " + name + "=\"" + val + "\""; } /** Return an XML attribute/value pair for boolean val */ public static String quoteAtt(String name, boolean val) { return " " + name + "=\"" + (val ? "TRUE" : "FALSE") + "\""; } /** Quote a string so that it can be included as an XML attribute value. */ public static void printAtt(PrintWriter pw, String val) { pw.print("\""); pw.print(escapeForQuoting(val)); pw.print("\""); } /** Print an XML attribute name and value for string val */ public static void printAtt(PrintWriter pw, String name, String val) { if (val != null /* && !val.equals("") */) { pw.print(" "); pw.print(name); pw.print("=\""); pw.print(escapeForQuoting(val)); pw.print("\""); } } /** Print an XML attribute name and value for int val */ public static void printAtt(PrintWriter pw, String name, int val) { pw.print(" "); pw.print(name); pw.print("=\""); pw.print(val); pw.print("\""); } /** Print an XML attribute name and value for boolean val */ public static void printAtt(PrintWriter pw, String name, boolean val) { pw.print(" "); pw.print(name); pw.print(val ? "=\"true\"" : "=\"false\""); } /** * Retrieve the name of the first tag in the XML document specified by the * given Reader, without parsing the full file/string. This function is * useful to identify the DocType of an XML document before parsing, * possibly to send the document off to different pieces of code. * For performance reasons, the function attempts to read as little of * the file or string as possible before making its decision about the * first tag. Leading comments are ignored. * @param xml a Reader containing an XML document. * @return the first tag name, as a String, or null if no first tag * can be found. */ public static String getFirstTagName(Reader xml) { final int OUTSIDE = 0; // constant: identify outside state final int BRACKET = 1; // constant: bracket, contents unknown final int COMMENT = 2; // constant: identify a comment section final int IGNORE = 3; // constant: identify an ignored section final int TAG = 4; // constant: identify a tag section int state = OUTSIDE; String commentMatch = null; StringBuffer tagBuffer = null; boolean sawBang = false; try { int c = xml.read(); for (;;) { // No tag found if we hit EOF first. if (c == -1) { return null; } switch (state) { case OUTSIDE: // Start of any sort of tag if (c == '<') { state = BRACKET; commentMatch = "!--"; sawBang = false; c = xml.read(); // Other non-whitespace characters outside of any tag } else if (!Character.isWhitespace((char) c)) { return null; // Whitespace characters are ignored } else { c = xml.read(); } break; case BRACKET: // Check for the start of a comment. if (commentMatch != null) { if (c == commentMatch.charAt(0)) { // This match indicates a comment if (commentMatch.length() == 1) { c = xml.read(); commentMatch = "-->"; state = COMMENT; } else { // Remove the first character from commentMatch, // then process the character as usual. commentMatch = commentMatch.substring(1, commentMatch.length()); } } else { // No longer eligible for comment. commentMatch = null; } } // Hit whitespace; ignore the character. if (Character.isWhitespace((char) c)) { c = xml.read(); break; } switch (c) { case '?': c = xml.read(); state = IGNORE; break; case '!': // Enter an ignored section unless eligible for comment. c = xml.read(); sawBang = true; if (commentMatch == null) { state = IGNORE; } break; case '-': // Enter an ignored section unless eligible for comment. c = xml.read(); if (commentMatch == null) { state = IGNORE; } break; case '>': // Return to OUTSIDE state immediately c = xml.read(); state = OUTSIDE; break; default: // State depends on whether we saw a ! or not. if (sawBang) { state = IGNORE; } else { state = TAG; } tagBuffer = new StringBuffer(); } break; case COMMENT: // Did we match the next expected end-of-comment character? if (c == commentMatch.charAt(0)) { c = xml.read(); if (commentMatch.length() == 1) { // Done with the comment state = OUTSIDE; } else { commentMatch = commentMatch.substring(1, commentMatch.length()); } } else { // If not, restart our quest for the end-of-comment character. c = xml.read(); commentMatch = "-->"; } break; case IGNORE: // Drop out on a close >. Ignore all other characters. if (c == '>') { c = xml.read(); state = OUTSIDE; } else { c = xml.read(); } break; case TAG: // Store characters in the tag buffer until we hit whitespace. // When we hit whitespace or '>' or '/', return the name of the tag. if (Character.isWhitespace((char)c) || c == '>' || c == '/') { return tagBuffer.toString(); } else { tagBuffer.append((char)c); c = xml.read(); } break; } } } catch (IOException ex) { // On exception, we can't determine the first tag, so return null. return null; } } } // End XMLUtil.java resgen/src/org/eigenbase/xom/Meta.xml0000444000175000017500000003367611543216467017776 0ustar drazzibdrazzib This model is the XOM Meta Model. It is the specification of the model used to define new XML-based models. It is also an instance of itself. Model is the top-level element for a model description. The model element contains all other elements in the model and also defines the model's basic attributes, such as its name and version number. Colon-separated list of packages to import. For example, importName="java.lang.*:java.util.List" Default value for keepDef attribute. The elements array contains a definition for each element within the model. Elements include Class, Element, and String definitions. The Definition class represents a generic type of element definition. The actual definition may be of a Class, Element, or String. Definitions are the basic building blocks of a model. Doc tags allow documentation to be added to any definition. The documentation will automatically appear in all physical forms of this model, including dtds, java classes, and the xsl transformation. The FullDefinition class represents a fully-specified definition that may include content. Specifies the content model of this definition. Content model determines how the contained objects and arrays will be parsed and intepreted:
  • Sequential content is the default model. Under a sequential model, content is intepreted by its position, and the order of content in a .xml file must match the order defined in the model.
  • Under random content, order is less important; different types are parsed as needed. Order is still used to resolve multiple instances of the same type.
  • Mixed content allows text to appear intermixed with elements, which are interpreted in random order. It is currently unsupported.
  • Any content removes all restrictions, allowing any content to appear (but at the price of a lack of type-safety in the java representation of the element).
  • CData content specifies text-only content. No objects or arrays may be defined.
sequential random mixed any cdata
Whether to keep the underlying wrapper around (in a field called _def) after the object has been constructed.

If not specified, defaults to the value of the Model.defaultKeepDef attribute, or false if that is not specified.

This array defines all attributes to appear within this class or element. This array defines all content (objects and arrays) to appear within this class or element. The interpretation of this array depends on the element's defined content model. This element allows arbitrary Java Code to be attached to any class or element. Code sections are not verified until the final .java class is compiled and should be used sparingly. An Element Definition defines a basic entity of the meta model. Elements are containers for two types of data: attributes and content. Attributes are simple name/value pairs which may take on the full range of Java types. Content consists of other Elements and Strings, either appearing alone or as arrays. Name of the Class that this Element belongs to.

If the Element has multiple supertypes, the value is a comma-separated list. Since a Java interface is generated for each Class and a Java class is generated for each Element, and Java only allows single inheritance of classes, at most one of the supertypes can be an Element.

The dtdName attribute sets the name by which this Element will be known in the dtd. If not specified, it will default to the model's prefix (in any) plus the type of this element. Whether the class generated for this Element is abstract. An abstract Element is similar to a Class: an abstract Element is implemented by an abstract Java class; a Class is implemented by a Java interface. Per the rules of Java, the abstract class generated for an abstract Element can have members and methods with bodies, but it only allows single inheritance.
A Class Definition defines a class of entities. A class specifies a group of entities with similar properties. Full inheritence is supported, although there are limits on what can be overridden. Name of this Class. Name of the supertype(s) of this Class.

If the Class has multiple supertypes, the value is a comma-separated list.

A StringElement is a simple type of element which has no attributes and whose content is a single String (usually represented as a CDATA section). StringElements are used when raw text must be included in a model, such as raw Java code, or SQL statements, or HTML documentation. A Plugin in a special type of element whose content may be derived from a different model. The exact model to use is specified by the individual XML file, allowing a Plugin element to link to another model dynamically. The Plugin element automatically defines the defPackage and defClass attributes. Other attributes may be added as needed. Code and documentation sections are supported as well. An Import as a special type of element that represents another element stored in an external model. The model to use is specified by the defPackage and defClass attributes of the import. An Import may not be derived from any class. The Doc entity specifies a documentation section. The text contained in this element should be raw text or HTML used to document the object in which the Doc section appears. The Code entity specifies a raw block of Java code. Each Class/Element becomes represented by a Java Class. Including a Code block inside a Class or Element will insert the code directly into the corresponding class. No checking is done on the code until it is complied later. The Attribute entity appears within any Element definition. It defines an Attribute, which is a name/value pair used to hold data inside of an Element. The Attribute's definition includes its name, type, and usage information (default value and whether or not it is required). An Attribute definition may limit its values by specifying Value objects. The Value entity specifies a single value in the set of allowed values for an Attribute. The value is specifies as text so that any special characters may appear. The Content class contains all entities which represent types of content which may appear within an Element. Content includes Objects, Arrays, Strings, and special markers such as Any. An Object is a single instance of an Element type. Objects have an identifying name and a type. The name identifies the object within its Element and must be unique within the Element. The object is itself an instance of an Element, and this Element is identified by the type. The type may be the type name of an Element or the class name of a Class. An Array is a set of multiple instances of Elements. The Array has an identifying name and a base type. The name identifies the array within its Element and must be unique within the Element. Each object in the array is an instance of the Element identified by the type. The type may be the type name of an Element or the class name of a Class. The Any content is a special marker which allows an Element to contain any type of data. The data will appear in a single array called "children". The data will contain all kinds of node (elements, comments, text) if the content model is "mixed", otherwise just elements. If an Any marker appears, no other content may appear in the element. The CData content is a special marker which allows an Element to contain a single CDATA section as its only content, yet still have attributes. The data will appear in a single String called "cdata". If a CData marker appears, no other content may appear in the element. resgen/src/org/eigenbase/xom/XOMUtil.java0000444000175000017500000002506611543216467020524 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/XOMUtil.java#5 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 3 October, 2001 */ package org.eigenbase.xom; import java.io.File; import java.io.StringWriter; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * Utility functions for the org.eigenbase.xom and * org.eigenbase.xom.wrappers packages. * * @author jhyde * @since 3 October, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/XOMUtil.java#5 $ **/ public abstract class XOMUtil extends XMLUtil { static final NodeDef[] emptyNodeArray = new NodeDef[0]; /** * When the compiler is complaining that you are not using a variable, just * call one of these routines with it. **/ public static void discard(boolean b) { } public static void discard(byte b) { } public static void discard(char c) { } public static void discard(double d) { } public static void discard(float d) { } public static void discard(int i) { } public static void discard(long l) { } public static void discard(Object o) { } public static void discard(short s) { } /** * Converts the first letter of name to upper-case. */ static String capitalize(String name) { if (name == null || name.length() < 1) { return name; } return name.substring(0,1).toUpperCase() + name.substring(1); } /** * Adds an object to the end of an array. The resulting array is of the * same type (e.g. String[]) as the input array. **/ public static Object[] addElement(Object[] a, Object o) { Class clazz = a.getClass().getComponentType(); Object[] a2 = (Object[]) Array.newInstance(clazz, a.length + 1); System.arraycopy(a, 0, a2, 0, a.length); a2[a.length] = o; return a2; } /** * Concatenates two arrays. The resulting array is of the * same type (e.g. String[]) as the first array. **/ public static Object[] concatenate(Object[] a0, Object[] a1) { Class clazz = a0.getClass().getComponentType(); Object[] a2 = (Object[]) Array.newInstance( clazz, a0.length + a1.length); System.arraycopy(a0, 0, a2, 0, a0.length); System.arraycopy(a1, 0, a2, a0.length, a1.length); return a2; } /** * Adds a set of children to an object, using its best guess as to where to * put them. **/ public static void addChildren(ElementDef parent, NodeDef[] children) throws XOMException { if (parent instanceof GenericDef) { GenericDef xmlGeneric = (GenericDef) parent; for (int i = 0; i < children.length; i++) { xmlGeneric.addChild(children[i]); } } else if (parent instanceof Any) { Any any = (Any) parent; NodeDef[] currentChildren = any.getChildren(); if (currentChildren == null) { if (children instanceof ElementDef[]) { currentChildren = new ElementDef[0]; } else { currentChildren = new NodeDef[0]; } } NodeDef[] newChildren = (NodeDef[]) concatenate( currentChildren, children); any.setChildren(newChildren); } else { // Use reflection. We presume that the children are stored in the // first array field. Field field = null; Field[] fields = parent.getClass().getFields(); for (int i = 0; i < fields.length; i++) { if (fields[i].getType().isArray()) { field = fields[i]; break; } } if (field == null) { throw new XOMException( "cannot add field to " + parent.getClass() + ": it has no array field"); } try { Object[] a = (Object[]) field.get(parent); Object[] b = concatenate(a, children); field.set(parent, b); } catch (IllegalAccessException e) { throw new XOMException(e, "in XOMUtil.getChildren"); } } } public static void addChild(ElementDef parent, ElementDef child) throws XOMException { addChildren(parent, new ElementDef[] {child}); } public static void addChild(ElementDef parent, NodeDef child) throws XOMException { addChildren(parent, new NodeDef[] {child}); } /** * Creates a {@link Parser} of the default parser type. **/ public static Parser createDefaultParser() throws XOMException { String className = "org.eigenbase.xom.wrappers.JaxpDOMParser"; try { Class clazz = Class.forName(className); return (Parser) clazz.newInstance(); } catch (ClassNotFoundException e) { throw new XOMException(e, "Error while creating xml parser '" + className + "'"); } catch (IllegalAccessException e) { throw new XOMException(e, "Error while creating xml parser '" + className + "'"); } catch (InstantiationException e) { throw new XOMException(e, "Error while creating xml parser '" + className + "'"); } catch (VerifyError e) { throw new XOMException( e, "Error while creating xml parser '" + className + "' " + "(If you are running Weblogic 6.1, try putting " + "xml-apis.jar and xercesImpl.jar BEFORE weblogic.jar " + "on CLASSPATH)"); } } /** * @see #makeParser **/ static final int MSXML = 1; /** * @see #makeParser **/ static final int XERCES = 2; /** * Creates a parser of given type. * * @param parserType valid values are {@link #MSXML} and {@link #XERCES}. **/ static Parser makeParser( int parserType, boolean usesPlugins, String fileDirectory, String dtdName, String docType) throws XOMException { try { switch (parserType) { case MSXML: if (usesPlugins) { // Use reflection to call // MSXMLWrapper.createParser(); Class clazz = Class.forName( "org.eigenbase.xom.wrappers.MSXMLWrapper"); Method method = clazz.getDeclaredMethod( "createParser", new Class[] {}); return (Parser) method.invoke(null, new Object[] {}); } else { // Use reflection to call // MSXMLWrapper.createParser(docType, dtdPath); File dtdPath = new File(fileDirectory, dtdName); Class clazz = Class.forName( "org.eigenbase.xom.wrappers.MSXMLWrapper"); Method method = clazz.getDeclaredMethod( "createParser", new Class[] { String.class, String.class}); return (Parser) method.invoke(null, new Object[] { docType, dtdPath}); } case XERCES: return new org.eigenbase.xom.wrappers.XercesDOMParser( !usesPlugins); default: throw new XOMException("Unknown parser type: " + parserType); } } catch (ClassNotFoundException e) { throw new XOMException(e, "while creating xml parser"); } catch (IllegalAccessException e) { throw new XOMException(e, "while creating xml parser"); } catch (NoSuchMethodException e) { throw new XOMException(e, "while creating xml parser"); } catch (InvocationTargetException e) { throw new XOMException(e, "while creating xml parser"); } } /** * Returns the first member of an array of objects which is an instance of * a given class, or null if there is no such. **/ public static Object getFirstInstance(Object[] a, Class clazz) { for (int i = 0; i < a.length; i++) { if (clazz.isInstance(a[i])) { return a[i]; } } return null; } public static String wrapperToXml(DOMWrapper wrapper, boolean ignorePcdata) { try { NodeDef node; switch (wrapper.getType()) { case DOMWrapper.ELEMENT: node = new WrapperElementDef(wrapper,null,null); break; case DOMWrapper.CDATA: node = new CdataDef(wrapper); break; case DOMWrapper.FREETEXT: node = new TextDef(wrapper); break; case DOMWrapper.COMMENT: node = new CommentDef(wrapper); break; default: throw new Error( "unknown node type " + wrapper.getType() + " while converting node to xml"); } StringWriter sw = new StringWriter(); XMLOutput out = new XMLOutput(sw); out.setIgnorePcdata(ignorePcdata); out.setGlob(true); node.displayXML(out, 0); return sw.toString(); } catch (XOMException e) { throw new Error( "[" + e.toString() + "] while converting node to xml"); } } } // End XOMUtil.java resgen/src/org/eigenbase/xom/MetaTester.java0000444000175000017500000003672211543216467021301 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/MetaTester.java#3 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2000-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // dsommerfield, 28 December, 2000 */ package org.eigenbase.xom; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * The MetaTester class is a utility class for testing generated models. * The tester reads a model file in XML, validates it against its DTD, * converts it to its corresponding model definition class (always a * subclass of ElementDef), and displays the results. * The MetaTester may be used to test a model against a suite of input * files to verify the model's correctness. */ public class MetaTester { // rootDef is the ElementDef class representing the root of the model. private Class rootDef; // rootConstructor is the constructor for the rootDef class which // takes Element as its only argument. private Constructor rootConstructor; /** The parser. */ private Parser parser; // model is the root of the metamodel, and contains all basic model // information. private MetaDef.Model model; // modelDocType is the DocType expected for all test files private String modelDocType; /** * The type of parser to use. Values are {@link XOMUtil#MSXML}, etc. **/ private int parserType; /** * Constructs a new MetaTester using the given model file, the given * test file, and the directory containing all support files. * @param modelFile an XML file describing the model to be tested. * This model should have already been compiled using the MetaGenerator * utility. * @param fileDirectory the directory containing all output files * (Java classes, dtds, etc) from the model compilation. The model * and its associated java class must be compiled. * @throws XOMException if the model file is corrupted or if any * of its compiled components cannot be loaded. */ public MetaTester(String modelFile, String fileDirectory, int parserType) throws XOMException, IOException { // Set the parser this.parserType = parserType; // Load the input model file. FileInputStream in = null; try { in = new FileInputStream(modelFile); } catch (IOException ex) { throw new XOMException("Loading of model file " + modelFile + " failed: " + ex.getMessage()); } // Parse the meta model. Parser parser = XOMUtil.createDefaultParser(); try { DOMWrapper def = parser.parse(in); model = new MetaDef.Model(def); } catch (XOMException ex) { throw new XOMException( ex, "Failed to parse XML file: " + modelFile); } // Load the root java class of the Java version of this model. // Then find the Constructor which takes a single DOMWrapper. String modelRoot = getModelRoot(model); try { rootDef = Class.forName(model.className + "$" + modelRoot); Class[] params = new Class[1]; params[0] = DOMWrapper.class; rootConstructor = rootDef.getConstructor(params); } catch (ClassNotFoundException ex) { throw new XOMException("Model class " + model.className + "." + modelRoot + " could not be " + "loaded: " + ex.getMessage()); } catch (NoSuchMethodException ex) { throw new XOMException("Model class " + model.className + "." + modelRoot + " has no " + "constructor which takes a " + "DOMWrapper."); } // Figure out if the model uses plugins or imports by looking at all // element definitions. If plugins or imports are in use, we can't use the // dtd for validation. boolean usesPlugins = false; for(int i=0; i 0) writer.write(buffer, 0, numChars); } } /** * This helper function retrieves the root element name from a model. The * root element name may be defined explicitly, or it may need to be * located as the first element in the file itself. * Also, if a prefix is defined, we need to add it here. */ private static String getModelRoot(MetaDef.Model model) throws XOMException { if(model.root != null) return model.root; for(int i=0; i"); if(modelDocType != null) out.println(""); out.flush(); } readerToWriter(reader, sWriter); reader.close(); xmlString = sWriter.toString(); } catch (IOException ex) { throw new XOMException("Unable to read input test " + testFile + ": " + ex.getMessage()); } DOMWrapper elt = parser.parse(xmlString); // Instantiate the ElementDef class using its Element constructor. ElementDef def = instantiate(elt); // Display the results System.out.println("Testing model " + testFile); System.out.println("Display:"); System.out.println(def.toString()); System.out.println(); // Display the results in XML as well String xmlOut = def.toXML(); System.out.println(); System.out.println("Regurgitated XML:"); System.out.println(xmlOut); // Parse the generated XML back into another ElementDef. // To do so, we must add the xml PI and DOCTYPE at the top of the // String (unless we're using MSXML). if(parserType != XOMUtil.MSXML) { StringWriter writer = new StringWriter(); PrintWriter out = new PrintWriter(writer); out.println(""); if(modelDocType != null) out.println(""); out.println(xmlOut); out.flush(); xmlOut = writer.toString(); } DOMWrapper elt2 = parser.parse(xmlOut); // Instantiate the second ElementDef class ElementDef def2 = instantiate(elt2); // Verify equality, and then test equality try { def.verifyEqual(def2); } catch(XOMException ex) { System.err.println("Equality failure. Regurgitated XML:"); System.err.println(xmlOut); throw ex; } if(!def.equals(def2)) throw new XOMException("Equality check failed even though " + "verifyEqual passed."); } /** * The MetaTester tests a suite of test model files against a * compiled model. *

Arguments: *

    *
  1. The name of the model description file. This is an XML file * describing the model itself. *
  2. The name of the output directory. This output directory should * contain all files generated when compiling the model. *
*

All other arguments are the names of the test model files. Each * of these will be tested and displayed in turn. */ public static void main(String[] args) throws XOMException, IOException { int firstArg = 0; if(args.length > 0 && args[0].equals("-debug")) { System.err.println("MetaTester pausing for debugging. " + "Attach your debugger " + "and press return."); try { System.in.read(); firstArg++; } catch(IOException ex) { // Do nothing } } int parser = XOMUtil.MSXML; if (firstArg < args.length && args[firstArg].equals("-msxml")) { parser = XOMUtil.MSXML; firstArg++; } else if (firstArg < args.length && args[firstArg].equals("-xerces")) { parser = XOMUtil.XERCES; firstArg++; } if(args.length < firstArg+2) { System.err.println( "Usage: java MetaTester [-debug] [-msxml | -xerces] " + " ..."); System.exit(-1); } MetaTester tester = new MetaTester(args[0+firstArg], args[1+firstArg], parser); for(int i=2+firstArg; iGenericDef is a {@link ElementDef} whose attributes and * children are stored in collections, not generated members. It is convenient * for building XML documents, but is not strongly typed. * * @author jhyde * @since 3 October, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/GenericDef.java#3 $ **/ public class GenericDef extends ElementDef { private String tagName; private Vector children; private OrderedStringMap attributes; public GenericDef(String tagName) { this.tagName = tagName; this.children = new Vector(); this.attributes = new OrderedStringMap(); } // implement ElementDef public void display(PrintWriter out, int indent) { out.println(getName()); for (int i = 0, count = attributes.size(); i < count; i++) { String key = attributes.keyAt(i); Object value = attributes.valueAt(i); displayAttribute(out, key, value.toString(), indent + 1); } for (int i = 0, count = children.size(); i < count; i++) { ElementDef child = (ElementDef) children.elementAt(i); displayElement(out, "?", child, indent + 1); } } // implement NodeDef public void displayXML(XMLOutput out, int indent) { out.beginBeginTag(tagName); for (int i = 0, count = attributes.size(); i < count; i++) { String key = attributes.keyAt(i); Object value = attributes.valueAt(i); out.attribute(key, value.toString()); } out.endBeginTag(tagName); for (int i = 0, count = children.size(); i < count; i++) { NodeDef child = (NodeDef) children.elementAt(i); child.displayXML(out, indent + 1); } out.endTag(tagName); } // override ElementDef public int getType() { return DOMWrapper.ELEMENT; } /** * Returns the tag name of this element, or null for TEXT elements. */ public String getName() { return tagName; } public void addChild(NodeDef element) { children.addElement(element); } public NodeDef[] getChildren() { NodeDef[] a = new NodeDef[children.size()]; children.copyInto(a); return a; } public void setAttribute(String key, Object value) { attributes.put(key, value); } public Object getAttribute(String key) { return attributes.get(key); } private static class OrderedStringMap { Vector v; Hashtable h; OrderedStringMap() { v = new Vector(); h = new Hashtable(); } int size() { return v.size(); } Object get(String key) { return h.get(key); } void put(String key, Object value) { if (h.put(key, value) == null) { // attribute does not have a value; append to vector v.addElement(new StringMapEntry(key,value)); } else { // attribute already has a value; replace it for (int i = 0, count = v.size(); i < count; i++) { StringMapEntry entry = (StringMapEntry) v.elementAt(i); if (entry.key.equals(key)) { entry.value = value; return; } } throw new Error( "key " + key + " not found in OrderedStringMap"); } } String keyAt(int i) { return ((StringMapEntry) v.elementAt(i)).key; } Object valueAt(int i) { return ((StringMapEntry) v.elementAt(i)).value; } }; private static class StringMapEntry { String key; Object value; StringMapEntry(String key, Object value) { this.key = key; this.value = value; } } } // End GenericDef.java resgen/src/org/eigenbase/xom/XomTest.java0000444000175000017500000001011511543216467020613 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/XomTest.java#1 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2008-2008 The Eigenbase Project // Copyright (C) 2008-2008 Disruptive Tech // Copyright (C) 2008-2008 LucidEra, Inc. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.xom; import junit.framework.TestCase; /** * Unit tests for XOM module. * * @author jhyde * @version $Id: //open/util/resgen/src/org/eigenbase/xom/XomTest.java#1 $ * @since Jun 6, 2008 */ public class XomTest extends TestCase { public void testFoo() throws XOMException { final Parser xmlParser = XOMUtil.createDefaultParser(); xmlParser.setKeepPositions(true); final String lineSep = System.getProperty("line.separator"); final String xml = "" + lineSep + " " + lineSep + "" + lineSep + " This model is the XOM Meta Model. It is the specification of the model used" + lineSep + " to define new XML-based models. It is also an instance of itself." + lineSep + "" + lineSep + "" + lineSep + "" + lineSep + "" + lineSep + " " + lineSep + " Contains a \"single\" apostrope '." + lineSep + " " + lineSep + "" + lineSep + " " + lineSep + " " + lineSep + "" + lineSep + ""; DOMWrapper def = xmlParser.parse(xml); assertNotNull(def); final MetaDef.Model model = new MetaDef.Model(def); assertNotNull(model); Location location = model.getLocation(); assertEquals("Model", model.getName()); assertEquals(1, location.getStartLine()); assertEquals(1, location.getStartColumn()); assertEquals(25, location.getEndLine()); assertEquals(9, location.getEndColumn()); // Model only has one child, Element. Doc is Cdata, so becomes an // attribute. NodeDef[] children = model.getChildren(); assertEquals(1, children.length); final NodeDef element = children[0]; assertEquals("Element", element.getName()); location = element.getLocation(); assertEquals(17, location.getStartLine()); assertEquals(1, location.getStartColumn()); assertEquals(24, location.getEndLine()); assertEquals(11, location.getEndColumn()); children = element.getChildren(); assertEquals(4, children.length); NodeDef attribute = children[1]; assertEquals("Attribute", attribute.getName()); location = attribute.getLocation(); assertEquals(23, location.getStartLine()); assertEquals(5, location.getStartColumn()); assertEquals(23, location.getEndLine()); assertEquals(32, location.getEndColumn()); } } // End XomTest.java resgen/src/org/eigenbase/xom/wrappers/0000755000175000017500000000000011543216467020214 5ustar drazzibdrazzibresgen/src/org/eigenbase/xom/wrappers/Annotator.java0000444000175000017500000004444611543216467023036 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/Annotator.java#4 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2008-2008 The Eigenbase Project // Copyright (C) 2008-2008 Disruptive Tech // Copyright (C) 2008-2008 LucidEra, Inc. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.xom.wrappers; import org.eigenbase.xom.*; import org.w3c.dom.Node; import java.util.*; import java.io.PrintWriter; /** * Quick and dirty XML parser that finds the precise start and end * position of all nodes in a document. Also finds all line endings, so * that character offsets can be converted to line/column positions. * * @author jhyde * @since 13 October, 2008 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/Annotator.java#4 $ */ public class Annotator { private final List/**/ locInfoList = new ArrayList(); private int[] lineStartPositions; private final String xml; private final Map/**/ wrapperLocMap = new HashMap(); private final Map/**/ nodeLocMap = new HashMap(); private int seq; // workspace for populateMap /** * Creates an Annotator. * *

For testing purposes, wrapper may be null. Parses the XML * but does not build the mapping from location information to DOM nodes. * * @param xml XML source string * @param def Wrapper around root DOM node */ Annotator(String xml, DOMWrapper def) { this.xml = xml; parse(xml); if (def != null) { seq = 0; populateMap(def); assert this.nodeLocMap.size() == this.wrapperLocMap.size(); } } public Location getLocation(DOMWrapper wrapper) { LocInfo location0 = (LocInfo) wrapperLocMap.get(wrapper); if (location0 == null) { location0 = (Annotator.LocInfo) nodeLocMap.get(((W3CDOMWrapper) wrapper).node); if (location0 == null) { return null; } } final LocInfo location = location0; return new Location() { public int getStartLine() { return getLine(getStartPos()) + 1; } public int getStartColumn() { return getCol(getStartPos()) + 1; } public int getStartPos() { return location.startTagStartPos; } public int getEndLine() { return getLine(getEndPos()) + 1; } public int getEndColumn() { return getCol(getEndPos()) + 1; } public int getEndPos() { return location.endTagEndPos >= 0 ? location.endTagEndPos : location.startTagEndPos; } public String getText(boolean headOnly) { return location.getText(headOnly); } public String toString() { return location.toString(Annotator.this); } }; } /** * Returns the list of LocInfo. For testing. * * @return list of LocInfo. */ List getLocInfoList() { return locInfoList; } // enum State private static final int STATE_NORMAL = 0, STATE_TAG = 1, STATE_ENDTAG = 2, STATE_QUOT = 3, STATE_APOS = 4, STATE_COMMENT = 5, STATE_CDATA = 6; void parse(String s) { final ArrayStack/**/ lockInfoStack = new ArrayStack(); final List lineStartPositions = new ArrayList(); int state = STATE_NORMAL; final int count = s.length(); int i = 0; int last = 0; lineStartPositions.add(new Integer(i)); lockInfoStack.push(null); LocInfo location = null; loop: while (i < count) { final char c = s.charAt(i); switch (c) { case '<': stateSwitch: switch (state) { case STATE_NORMAL: if (i > last) { // Unlike other node types, we create the LocInfo // at the end of the element. No need to add the node // to the stack, because we'd just remove it again. LocInfo loc2 = new LocInfo(locInfoList.size(), TYPE_TEXT, last); loc2.endTagEndPos = i; locInfoList.add(loc2); } if (i + 1 < count) { final char c1 = s.charAt(i + 1); switch (c1) { case '/': // ^ state = STATE_ENDTAG; assert location != null; break stateSwitch; case '?': // ^ location = new LocInfo( locInfoList.size(), TYPE_PROCESSING_INSTRUCTION, i); locInfoList.add(location); state = STATE_TAG; i += " // Don't push until we see end of the head tag state = STATE_TAG; location = new LocInfo(locInfoList.size(), TYPE_ELEMENT, i); locInfoList.add(location); ++i; continue loop; } break; case '>': switch (state) { case STATE_TAG: ++i; assert location != null; switch (location.type) { case TYPE_PROCESSING_INSTRUCTION: // case TYPE_CDATA_SECTION: // case TYPE_COMMENT: // i += "-->".length(); location.endTagEndPos = i; last = i; location = (LocInfo) lockInfoStack.peek(); state = STATE_NORMAL; continue loop; } } break; case '\r': ++i; if (i < count && s.charAt(i) == '\n') { // only count windows line ending CR LF as one line ++i; } lineStartPositions.add(new Integer(i)); continue loop; case '\n': ++i; lineStartPositions.add(new Integer(i)); continue loop; case '\'': switch (state) { case STATE_APOS: // a='xxx^' state = STATE_TAG; break; case STATE_TAG: // a=^'xxx' state = STATE_APOS; break; case STATE_QUOT: // a="doesn^'t matter" default: break; } break; case '"': switch (state) { case STATE_QUOT: // a="xxx^" state = STATE_TAG; break; case STATE_TAG: // a=^"xxx" state = STATE_QUOT; break; case STATE_APOS: // a='doesn^"t matter' default: break; } break; } ++i; } this.lineStartPositions = new int[lineStartPositions.size()]; for (int j = 0; j < lineStartPositions.size(); j++) { this.lineStartPositions[j] = ((Integer) lineStartPositions.get(j)).intValue(); } } private void populateMap(DOMWrapper def) { final int defType = def.getType(); LocInfo location; while (true) { location = (LocInfo) locInfoList.get(seq++); if (defType == DOMWrapper.ELEMENT && location.type == TYPE_ELEMENT) { break; } if (defType == DOMWrapper.CDATA && location.type == TYPE_TEXT) { break; } if (seq >= locInfoList.size()) { return; } } wrapperLocMap.put(def, location); nodeLocMap.put(((W3CDOMWrapper) def).node, location); final DOMWrapper[] elementChildren = def.getElementChildren(); for (int i = 0; i < elementChildren.length; i++) { DOMWrapper domWrapper = elementChildren[i]; populateMap(domWrapper); } } /** * Returns the line that a character position falls on. The first line in a * document is numbered 0. * * @param pos Character position * @return Line (starting from 0) */ int getLine(int pos) { int index = Arrays.binarySearch(lineStartPositions, pos); if (index >= 0) { return index; } else { return -2 - index; } } /** * Returns the column that a character position falls on. The first column * in a line is numbered 0. * * @param pos Character position * @return column (starting from 0) */ int getCol(int pos) { int index = Arrays.binarySearch(lineStartPositions, pos); if (index >= 0) { return 0; } else { index = -2 - index; return pos - lineStartPositions[index]; } } void list(PrintWriter pw) { for (int i = 0; i < locInfoList.size(); i++) { LocInfo location = (LocInfo) locInfoList.get(i); pw.println( location.seq + ": " + location.toString(this) + " [" + location.getText(xml) + "]"); } pw.flush(); } // enum Type private static final int TYPE_ELEMENT = Node.ELEMENT_NODE, TYPE_PROCESSING_INSTRUCTION = Node.PROCESSING_INSTRUCTION_NODE, TYPE_COMMENT = Node.COMMENT_NODE, TYPE_CDATA_SECTION = Node.CDATA_SECTION_NODE, TYPE_TEXT = Node.TEXT_NODE; class LocInfo { /** Sequence in document, ordered by start position (prefix order) */ final int seq; /** Node type, typically {@link Node#ELEMENT_NODE}. */ final int startTagStartPos; final int type; int startTagEndPos = -1; // -1 if entity is a single tag int endTagEndPos = -1; /** * Creates a LocInfo. * * @param seq Sequence number in document * @param nodeType Node type, typically {@link Node#ELEMENT_NODE}. * @param startTagStartPos Position of start of element */ LocInfo(int seq, int nodeType, int startTagStartPos) { this.seq = seq; this.type = nodeType; this.startTagStartPos = startTagStartPos; } public String toString(Annotator annotator) { return "line " + annotator.getLine(startTagStartPos) + ", column " + annotator.getCol(startTagStartPos); } /** * Returns the fragment of source XML that this node encompasses. * * @param xml Whole source XML * @return fragment of source XML */ public String getText(String xml) { return xml.substring( startTagStartPos, endTagEndPos >= 0 ? endTagEndPos : xml.length()); } /** * Returns the fragment of source XML corresponding to the head tag * of this element, if this is an element, otherwise the whole node. * * @param xml Whole source XML * @return fragment of source XML */ public String getHeadText(String xml) { return xml.substring( startTagStartPos, startTagEndPos >= 0 ? startTagEndPos : endTagEndPos >= 0 ? endTagEndPos : xml.length()); } public String toString() { return getHeadText(xml); } /** * Returns the text of this location. Specification as for * {@link org.eigenbase.xom.Location#getText(boolean)}. * * @param headOnly Whether to return only the head of elements * @return Source text underlying a location */ public String getText(boolean headOnly) { return xml.substring( startTagStartPos, headOnly && startTagEndPos >= 0 ? startTagEndPos : endTagEndPos >= 0 ? endTagEndPos : xml.length()); } } /** * Similar to {@link Stack} but based on {@link ArrayList} instead of * {@link Vector}, and therefore more efficient. */ private static class ArrayStack extends ArrayList { public final void push(Object t) { if (false) System.out.println(size() + " push [" + t + "]"); add(t); } public final Object peek() { return get(size() - 1); } public final Object pop() { final int index = size() - 1; Object t = remove(index); if (false) System.out.println(size() + " pop [" + t + "]"); return get(index - 1); } } } // End Annotator.java resgen/src/org/eigenbase/xom/wrappers/LocationImpl.java0000444000175000017500000000243511543216467023453 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/LocationImpl.java#1 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2008-2008 The Eigenbase Project // Copyright (C) 2008-2008 Disruptive Tech // Copyright (C) 2008-2008 LucidEra, Inc. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.xom.wrappers; import org.eigenbase.xom.Location; /** * Location information. * * @author jhyde * @version $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/LocationImpl.java#1 $ * @since Jun 17, 2008 */ // End LocationImpl.java resgen/src/org/eigenbase/xom/wrappers/JaxpDOMParser.java0000444000175000017500000000700211543216467023473 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/JaxpDOMParser.java#3 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.xom.wrappers; import org.eigenbase.xom.XOMException; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; /** * A JaxpDOMParser implements {@link org.eigenbase.xom.Parser} using * a {@link DocumentBuilder JAXP-compliant parser}. * * @author jhyde * @since Aug 29, 2002 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/JaxpDOMParser.java#3 $ **/ public class JaxpDOMParser extends GenericDOMParser { private DocumentBuilder builder; /** Creates a non-validating parser. **/ public JaxpDOMParser() throws XOMException { this(false); } /** Creates a parser. **/ public JaxpDOMParser(boolean validating) throws XOMException { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(validating); try { factory.setAttribute(VALIDATION_FEATURE, new Boolean(validating)); factory.setAttribute(LOAD_EXTERNAL_DTD_FEATURE, new Boolean(validating)); } catch (IllegalArgumentException e) { // Weblogic 6.1's parser complains 'No arguments are // implemented' } builder = factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new XOMException(e, "Error creating parser"); } catch (FactoryConfigurationError e) { throw new XOMException(e, "Error creating parser"); } builder.setErrorHandler(this); document = builder.newDocument(); } protected Document parseInputSource(InputSource in) throws XOMException { prepareParse(); try { Document document = builder.parse(in); handleErrors(); return document; } catch (SAXException e) { // Display any pending errors handleErrors(); throw new XOMException(e, "Document parse failed"); } catch (IOException e) { // Display any pending errors handleErrors(); throw new XOMException(e, "Document parse failed"); } } } // End JaxpDOMParser.java resgen/src/org/eigenbase/xom/wrappers/GenericDOMParser.java0000444000175000017500000001553311543216467024155 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/GenericDOMParser.java#6 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.xom.wrappers; import org.eigenbase.xom.*; import org.w3c.dom.*; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import java.io.*; import java.net.URL; /** * A GenericDOMParser is an abstract base class for {@link * XercesDOMParser} and {@link JaxpDOMParser}. * * @author jhyde * @since Aug 29, 2002 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/GenericDOMParser.java#6 $ **/ abstract class GenericDOMParser implements ErrorHandler, org.eigenbase.xom.Parser, Locator { // Used for capturing error messages as they occur. StringWriter errorBuffer = null; PrintWriter errorOut = null; /** The document which spawns elements. The constructor of the derived * class must set this. **/ protected Document document; static final String LOAD_EXTERNAL_DTD_FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; static final String VALIDATION_FEATURE = "http://xml.org/sax/features/validation"; private boolean keepPositions; private Annotator annotator; public DOMWrapper create(String tagName) { Element element = document.createElement(tagName); return new W3CDOMWrapper(element, this); } public DOMWrapper parse(InputStream is) throws XOMException { TeeInputStream tis = new TeeInputStream(is); InputSource source = new InputSource(tis); Document document = parseInputSource(source); final W3CDOMWrapper wrapper = new W3CDOMWrapper(document.getDocumentElement(), this); if (keepPositions) { String xmlString = new String(tis.getBytes()); annotator = new Annotator(xmlString, wrapper); } return wrapper; } public void setKeepPositions(boolean keepPositions) { this.keepPositions = keepPositions; } public boolean isKeepPositions() { return keepPositions; } public DOMWrapper parse(String xmlString) throws XOMException { final DOMWrapper wrapper = parse(new StringReader(xmlString)); if (keepPositions) { annotator = new Annotator(xmlString, wrapper); } return wrapper; } public DOMWrapper parse(Reader reader) throws XOMException { Document document = parseInputSource(new InputSource(reader)); return new W3CDOMWrapper(document.getDocumentElement(), this); } /** * Parses the specified URI and returns the document. * @param in Input source * @return Document * @throws org.eigenbase.xom.XOMException on error */ protected abstract Document parseInputSource(InputSource in) throws XOMException; /** Warning. */ public void warning(SAXParseException ex) { errorOut.println("[Warning] " + getLocationString(ex) + ": " + ex.getMessage()); } /** Error. */ public void error(SAXParseException ex) { errorOut.println("[Error] " + getLocationString(ex) + ": " + ex.getMessage()); } /** Fatal error. */ public void fatalError(SAXParseException ex) throws SAXException { errorOut.println("[Fatal Error] " + getLocationString(ex) + ": " + ex.getMessage()); throw ex; } /** Returns a string of the location. * @param ex Exception * @return Location string, e.g. "file.xml:4:72" */ private String getLocationString(SAXParseException ex) { StringBuffer str = new StringBuffer(); String systemId = ex.getSystemId(); if (systemId != null) { int index = systemId.lastIndexOf('/'); if (index != -1) { systemId = systemId.substring(index + 1); } str.append(systemId); } str.append(':'); str.append(ex.getLineNumber()); str.append(':'); str.append(ex.getColumnNumber()); return str.toString(); } // implement Parser public DOMWrapper parse(URL url) throws XOMException { try { return parse(new BufferedInputStream(url.openStream())); } catch (IOException ex) { throw new XOMException(ex, "Document parse failed"); } } // Helper: reset the error buffer to prepare for a new parse. protected void prepareParse() { errorBuffer = new StringWriter(); errorOut = new PrintWriter(errorBuffer); } // Helper: throw an exception with messages of any errors // accumulated during the parse. protected void handleErrors() throws XOMException { errorOut.flush(); String errorStr = errorBuffer.toString(); if (errorStr.length() > 0) { throw new XOMException("Document parse failed: " + errorStr); } } // implement Locator public Location getLocation(DOMWrapper wrapper) { return annotator.getLocation(wrapper); } /** * Input stream that keeps a copy of every byte that flows through it. */ private static class TeeInputStream extends FilterInputStream { private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); TeeInputStream(InputStream in) { super(in); } public int read() throws IOException { int x = super.read(); baos.write(x); return x; } /** * Returns the bytes that have been read from this stream. * * @return Array of bytes that have been read from this stream */ public byte[] getBytes() { return baos.toByteArray(); } } } // End GenericDOMParser.java resgen/src/org/eigenbase/xom/wrappers/XercesDOMParser.java0000444000175000017500000000632011543216467024024 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/XercesDOMParser.java#4 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // klo, 1 August, 2001 */ package org.eigenbase.xom.wrappers; import org.eigenbase.xom.DOMWrapper; import org.eigenbase.xom.XOMException; import org.apache.xerces.dom.DocumentImpl; import org.apache.xerces.parsers.DOMParser; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import java.io.IOException; /** * This private helper class presents a GenericDOMParser using Xerces, with * simple error handling appropriate for a testing environment. */ public class XercesDOMParser extends GenericDOMParser { private DOMParser parser; /** * Constructs a non-validating Xerces DOM Parser. */ public XercesDOMParser() throws XOMException { this(false); } /** * Constructs a Xerces DOM Parser. * @param validate whether to enable validation */ public XercesDOMParser(boolean validate) throws XOMException { parser = new DOMParser(); try { if (!validate) { parser.setFeature(VALIDATION_FEATURE, false); parser.setFeature(LOAD_EXTERNAL_DTD_FEATURE, false); } } catch (SAXException e) { throw new XOMException(e, "Error setting up validation"); } parser.setErrorHandler(this); document = new DocumentImpl(); } // implement GenericDOMParser protected Document parseInputSource(InputSource in) throws XOMException { prepareParse(); try { parser.parse(in); } catch (SAXException ex) { // Display any pending errors handleErrors(); throw new XOMException(ex, "Document parse failed"); } catch (IOException ex) { // Display any pending errors handleErrors(); throw new XOMException(ex, "Document parse failed"); } handleErrors(); return parser.getDocument(); } // implement Parser public DOMWrapper create(String tagName) { Node node = document.createElement(tagName); return new W3CDOMWrapper(node, this); } } // End XercesDOMParser.java resgen/src/org/eigenbase/xom/wrappers/W3CDOMWrapper.java0000444000175000017500000001534511543216467023362 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/W3CDOMWrapper.java#5 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // dsommerfield, 16 July, 2001 */ package org.eigenbase.xom.wrappers; import org.eigenbase.xom.*; import org.w3c.dom.CharacterData; import org.w3c.dom.*; /** * This implementation of DOMWrapper wraps any w3c DOM-compliant java * XML Parser. */ public class W3CDOMWrapper implements DOMWrapper { final Node node; private final Locator locator; /** * W3CDOMWrapper parses XML based on a Node. The Node may be either an * Element or some form of text node. * * @param node DOM Node * @param locator Callback to find location of node. May be null. */ public W3CDOMWrapper(Node node, Locator locator) { this.node = node; this.locator = locator; } /** * Map the Node's type to DOMWrapper's simplified concept of type. */ public int getType() { int nodeType = node.getNodeType(); switch (nodeType) { case Node.ELEMENT_NODE: return ELEMENT; case Node.COMMENT_NODE: return COMMENT; case Node.CDATA_SECTION_NODE: return CDATA; case Node.TEXT_NODE: return FREETEXT; default: return UNKNOWN; } } /** * Retrieve the tag name directly. Return null immediately if not an * element. **/ public String getTagName() { if (getType() != ELEMENT) { return null; } return ((Element)node).getTagName(); } /** * Return the attribute. Return null if the attribute isn't defined, * or if not an element. This behavior differs from the underlying DOM, * which returns an empty string for undefined attributes. */ public String getAttribute(String attrName) { if (getType() != ELEMENT) { return null; } String attrVal = ((Element)node).getAttribute(attrName); if (attrVal == null || attrVal.length() == 0) { return null; } else { return attrVal; } } // implement DOMWrapper public String[] getAttributeNames() { NamedNodeMap map = node.getAttributes(); int count = map.getLength(); String[] attributeNames = new String[count]; for (int i = 0; i < count; i++) { attributeNames[i] = map.item(i).getLocalName(); } return attributeNames; } /** * Recursively unwrap and create the contained text. If the node is a * comment, return the comment text; but ignore comments inside elements. **/ public String getText() { if (node instanceof Comment) { return ((Comment)node).getData(); } else { StringBuffer sbuf = new StringBuffer(); appendNodeText(node, sbuf); return sbuf.toString(); } } // implement DOMWrapper public String toXML() { boolean onlyElements = false; return XOMUtil.wrapperToXml(this, onlyElements); } /** * Helper to collect all Text nodes into a buffer. */ private static void appendNodeText(Node node, StringBuffer sbuf) { if (node instanceof Comment) { // ignore it } else if (node instanceof CharacterData) { // Text sbuf.append(((CharacterData)node).getData()); } else if (node instanceof Element) { NodeList nodeList = node.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { appendNodeText(nodeList.item(i), sbuf); } } } /** * Retrieve all children, and build an array of W3CDOMWrappers around * each child that is of TEXT or ELEMENT type to return. */ public DOMWrapper[] getChildren() { if (getType() != ELEMENT) { return new DOMWrapper[0]; } NodeList nodeList = node.getChildNodes(); // Count the elements that are TEXT or ELEMENTs. int count = 0; for (int i = 0; i < nodeList.getLength(); i++) { Node nextNode = nodeList.item(i); if (nextNode instanceof Element || nextNode instanceof Text) { count++; } } // Create and populate the array DOMWrapper[] ret = new DOMWrapper[count]; count = 0; for (int i = 0; i < nodeList.getLength(); i++) { Node nextNode = nodeList.item(i); if (nextNode instanceof Element || nextNode instanceof Text) { ret[count++] = new W3CDOMWrapper(nextNode, locator); } } // Done. return ret; } /** * Retrieve all children, and build an array of W3CDOMWrappers around * each ELEMENT child. */ public DOMWrapper[] getElementChildren() { if (getType() != ELEMENT) { return new DOMWrapper[0]; } NodeList nodeList = node.getChildNodes(); // Count the elements that are TEXT or ELEMENTs. int count = 0; for (int i = 0; i < nodeList.getLength(); i++) { Node nextNode = nodeList.item(i); if (nextNode instanceof Element) { count++; } } // Create and populate the array DOMWrapper[] ret = new DOMWrapper[count]; count = 0; for (int i = 0; i < nodeList.getLength(); i++) { Node nextNode = nodeList.item(i); if (nextNode instanceof Element) { ret[count++] = new W3CDOMWrapper(nextNode, locator); } } // Done. return ret; } public Location getLocation() { return locator.getLocation(this); } } // End W3CDOMWrapper.java resgen/src/org/eigenbase/xom/DefWalker.java0000444000175000017500000001126611543216467021064 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/DefWalker.java#3 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2000-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // dsommerfield, 18 February, 2001 */ package org.eigenbase.xom; import java.lang.reflect.Array; import java.util.Vector; /** * DefWalker is a class designed to help users of plugin elements and elements * with content type ANY. It walks through an array of ElementDef, searching * for and returning portions as the correct types. */ public class DefWalker { private NodeDef[] defs; private int pos; /** * Construct a DefWalker, attaching it to a NodeDef array and * specifying a PrintWriter to display error messages for later * consumption. * @param defs a NodeDef array to walk. All returned objects * come from this array. */ public DefWalker(NodeDef[] defs) { this.defs = defs; pos = 0; } /** * Returns the next node in the defs array, but only if it matches * the provided class elemType. * @param elemType the Class of NodeDef to expect. This class will * always be assignable from the returned object. * @throws XOMException if there are no more nodes in the defs * array or if the next node is of an incorrect type. */ public NodeDef expect(Class elemType) throws XOMException { if(pos >= defs.length) throw new XOMException("Expecting a Node of type " + elemType.getName() + " but no " + "Nodes remain."); if(!(elemType.isAssignableFrom(defs[pos].getClass()))) throw new XOMException("Expecting a Node of type " + elemType.getName() + " but " + "found a Node of type " + defs[pos].getClass().getName()); return defs[pos++]; } /** * Returns a portion of the remaining nodes in the defs array as an * array. All nodes in the array will be of the specified class * elemType. The nodes are returned as a generic NodeDef[] * array and may need to be explicitly converted to an array of the * appropriate type by the caller. * @param elemType the Class of NodeDef to expect and return. This * class will always be assignable from each returned object in the * array. */ public NodeDef[] expectArray(Class elemType) { Vector found = new Vector(); while(pos < defs.length && elemType.isAssignableFrom(defs[pos].getClass())) found.addElement(defs[pos++]); NodeDef[] ret = new NodeDef[found.size()]; for(int i=0; ielemType. The nodes are in an array of the specified type, * which will be returned as an object (which must be cast to the * appropriate array type by the caller when needed. * @param elemType the Class of NodeDef to expect and return. This * class will always be assignable from each returned object in the * array. */ public Object expectTypeArray(Class elemType) { Vector found = new Vector(); while(pos < defs.length && elemType.isAssignableFrom(defs[pos].getClass())) found.addElement(defs[pos++]); Object ret = Array.newInstance(elemType, found.size()); for(int i=0; iTextDef represents piece of textual data in an XML document. * Free text (such as Some text) is represented by an actual * TextDef; comments (such as <-- a comment -->) * by derived class {@link CommentDef}; and CDATA sections (such as * <![CDATA[Some text]]>) by derived class {@link CdataDef}. * * @author jhyde * @since 5 October, 2001 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/TextDef.java#4 $ **/ public class TextDef implements NodeDef { public String s; /** * Whether to print the data as is -- never quote as a CDATA * section. Useful if the fragment contains a valid XML string. **/ boolean asIs; private Location location; public TextDef() { this(null, false, null); } public TextDef(String s) { this(s, false, null); } public TextDef(String s, boolean asIs) { this(s, asIs, null); } public TextDef(String s, boolean asIs, Location location) { this.s = s; this.asIs = asIs; this.location = location; } public TextDef(org.eigenbase.xom.DOMWrapper _def) throws org.eigenbase.xom.XOMException { switch (_def.getType()) { case DOMWrapper.FREETEXT: case DOMWrapper.CDATA: case DOMWrapper.COMMENT: break; default: throw new XOMException( "cannot make CDATA/PCDATA element from a " + _def.getType()); } this.s = _def.getText(); this.location = _def.getLocation(); } // override ElementDef public String getName() { return null; } // override ElementDef public String getText() { return s; } // implement NodeDef public NodeDef[] getChildren() { return XOMUtil.emptyNodeArray; } // implement NodeDef public DOMWrapper getWrapper() { return null; } // implement NodeDef public int getType() { return DOMWrapper.FREETEXT; } // implement NodeDef public void display(PrintWriter pw, int indent) { pw.print(s); } // override NodeDef public void displayXML(XMLOutput out, int indent) { if (out.getIgnorePcdata()) { return; } out.beginNode(); if (asIs) { out.print(s); } else { boolean quote = true; out.cdata(s, quote); } } // implement NodeDef public Location getLocation() { return location; } } // End TextDef.java resgen/src/org/eigenbase/xom/MetaGenerator.java0000444000175000017500000026100111543216467021747 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/MetaGenerator.java#8 $ // package org.eigenbase.xom is an XML Object Mapper // Copyright (C) 2005-2010 The Eigenbase Project // Copyright (C) 2005-2010 Disruptive Tech // Copyright (C) 2005-2010 Red Square, Inc. // Portions Copyright (C) 2000-2008 Kana Software, Inc. and others. // All Rights Reserved. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public // License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. // // dsommerfield, 26 December, 2000 */ package org.eigenbase.xom; import java.io.*; import java.util.*; /** * MetaGenerator is a utility class which reads a XOM Meta * Model description in XML and generates the corresponding .dtd and .java * definition files. MetaGenerator is invoked during the build process to help * generate files for the build. **/ public class MetaGenerator { /** * Private member to hold the active model to be generated. */ private MetaDef.Model model; /** * Private member. This is model.prefix, except that it is "" if * model.prefix is null, rather than null. */ private String prefix; private Hashtable keywordMap; private Hashtable typeMap; private Hashtable infoMap; private Hashtable subclassMap; private Vector allTypes; private boolean testMode; private static final String newLine = System.getProperty("line.separator"); private static final char fileSep = System.getProperty("file.separator").charAt(0); /** * This helper class contains all necessary information about a type. * The information is collected here to help support inheritence and * other advanced features. */ private class TypeInfo { // XML definition of the type. Includes defined attributes, // content, and other information. public MetaDef.Definition def; // Documentation and code, here for easy reference. public String doc; public String code; // Name of the class and associated XML tag. public String name; public String className; public String tagName; // This array holds all attributes, inherited or otherwise, that may // be used by this type. public MetaDef.Attribute[] allAttributes; // This array holds all attributes that are overridden by this type. public MetaDef.Attribute[] ovrAttributes; // This array holds all new attributes defined only in this type // and not overriding any inherited attributes. public MetaDef.Attribute[] newAttributes; // This array holds all content, inherited or otherwise, that may // be used by this type. public MetaDef.Content[] allContent; // This array holds all new content defined only in this type. public MetaDef.Content[] newContent; // True if content is (either defined or inherited). public boolean isAny; // True if content is (either defined or inherited). public boolean isCData; // References to superclass info public TypeInfo[] superInfos; // Class to use when importing elements. public Class impClass; public String impName; // e.g. "foo.MetaDef.Tag" public String contentModel; public TypeInfo(MetaDef.Definition elt) throws XOMException { def = elt; // Get the name and superclass name name = null; MetaDef.Attribute[] attributes; MetaDef.Content[] content; contentModel = "sequential"; Vector superInfoList = new Vector(); if (elt instanceof MetaDef.Element) { MetaDef.Element element = (MetaDef.Element) elt; name = element.type; if (element.dtdName != null) { tagName = element.dtdName; } else { tagName = prefix + name; } registerSuper(superInfoList, element._class); attributes = element.attributes; content = element.content; contentModel = element.contentModel; doc = element.doc; code = element.code; impClass = null; impName = null; } else if (elt instanceof MetaDef.Plugin) { name = ((MetaDef.Plugin)elt).type; tagName = prefix + name; registerSuper(superInfoList, ((MetaDef.Plugin)elt)._class); attributes = ((MetaDef.Plugin)elt).attributes; content = new MetaDef.Content[0]; doc = ((MetaDef.Plugin)elt).doc; code = ((MetaDef.Plugin)elt).code; impClass = null; impName = null; } else if (elt instanceof MetaDef.Class) { name = ((MetaDef.Class)elt)._class; tagName = "(%" + name + ";)"; registerSuper(superInfoList, ((MetaDef.Class)elt).superclass); attributes = ((MetaDef.Class)elt).attributes; content = ((MetaDef.Class)elt).content; doc = ((MetaDef.Class)elt).doc; code = ((MetaDef.Class)elt).code; impClass = null; impName = null; } else if (elt instanceof MetaDef.StringElement) { name = ((MetaDef.StringElement)elt).type; tagName = prefix + name; attributes = new MetaDef.Attribute[0]; content = new MetaDef.Content[0]; doc = ((MetaDef.StringElement)elt).doc; code = null; impClass = null; impName = null; } else if (elt instanceof MetaDef.Import) { MetaDef.Import imp = (MetaDef.Import)elt; name = imp.type; if (imp.dtdName != null) { tagName = imp.dtdName; } else { tagName = prefix + name; } attributes = new MetaDef.Attribute[0]; content = new MetaDef.Content[0]; doc = null; code = null; try { impName = imp.defPackage + "." + imp.defClass + "." + name; impClass = Class.forName(imp.defPackage + "." + imp.defClass + "$" + name); } catch (ClassNotFoundException ex) { // throw new XOMException( // "Import " + name + " references Java Class " // + imp.defPackage + "." + imp.defClass // + "." + name + " that does not exist."); } } else { throw new XOMException("Illegal element type " + elt.getClass().getName()); } className = XOMUtil.capitalize(name); superInfos = (TypeInfo[]) superInfoList.toArray( new TypeInfo[superInfoList.size()]); // Check for special content ( or ). If we find it, // it must be the only content defined. boolean newAny = false; boolean newCData = false; if (content.length == 1) { if (content[0] instanceof MetaDef.CData) { newCData = true; } else if (content[0] instanceof MetaDef.Any) { newAny = true; } } // Make sure that or occurs only by itself. if (!newAny && !newCData) { for (int i = 0; i < content.length; i++) { if (content[i] instanceof MetaDef.CData || content[i] instanceof MetaDef.Any) { throw new XOMException( "Type " + name + " defines or " + "content as well as other content."); } } } // Do we have a superclass/supertype? if (superInfos.length == 0) { // No supertype, so consider this type by itself. allAttributes = attributes; ovrAttributes = new MetaDef.Attribute[0]; newAttributes = allAttributes; if (newAny || newCData) { isAny = newAny; isCData = newCData; allContent = new MetaDef.Content[0]; } else { isAny = isCData = false; allContent = content; } newContent = allContent; } else { // Reconcile attributes. Hashtable attrHash = new Hashtable(); Hashtable ovrHash = new Hashtable(); Vector allAttrs = new Vector(); Vector ovrAttrs = new Vector(); Vector newAttrs = new Vector(); for (int j = 0; j < superInfos.length; j++) { TypeInfo superInfo = superInfos[j]; for (int i = 0; i < superInfo.allAttributes.length; i++) { attrHash.put( superInfo.allAttributes[i].name, superInfo.allAttributes[i]); } } for (int i = 0; i < attributes.length; i++) { // Does the attribute already exist? MetaDef.Attribute inhAttr = (MetaDef.Attribute)(attrHash.get(attributes[i].name)); if (inhAttr == null) { // attribute doesn't exist, so add to all and new. allAttrs.addElement(attributes[i]); newAttrs.addElement(attributes[i]); } else { // attribute does exist. Type must match exactly. if (!(attributes[i].type.equals(inhAttr.type))) { throw new XOMException( "Element " + name + " inherits attribute " + inhAttr.name + " of type " + inhAttr.type + " but redefines it to be of type " + attributes[i].type); } // Add to overridden vector and overridden hashtable ovrAttrs.addElement(attributes[i]); ovrHash.put(attributes[i].name, attributes[i]); } } // Add all non-overridden attributes to the allAttributes vector boolean superAny = false, superCData = false; for (int j = 0; j < superInfos.length; j++) { TypeInfo superInfo = superInfos[j]; for (int i = 0; i < superInfo.allAttributes.length; i++) { if (ovrHash.get(superInfo.allAttributes[i].name) == null) { allAttrs.addElement(superInfo.allAttributes[i]); } } if (superInfo.isAny) { superAny = true; } if (superInfo.isCData) { superCData = true; } } // Add all overridden attributes to the allAttributes vector for (int i = 0; i < ovrAttrs.size(); i++) { allAttrs.addElement(ovrAttrs.elementAt(i)); } allAttributes = new MetaDef.Attribute[allAttrs.size()]; for (int i = 0; i < allAttributes.length; i++) { allAttributes[i] = (MetaDef.Attribute) allAttrs.elementAt(i); } ovrAttributes = new MetaDef.Attribute[ovrAttrs.size()]; for (int i = 0; i < ovrAttributes.length; i++) { ovrAttributes[i] = (MetaDef.Attribute) ovrAttrs.elementAt(i); } newAttributes = new MetaDef.Attribute[newAttrs.size()]; for (int i = 0; i < newAttributes.length; i++) { newAttributes[i] = (MetaDef.Attribute) newAttrs.elementAt(i); } // Reconcile content. First check for specials. if (newAny || newCData) { for (int j = 0; j < superInfos.length; j++) { TypeInfo superInfo = superInfos[j]; if (superInfo.isAny || superInfo.isCData) { throw new XOMException( "Element " + name + " both defines and " + "inherits or content."); } if (superInfo.allContent.length > 0) { throw new XOMException( "Element " + name + " inherits standard " + "content but defines or " + "content."); } } isAny = newAny; isCData = newCData; allContent = new MetaDef.Content[0]; newContent = new MetaDef.Content[0]; } else if (superAny || superCData) { if (content.length > 0) { throw new XOMException( "Element " + name + " inherits or " + "content but defines standard content."); } isAny = superAny; isCData = superCData; allContent = new MetaDef.Content[0]; newContent = new MetaDef.Content[0]; } else { isAny = isCData = false; // Overriding of content is forbidden. Hashtable contentHash = new Hashtable(); Vector allContentVec = new Vector(); Vector newContentVec = new Vector(); newContentVec.addAll(Arrays.asList(content)); for (int j = 0; j < superInfos.length; j++) { TypeInfo superInfo = superInfos[j]; for (int i = 0; i < superInfo.allContent.length; i++) { if (!superInfo.isInterface()) { contentHash.put( getContentName(superInfo.allContent[i]), superInfo.allContent[i]); } else { newContentVec.addElement( superInfo.allContent[i]); } allContentVec.addElement(superInfo.allContent[i]); } } for (int i = 0; i < content.length; i++) { MetaDef.Content inhContent = (MetaDef.Content) (contentHash.get(getContentName(content[i]))); if (inhContent != null) { throw new XOMException( "Content named " + getContentName(content[i]) + " defined in element " + name + " was " + "already defined in an inherited element."); } allContentVec.addElement(content[i]); } allContent = new MetaDef.Content[allContentVec.size()]; for (int i = 0; i < allContent.length; i++) { allContent[i] = (MetaDef.Content) allContentVec.elementAt(i); } newContent = new MetaDef.Content[newContentVec.size()]; for (int i = 0; i < newContent.length; i++) { newContent[i] = (MetaDef.Content) newContentVec.elementAt(i); } } } // Add ourself to the hashtable if we're not already there if (infoMap.get(name) == null) { infoMap.put(name, this); } } private void registerSuper(Vector superInfoList, String className) throws XOMException { if (className == null) { return; } final String[] classNames = className.split(","); for (int i = 0; i < classNames.length; i++) { superInfoList.add(lookupSuper(classNames[i].trim())); } } /** * Get the TypeInfo record for the superclass. If we don't find * it, we'll have to create it by looking up its definition. * * @param superName Name of superClass * @throws XOMException */ private TypeInfo lookupSuper(String superName) throws XOMException { TypeInfo superInfo = (TypeInfo) infoMap.get(superName); if (superInfo == null) { MetaDef.Definition superDef = (MetaDef.Definition) infoMap.get(superName); if (superDef == null) { throw new XOMException( "Parent class " + superName + " of element " + name + " was never defined."); } superInfo = new TypeInfo(superDef); } return superInfo; } /** * Returns whether this type is implemented by an Java interface. */ private boolean isInterface() { return def instanceof MetaDef.Class; } public void writeJavaClass(PrintWriter out) throws XOMException { // Documentation first if (doc != null) { writeJavaDoc(out, 1, doc); } // Then create the inner class. String classDesc; StringBuffer extendsList = new StringBuffer(); StringBuffer implementsList = new StringBuffer(); if (def instanceof MetaDef.Class) { classDesc = "interface"; for (int j = 0; j < superInfos.length; j++) { TypeInfo superInfo = superInfos[j]; if (superInfo.isInterface()) { append( extendsList, " extends ", ", ", superInfo.className); } else { throw new RuntimeException( "Superclass of a Class must be a Class: " + className + " extends " + superInfo.className); } } if (extendsList.length() == 0) { extendsList.append(" extends org.eigenbase.xom.NodeDef"); } } else { final MetaDef.Element element = (MetaDef.Element) def; classDesc = "static " + (element._abstract != null && element._abstract.booleanValue() ? "abstract " : "") + "class"; for (int j = 0; j < superInfos.length; j++) { TypeInfo superInfo = superInfos[j]; if (superInfo.isInterface()) { append( implementsList, " implements ", ", ", superInfo.className); } else { append( extendsList, " extends ", ", ", superInfo.className); } } if (extendsList.length() == 0) { extendsList.append(" extends org.eigenbase.xom.ElementDef"); } } out.println("\tpublic " + classDesc + " " + className + extendsList + implementsList); if (isAny) { out.println("\t\timplements org.eigenbase.xom.Any"); } if (def instanceof MetaDef.Class) { out.println("\t{"); // Add the code section, if defined if (code != null) { writeJavaCode(out, 2, code); } // Complete the class definition and finish with a blank. out.println("\t}"); out.println(); return; } out.println("\t{"); // Default constructor out.println("\t\tpublic " + className + "()"); out.println("\t\t{"); out.println("\t\t}"); out.println(); // org.eigenbase.xom.DOMWrapper Constructor out.println("\t\tpublic " + className + "(org.eigenbase.xom.DOMWrapper _def)"); out.println("\t\t\tthrows org.eigenbase.xom.XOMException"); out.println("\t\t{"); // Body of constructor. Special case for completely empty // model (no content and no attributes) to avoid warnings // about unused things. boolean mixed = contentModel.equals("mixed"); if (allContent.length == 0 && allAttributes.length == 0 && !isAny && !isCData && !(def instanceof MetaDef.Plugin)) { // constructor has no body } else { if (def instanceof MetaDef.Element && booleanValue( new Boolean[] { ((MetaDef.Element) def).keepDef, model.defaultKeepDef, Boolean.FALSE})) { out.println("\t\t\tthis._def = _def;"); } out.println("\t\t\ttry {"); // Plugins: read defPackage and defClass here. if (def instanceof MetaDef.Plugin) { out.println("\t\t\t\tdefPackage = " + "org.eigenbase.xom.DOMElementParser." + "requiredDefAttribute(" + "_def, \"defPackage\", \"org.eigenbase.xom\");"); out.println("\t\t\t\tdefClass = org.eigenbase.xom.DOMElementParser." + "requiredDefAttribute(" + "_def, \"defClass\", null);"); // Get the enclosure class we'll be using out.println("\t\t\t\tClass _pluginClass = " + "org.eigenbase.xom.DOMElementParser.getPluginClass(" + "defPackage, defClass);"); } // Create the parser. If using a Plugin, parse from a // different enclosure class. out.print("\t\t\t\torg.eigenbase.xom.DOMElementParser _parser " + "= new org.eigenbase.xom.DOMElementParser(" + "_def, "); if (def instanceof MetaDef.Plugin) { out.println("\"\", _pluginClass);"); } else { if (model.prefix == null) { out.print("\"\", "); } else { out.print("\"" + model.prefix + "\", "); } out.println(model.className + ".class);"); } // Define a temp array if any Array elements are used if (hasContentType(allContent, MetaDef.Array.class)) { out.println("\t\t\t\torg.eigenbase.xom.NodeDef[] " + "_tempArray;"); } // Generate statements to read in all attributes. for (int i = 0; i < allAttributes.length; i++) { writeJavaGetAttribute(out, allAttributes[i]); } // Generate statements to read in all content. if (def instanceof MetaDef.Plugin) { writeJavaGetPluginContent(out, mixed); } else if (isAny) { writeJavaGetAnyContent(out, mixed); } else if (isCData) { writeJavaGetCDataContent(out); } else { for (int i = 0; i < allContent.length; i++) { writeJavaGetContent(out, allContent[i]); } } out.println("\t\t\t} catch(org.eigenbase.xom.XOMException _ex) {"); out.println("\t\t\t\tthrow new org.eigenbase.xom.XOMException(" + "\"In \" + getName() + \": \" + _ex.getMessage());"); out.println("\t\t\t}"); } // Finish the constructor out.println("\t\t}"); out.println(); // Declare all attributes inherited from superclass, if superclass // is an interface. (Because interfaces can't have attributes.) for (int j = 0; j < superInfos.length; j++) { TypeInfo superInfo = superInfos[j]; if (superInfo.isInterface()) { for (int i = 0; i < superInfo.newAttributes.length; i++) { writeJavaDeclareAttribute( out, superInfo.newAttributes[i]); } } } // Declare all new attributes for (int i = 0; i < newAttributes.length; i++) { writeJavaDeclareAttribute(out, newAttributes[i]); } if (def instanceof MetaDef.Plugin) { writeJavaDeclarePluginAttributes(out); } if (def instanceof MetaDef.Element && booleanValue( new Boolean[] { ((MetaDef.Element) def).keepDef, model.defaultKeepDef, Boolean.FALSE})) { out.println("\t\tpublic org.eigenbase.xom.DOMWrapper _def;"); } out.println(); // Declare all new content if (def instanceof MetaDef.Plugin) { writeJavaDeclarePluginContent(out, mixed); } else if (isAny) { writeJavaDeclareAnyContent(out, mixed); } else if (isCData) { writeJavaDeclareCDataContent(out); } else { for (int i = 0; i < newContent.length; i++) { writeJavaDeclareContent(out, newContent[i]); } } out.println(); // Create the getName() function out.println("\t\tpublic String getName()"); out.println("\t\t{"); out.println("\t\t\treturn \"" + className + "\";"); out.println("\t\t}"); out.println(); // Create the display() function out.println("\t\tpublic void display(java.io.PrintWriter _out, " + "int _indent)"); out.println("\t\t{"); if (def instanceof MetaDef.Class && !isAny && !isCData && allContent.length == 0 && allAttributes.length == 0) { } else { out.println("\t\t\t_out.println(getName());"); } for (int i = 0; i < allAttributes.length; i++) { writeJavaDisplayAttribute(out, allAttributes[i]); } if (def instanceof MetaDef.Plugin) { writeJavaDisplayPluginAttributes(out); } if (def instanceof MetaDef.Plugin) { writeJavaDisplayPluginContent(out); } else if (isAny) { writeJavaDisplayAnyContent(out); } else if (isCData) { writeJavaDisplayCDataContent(out); } else { for (int i = 0; i < allContent.length; i++) { writeJavaDisplayContent(out, allContent[i]); } } out.println("\t\t}"); // Create the displayXML() function out.println("\t\tpublic void displayXML(" + "org.eigenbase.xom.XMLOutput _out, " + "int _indent)"); out.println("\t\t{"); out.println("\t\t\t_out.beginTag(\"" + tagName + "\", " + "new org.eigenbase.xom.XMLAttrVector()"); for (int i = 0; i < allAttributes.length; i++) { writeJavaDisplayXMLAttribute(out, allAttributes[i]); } if (def instanceof MetaDef.Plugin) { writeJavaDisplayXMLPluginAttributes(out); } out.println("\t\t\t\t);"); if (def instanceof MetaDef.Plugin) { writeJavaDisplayXMLPluginContent(out); } else if (isAny) { writeJavaDisplayXMLAnyContent(out); } else if (isCData) { writeJavaDisplayXMLCDataContent(out); } else { for (int i = 0; i < allContent.length; i++) { writeJavaDisplayXMLContent(out, allContent[i]); } } out.println("\t\t\t_out.endTag(\"" + tagName + "\");"); out.println("\t\t}"); // Create the displayDiff() function out.println("\t\tpublic boolean displayDiff(" + "org.eigenbase.xom.ElementDef _other, " + "java.io.PrintWriter _out, " + "int _indent)"); out.println("\t\t{"); if (allAttributes.length > 0 || allContent.length > 0 || isAny || isCData || def instanceof MetaDef.Plugin) { out.println("\t\t\t" + className + " _cother = (" + className + ")_other;"); } int[] diffCount = {0}; for (int i = 0; i < newAttributes.length; i++) { writeJavaDisplayDiffAttribute(out, diffCount, allAttributes[i]); } if (def instanceof MetaDef.Plugin) { writeJavaDisplayDiffPluginAttributes(out, diffCount); } if (def instanceof MetaDef.Plugin) { writeJavaDisplayDiffPluginContent(out, diffCount); } else if (isAny) { writeJavaDisplayDiffAnyContent(out, diffCount); } else if (isCData) { writeJavaDisplayDiffCDataContent(out, diffCount); } else { for (int i = 0; i < allContent.length; i++) { writeJavaDisplayDiffContent(out, diffCount, allContent[i]); } } out.println("\t\t\treturn " + (diffCount[0] > 0 ? "_diff" : "true") + ";"); out.println("\t\t}"); // Add the code section, if defined if (code != null) { writeJavaCode(out, 2, code); } // Complete the class definition and finish with a blank. out.println("\t}"); out.println(); } } private void append( StringBuffer buf, String first, String next, String s) { if (buf.length() == 0) { buf.append(first); } else { buf.append(next); } buf.append(s); } /** * Converts a {@link Boolean} object into a {@code boolean} value, * falling back to successive defaults if values are null. * *

If all of the values are null, returns {@code false}; but we * recommend passing in an explicit {@code true} or {@code false} as the * last argument.

* *

For example, * {@code booleanValue(null, true, false)} returns {@code true}; * {@code booleanValue(null, null)} returns {@code false}.

* * @param bs One or more boolean values * @return Boolean value */ private static boolean booleanValue(Boolean[] bs) { for (int i = 0; i < bs.length; i++) { Boolean b = bs[i]; if (b != null) { return b.booleanValue(); } } return false; } /** * Get the name of any piece of content of any type. * @return the name of the piece of content. * @throws XOMException if the content is or . */ private static String getContentName(MetaDef.Content content) throws XOMException { if (content instanceof MetaDef.Object) { return ((MetaDef.Object)content).name; } else if (content instanceof MetaDef.Array) { return ((MetaDef.Array)content).name; } else { throw new XOMException( "Content of type " + content.getClass().getName() + " does not have a name."); } } /** * Return the TypeInfo class associated with the given name. * * @post fail == false || return != null * @exception XOMException if the type has not been defined */ public TypeInfo getTypeInfo(String name, boolean fail) throws XOMException { TypeInfo info = (TypeInfo) infoMap.get(name); if (info == null && fail == true) { throw new XOMException( "Type " + name + " does not exist."); } return info; } /** * Construct a MetaGenerator from an XML file. The XML should meet the * specifications of the XOM Meta Model. * @param xmlFile a filename for the xml description of the model to be * processed. */ public MetaGenerator(String xmlFile, boolean testMode) throws XOMException, IOException { this(xmlFile, testMode, null); } protected MetaGenerator(String xmlFile, boolean testMode, String className) throws XOMException, IOException { this.testMode = testMode; // Create a non-validating XML parser to parse the file FileInputStream in = new FileInputStream(xmlFile); Parser parser = XOMUtil.createDefaultParser(); try { DOMWrapper def = parser.parse(in); model = new MetaDef.Model(def); } catch (XOMException ex) { throw new XOMException(ex, "Failed to parse XML file: " + xmlFile); } // check that class names are consistent if (className != null) { if (model.className == null) { model.className = className; } else { String modelClassName = model.className; if (model.packageName != null && !model.packageName.equals("")) { modelClassName = model.packageName + "." + model.className; } if (!className.equals(modelClassName)) { throw new XOMException( "className parameter (" + className + ") is inconsistent with model's packageName and " + "className attributes (" + modelClassName + ")"); } } } // Construct the meta model from its XML description prefix = model.prefix; if (prefix == null) { prefix = ""; } // Setup the Hashtable maps initKeywordMap(); initTypeMap(); initSubclassMap(); } /** * Initialize the keyword map. This class maps all Java keywords to safe * versions (prepended with an underscore) which may be used for generated * names. Java keywords are listed in the java spec at * * http://java.sun.com/docs/books/jls/html/3.doc.html#229308 */ private void initKeywordMap() { keywordMap = new Hashtable(); keywordMap.put("abstract", "_abstract"); keywordMap.put("boolean", "_boolean"); keywordMap.put("break", "_break"); keywordMap.put("byte", "_byte"); keywordMap.put("case", "_case"); keywordMap.put("catch", "_catch"); keywordMap.put("char", "_char"); keywordMap.put("class", "_class"); keywordMap.put("const", "_const"); keywordMap.put("continue", "_continue"); keywordMap.put("default", "_default"); keywordMap.put("do", "_do"); keywordMap.put("double", "_double"); keywordMap.put("else", "_else"); keywordMap.put("extends", "_extends"); keywordMap.put("final", "_final"); keywordMap.put("finally", "_finally"); keywordMap.put("float", "_float"); keywordMap.put("for", "_for"); keywordMap.put("if", "_if"); keywordMap.put("implements", "_implements"); keywordMap.put("import", "_import"); keywordMap.put("instanceof", "_instanceof"); keywordMap.put("int", "_int"); keywordMap.put("interface", "_interface"); keywordMap.put("long", "_long"); keywordMap.put("native", "_native"); keywordMap.put("new", "_new"); keywordMap.put("goto", "_goto"); keywordMap.put("package", "_package"); keywordMap.put("private", "_private"); keywordMap.put("protected", "_protected"); keywordMap.put("public", "_public"); keywordMap.put("return", "_return"); keywordMap.put("short", "_short"); keywordMap.put("static", "_static"); keywordMap.put("super", "_super"); keywordMap.put("switch", "_switch"); keywordMap.put("synchronized", "_synchronized"); keywordMap.put("this", "_this"); keywordMap.put("throw", "_throw"); keywordMap.put("throws", "_throws"); keywordMap.put("transient", "_transient"); keywordMap.put("try", "_try"); keywordMap.put("void", "_void"); keywordMap.put("volatile", "_volatile"); keywordMap.put("while", "_while"); keywordMap.put("true", "_true"); keywordMap.put("false", "_false"); keywordMap.put("null", "_null"); } /** * All Elements in the meta model have an associated type name which * identifies the element. The type map allows the XMLDef.ElementType * object describing an element to be retrieved from its name. It is * used to resolve references to element type names appearing * throughout a model. */ private void initTypeMap() throws XOMException { typeMap = new Hashtable(); allTypes = new Vector(); for (int i = 0; i < model.elements.length; i++) { MetaDef.Definition elt = model.elements[i]; String name = null; if (elt instanceof MetaDef.Element) { name = ((MetaDef.Element)elt).type; } else if (elt instanceof MetaDef.Plugin) { name = ((MetaDef.Plugin)elt).type; } else if (elt instanceof MetaDef.Class) { name = ((MetaDef.Class)elt)._class; } else if (elt instanceof MetaDef.StringElement) { name = ((MetaDef.StringElement)elt).type; } else if (elt instanceof MetaDef.Import) { name = ((MetaDef.Import)elt).type; } else { throw new XOMException( "Illegal element type " + elt.getClass().getName()); } typeMap.put(name, elt); allTypes.addElement(name); } infoMap = new Hashtable(); for (int i = 0; i < model.elements.length; i++) { // Get the element MetaDef.Definition elt = model.elements[i]; // Construct the new TypeInfo object and add to the hashtable TypeInfo info = new TypeInfo(elt); infoMap.put(info.name, info); } } /** * In a few cases, a complete list of all subclasses of a class * object is required. The subclass map maps each class object * (identified by its name) to a Vector containing all of its * subclasses. Currently, all subclasses must be Element types. */ private void initSubclassMap() throws XOMException { subclassMap = new Hashtable(); // First, iterate through all Class elements in the model, // initializing a location in the hashtable for each. for (int i = 0; i < model.elements.length; i++) { MetaDef.Definition elt = model.elements[i]; if (elt instanceof MetaDef.Class) { MetaDef.Class _class = (MetaDef.Class)elt; subclassMap.put(_class._class, new Vector()); } if (elt instanceof MetaDef.Element) { MetaDef.Element element = (MetaDef.Element)elt; subclassMap.put(element.type, new Vector()); } } // Now, iterate through all Element elements in the model. // For each one, go through all of its superclasses and add itself to // the vector of each. // If a class is not found, it is an error. for (int i = 0; i < model.elements.length; i++) { MetaDef.Definition elt = model.elements[i]; if (elt instanceof MetaDef.Element) { MetaDef.Element elem = (MetaDef.Element)elt; TypeInfo info = getTypeInfo(elem.type, true); addToSubclassMap(elem, info); } } } /** * Helper method for initSubclassMap: * Add this element to the subclass map for each superclass of info. */ private void addToSubclassMap(MetaDef.Element elem, TypeInfo info) throws XOMException { // Add to all superclasses as well for (int j = 0; j < info.superInfos.length; j++) { TypeInfo superInfo = info.superInfos[j]; // Add the element to this class's vector. Vector vec = (Vector)(subclassMap.get(superInfo.name)); if (vec == null) { throw new XOMException("Class " + superInfo.name + " of element " + elem.type + " is not defined."); } vec.addElement(elem); addToSubclassMap(elem, superInfo); } } /** * Create all files associated with the metamodel, including a Java class * and a DTD file. The DTD is primarily for reference--it will not work * if any advanced features (plugins, includes) are used. * @param outputDirName the output directory in which to generate the files. */ public void writeFiles(String outputDirName, String dtdFileName) throws XOMException, IOException { // Compute the output file names if (dtdFileName != null) { if (model.dtdName == null) { model.dtdName = dtdFileName; } else { if (!dtdFileName.equals(model.dtdName)) { throw new XOMException( "dtdFileName parameter (" + dtdFileName + ") is inconsistent with model's dtdName " + "attribute (" + model.dtdName + ")"); } } } File javaOutputDir = new File(outputDirName); if (!testMode && model.packageName != null && !model.packageName.equals("")) { javaOutputDir = new File( javaOutputDir, model.packageName.replace('.',fileSep)); } File javaFile = new File(javaOutputDir, model.className + ".java"); File outputDir = javaFile.getParentFile(); File dtdFile = new File(outputDir, model.dtdName); // If the output file is MetaDef.java, and we start writing to // MetaDef.java before we have loaded MetaDef.class, the system thinks // that the class is out of date. So load MetaDef.class before that // point. XOMUtil.discard(new MetaDef()); // Create directories if necessary. outputDir.mkdir(); // Open the files for writing FileWriter dtdWriter = new FileWriter(dtdFile); PrintWriter dtdOut = new PrintWriter(dtdWriter); FileWriter javaWriter = new FileWriter(javaFile); PrintWriter javaOut = new PrintWriter(javaWriter); if (!testMode) { System.out.println("Writing " + dtdFile); } writeDtd(dtdOut); dtdOut.flush(); dtdWriter.close(); if (!testMode) { System.out.println("Writing " + javaFile); } writeJava(javaOut); javaOut.flush(); javaWriter.close(); if (!testMode) { System.out.println("Done"); } } public void writeDtd(PrintWriter out) throws XOMException { // Write header information for the dtd out.println(""); out.println(); // Write toplevel documentation here writeDtdDoc(out, model.doc); // For each CLASS definition, write an entity definition. These must // be done before regular elements because entities must be defined // before use. for (int i = 0; i < model.elements.length; i++) { if (model.elements[i] instanceof MetaDef.Class) { writeDtdEntity(out, (MetaDef.Class)(model.elements[i])); } } // Write each element in turn for (int i = 0; i < model.elements.length; i++) { writeDtdElement(out, model.elements[i]); } } public void writeJava(PrintWriter out) throws XOMException { // Write header information for the java file out.println("/" + "*"); out.println("/" + "/ This java file was automatically generated"); out.println("/" + "/ from XOM model '" + model.name + "'"); if (!testMode) { out.println("/" + "/ on " + new Date().toString()); } out.println("/" + "/ Do not edit this file by hand."); out.println("*" + "/"); out.println(); if (!testMode && !(model.packageName == null || model.packageName.equals(""))) { out.println("package " + model.packageName + ";"); } if (!testMode && !(model.importName == null || model.importName.equals(""))) { // generate import statements (separated by : when more than one) int colonLoc = model.importName.indexOf(":"); int start = 0; while (colonLoc != -1) { out.println("import " + model.importName.substring(start, colonLoc) + ";"); start = colonLoc + 1; colonLoc = model.importName.indexOf(":", start); } out.println("import " + model.importName.substring(start) + ";"); } // Write the toplevel documentation for the package. This becomes // the toplevel documentation for the class and is also placed at // the top of the Dtd. String extraDoc = newLine + "

This class was generated from XOM model '" + model.name + "' on " + new Date().toString(); if (testMode) { extraDoc = ""; } writeJavaDoc(out, 0, model.doc + extraDoc); // Begin the class. Include a getXMLDefClass() function which // simply returns this class. out.println("public class " + model.className + " {"); out.println(); out.println("\tpublic static java.lang.Class getXMLDefClass()"); out.println("\t{"); out.println("\t\treturn " + model.className + ".class;"); out.println("\t}"); out.println(); // Create a static member that names all Elements that may be // used within this class. out.println("\tpublic static String[] _elements = {"); for (int i = 0; i < allTypes.size(); i++) { String type = (String) allTypes.elementAt(i); out.print("\t\t\"" + type + "\""); if (i < allTypes.size() - 1) { out.println(","); } else { out.println(); } } out.println("\t};"); out.println(); // Create an inner class for each Class/Object definition. for (int i = 0; i < model.elements.length; i++) { writeJavaElement(out, model.elements[i]); } // End the class out.println(); out.println("}"); } /** * Writes an entity definition based on a defined Class. Because entity * definitions must appear before use in a DTD, this function must be * called for each defined class before processing the rest of the model. * @param out PrintWriter to write the DTD. * @param _class Class definition on which the Entity will be based. */ private void writeDtdEntity(PrintWriter out, MetaDef.Class _class) { // Documentation first if (_class.doc != null) { writeDtdDoc(out, _class.doc); } // Lookup the subclass vector for this class. Use this to generate // the entity definition. Vector subclassVec = (Vector)(subclassMap.get(_class._class)); out.print(""); out.println(); } private void writeDtdElement(PrintWriter out, MetaDef.Definition elt) throws XOMException { // What is written into the dtd depends on the class of elt. if (elt instanceof MetaDef.Element) { // Get the info class for this element. MetaDef.Element element = (MetaDef.Element)elt; TypeInfo info = getTypeInfo(element.type, false); if (info == null) { throw new AssertFailure( "Element type " + element.type + " is missing from the " + "type map."); } // Documentation first if (element.doc != null) { writeDtdDoc(out, element.doc); } // Then content model. Special case empty models. out.print(""); // Finally, attribute list if (info.allAttributes.length > 0) { out.println(""); } // Finish with a blank out.println(); } else if (elt instanceof MetaDef.Class) { // Do nothing--entities are handled ahead of time. } else if (elt instanceof MetaDef.StringElement) { // Get the info class for this element. MetaDef.StringElement element = (MetaDef.StringElement)elt; TypeInfo info = (TypeInfo)(infoMap.get(element.type)); if (info == null) { throw new AssertFailure( "StringElement type " + element.type + " is missing from the type map."); } // Documentation first if (element.doc != null) { writeDtdDoc(out, element.doc); } // Then content model. It is always (#PCDATA). out.println(""); out.println(); } else if (elt instanceof MetaDef.Plugin) { // Get the info class for this element. MetaDef.Plugin plugin = (MetaDef.Plugin)elt; TypeInfo info = (TypeInfo)(infoMap.get(plugin.type)); if (info == null) { throw new AssertFailure( "Plugin element " + plugin.type + " is missing from the type map."); } // Documentation first if (plugin.doc != null) { writeDtdDoc(out, plugin.doc); } // Then content model. It is always ANY. out.println(""); // Finally, attribute list. Don't allow use of plugin reserved // attributes defPackage and defClass. out.println(""); out.println(); } else if (elt instanceof MetaDef.Import) { // Get the info class for this element. MetaDef.Import imp = (MetaDef.Import)elt; TypeInfo info = getTypeInfo(imp.type, true); // Imports can't really be handled, so just generate a placeholder // ANY element for show. out.println(""); out.println(); } else { throw new XOMException("Unrecognized element type definition: " + elt.getClass().getName()); } } private void writeDtdDoc(PrintWriter out, String doc) { out.println(""); } private void writeJavaDoc(PrintWriter out, int indent, String doc) { for (int i = 0; i < indent; i++) { out.print("\t"); } out.println("/" + "**"); // Process the String line-by-line. Trim whitespace from each // line and ignore fully blank lines. try { LineNumberReader reader = new LineNumberReader(new StringReader(doc)); String line; while ((line = reader.readLine()) != null) { String trimLine = line.trim(); if (!trimLine.equals("")) { for (int i = 0; i < indent; i++) { out.print("\t"); } out.print(" * "); out.println(trimLine); } } } catch (IOException ex) { throw new AssertFailure(ex); } for (int i = 0; i < indent; i++) { out.print("\t"); } out.println(" *" + "/"); } private void writeJavaCode(PrintWriter out, int indent, String code) { for (int i = 0; i < indent; i++) { out.print("\t"); } out.println("/" + "/ BEGIN pass-through code block ---"); // Process the String line-by-line. Don't trim lines--just echo try { LineNumberReader reader = new LineNumberReader(new StringReader(code)); String line; while ((line = reader.readLine()) != null) { out.println(line); } } catch (IOException ex) { throw new AssertFailure(ex); } for (int i = 0; i < indent; i++) { out.print("\t"); } out.println("/" + "/ END pass-through code block ---"); } private MetaDef.Definition getType(String name) throws XOMException { // The type mapping hash table maps element type names to their // MetaDef.Definition objects. First, look up the element type associated // with the name. MetaDef.Definition type = (MetaDef.Definition) typeMap.get(name); if (type == null) { throw new XOMException( "Element type name " + name + " was never defined."); } return type; } /** * Deterimines if a name conflicts with a Java keyword. If so, it returns * an alternate form of the name (typically the same name with an * underscore preprended). * @param name a name to be used in a Java program. * @return a safe form of the name; either the name itself or a modified * version if the name is a keyword. */ private String getDeclaredName(String name) { String mappedName = (String) keywordMap.get(name); if (mappedName == null) { return name; } else { return mappedName; } } private void writeDtdContent(PrintWriter out, MetaDef.Content content) throws XOMException { if (content instanceof MetaDef.Object) { MetaDef.Object obj = (MetaDef.Object)content; TypeInfo info = (TypeInfo)(infoMap.get(obj.type)); if (info == null) { throw new XOMException( "Object " + obj.name + " has undefined type " + obj.type); } out.print(info.tagName); if (!obj.required.booleanValue()) { out.print("?"); } } else if (content instanceof MetaDef.Array) { MetaDef.Array array = (MetaDef.Array)content; TypeInfo info = (TypeInfo)(infoMap.get(array.type)); if (info == null) { throw new XOMException( "Array " + array.name + " has undefined type " + array.type); } out.print("(" + info.tagName + ")"); if (array.min.intValue() > 0) { out.print("+"); } else { out.print("*"); } } else { throw new XOMException("Unrecognized content type definition: " + content.getClass().getName()); } } private void writeDtdAttribute(PrintWriter out, MetaDef.Attribute attr) { // Attribute name out.print(attr.name + " "); // Values, or CDATA if unspecified if (attr.values == null || attr.values.length == 0) { if (attr.type.equalsIgnoreCase("Boolean")) { out.print("(true|false) "); } else { out.print("CDATA "); } } else { out.print("("); for (int i = 0; i < attr.values.length; i++) { out.print(attr.values[i]); if (i < attr.values.length - 1) { out.print("|"); } } out.print(") "); } // Default value if (attr._default == null) { if (attr.required.booleanValue()) { out.println("#REQUIRED"); } else { out.println("#IMPLIED"); } } else { out.print("\"" + attr._default + "\""); out.println(); } } /** * This helper function returns true if any member of the given content * array is of the specified type. * @param content an array of content descriptors. * @param match a Class describing the class to match. * @return true if any member of the given content array matches * the given match type. */ private static boolean hasContentType(MetaDef.Content[] content, Class match) { for (int i = 0; i < content.length; i++) { if (content[i].getClass() == match) { return true; } } return false; } private void writeJavaElement(PrintWriter out, MetaDef.Definition elt) throws XOMException { // What is written into the dtd depends on the class of elt. if (elt instanceof MetaDef.Element) { MetaDef.Element element = (MetaDef.Element)elt; TypeInfo info = (TypeInfo)(infoMap.get(element.type)); if (info == null) { throw new XOMException( "Element type " + element.type + " was never defined."); } info.writeJavaClass(out); } else if (elt instanceof MetaDef.Plugin) { MetaDef.Plugin plugin = (MetaDef.Plugin)elt; TypeInfo info = (TypeInfo)(infoMap.get(plugin.type)); if (info == null) { throw new XOMException( "Plugin type " + plugin.type + " was never defined."); } info.writeJavaClass(out); } else if (elt instanceof MetaDef.Class) { MetaDef.Class _class = (MetaDef.Class)elt; TypeInfo info = (TypeInfo)(infoMap.get(_class._class)); if (info == null) { throw new XOMException( "Class type " + _class._class + " was never defined."); } info.writeJavaClass(out); } else if (elt instanceof MetaDef.StringElement) { // Documentation first MetaDef.StringElement element = (MetaDef.StringElement)elt; if (element.doc != null) { writeJavaDoc(out, 1, element.doc); } // Declare the name as a constant out.println("\tpublic static final String " + element.type + " = \"" + element.type + "\";"); out.println(); } else if (elt instanceof MetaDef.Import) { // Do nothing--imports are handled inline } else { throw new XOMException("Unrecognized element type definition: " + elt.getClass().getName()); } } public void writeJavaGetAttribute(PrintWriter out, MetaDef.Attribute attr) throws XOMException { out.print("\t\t\t\t" + getDeclaredName(attr.name) + " = "); out.print("(" + attr.type + ")_parser.getAttribute("); out.print("\"" + attr.name + "\", \"" + attr.type + "\", "); if (attr._default == null) { out.print("null, "); } else { out.print("\"" + attr._default + "\", "); } if (attr.values == null || attr.values.length == 0) { out.print("null, "); } else { out.print("_" + getDeclaredName(attr.name) + "_values, "); } if (attr.required.booleanValue()) { out.print("true"); } else { out.print("false"); } out.println(");"); } public void writeJavaDeclareAttribute(PrintWriter out, MetaDef.Attribute attr) throws XOMException { // Setup an array for attribute values if required if (attr.values != null && attr.values.length > 0) { out.println("\t\t/** Allowable values for {@link #" + getDeclaredName(attr.name) + "}. */"); out.print("\t\tpublic static final String[] _" + getDeclaredName(attr.name) + "_values = {"); for (int i = 0; i < attr.values.length; i++) { out.print("\"" + attr.values[i] + "\""); if (i < attr.values.length - 1) { out.print(", "); } } out.println("};"); } // Generate the declaration, including a quick comment out.print("\t\tpublic " + attr.type + " " + getDeclaredName(attr.name) + "; /" + "/ "); if (attr._default != null) { out.print("attribute default: " + attr._default); } else if (attr.required.booleanValue()) { out.print("required attribute"); } else { out.print("optional attribute"); } out.println(); } public void writeJavaDisplayAttribute(PrintWriter out, MetaDef.Attribute attr) throws XOMException { // Generate the display line out.println("\t\t\tdisplayAttribute(_out, \"" + attr.name + "\", " + getDeclaredName(attr.name) + ", _indent+1);"); } public void writeJavaDisplayXMLAttribute(PrintWriter out, MetaDef.Attribute attr) throws XOMException { out.println("\t\t\t\t.add(\"" + attr.name + "\", " + getDeclaredName(attr.name) + ")"); } public void writeJavaDisplayDiffAttribute( PrintWriter out, int[] diffCount, MetaDef.Attribute attr) throws XOMException { out.println("\t\t\t" + prefix(diffCount) + "displayAttributeDiff(\"" + attr.name + "\", " + getDeclaredName(attr.name) + ", _cother." + getDeclaredName(attr.name) + ", _out, _indent+1);"); } public void writeJavaGetContent(PrintWriter out, MetaDef.Content content) throws XOMException { if (content instanceof MetaDef.Object) { // Get the object and its type MetaDef.Object obj = (MetaDef.Object)content; MetaDef.Definition type = getType(obj.type); TypeInfo info = getTypeInfo(obj.type, true); out.print("\t\t\t\t" + getDeclaredName(obj.name) + " = "); // Behavior depends on the type if (type != null && type instanceof MetaDef.Import) { // Get the info object for the import info = getTypeInfo(((MetaDef.Import)type).type, true); // Call the class constructor directly. out.print("(" + info.impName + ")_parser.getElement("); out.print(info.impName + ".class, "); } else if (type != null && type instanceof MetaDef.StringElement) { out.print("_parser.getString(" + info.className + ", "); } else { out.print("(" + info.className + ")_parser.getElement("); out.print(info.className + ".class, "); } if (obj.required.booleanValue()) { out.print("true"); } else { out.print("false"); } out.println(");"); } else if (content instanceof MetaDef.Array) { // Get the object and its type MetaDef.Array array = (MetaDef.Array)content; MetaDef.Definition type = getType(array.type); String typeName = getTypeInfo(array.type, true).className; if (type instanceof MetaDef.Import) { // Get the info object for the import TypeInfo info = getTypeInfo(((MetaDef.Import)type).type, true); // Construct the array out.print("\t\t\t\t_tempArray = _parser.getArray("); out.print(info.impName + ".class, "); out.println(array.min + ", " + array.max + ");"); out.println("\t\t\t\t" + getDeclaredName(array.name) + " = new " + info.impName + "[_tempArray.length];"); out.println("\t\t\t\tfor (int _i = 0; _i < " + getDeclaredName(array.name) + ".length; _i++)"); out.println("\t\t\t\t\t" + getDeclaredName(array.name) + "[_i] = " + "(" + typeName + ")_tempArray[_i];"); } else if (type instanceof MetaDef.StringElement) { out.print("\t\t\t\t" + getDeclaredName(array.name) + " = _parser.getStringArray("); out.println("\"" + typeName + "\", " + array.min + ", " + array.max + ");"); } else { out.print("\t\t\t\t_tempArray = _parser.getArray("); out.print(typeName + ".class, "); out.println(array.min + ", " + array.max + ");"); out.println("\t\t\t\t" + getDeclaredName(array.name) + " = new " + typeName + "[_tempArray.length];"); out.println("\t\t\t\tfor (int _i = 0; _i < " + getDeclaredName(array.name) + ".length; _i++)"); out.println("\t\t\t\t\t" + getDeclaredName(array.name) + "[_i] = " + "(" + typeName + ")_tempArray[_i];"); } } else { throw new XOMException("Unrecognized content type definition: " + content.getClass().getName()); } } public void writeJavaGetAnyContent(PrintWriter out, boolean mixed) { if (mixed) { out.println("\t\t\t\tchildren = getMixedChildren(" + "_def, " + model.className + ".class, " + "\"" + prefix + "\");"); } else { out.println("\t\t\t\tchildren = getElementChildren(" + "_def, " + model.className + ".class, " + "\"" + prefix + "\");"); } } public void writeJavaGetCDataContent(PrintWriter out) { out.println("\t\t\t\tcdata = _parser.getText();"); } public void writeJavaDeclareContent(PrintWriter out, MetaDef.Content content) throws XOMException { if (content instanceof MetaDef.Object) { // Write documentation (if any) MetaDef.Object obj = (MetaDef.Object)content; if (obj.doc != null) { writeJavaDoc(out, 2, obj.doc); } // Handle includes MetaDef.Definition type = getType(obj.type); String typeName = getTypeInfo(obj.type, true).className; // Write content declaration. if (type instanceof MetaDef.Import) { // Get the info object for the import TypeInfo info = getTypeInfo(((MetaDef.Import)type).type, true); typeName = info.impName; out.print("\t\tpublic " + typeName + " " + getDeclaredName(obj.name) + "; /" + "/"); } else if (type instanceof MetaDef.StringElement) { out.print("\t\tpublic String " + getDeclaredName(obj.name) + "; /" + "/"); } else { out.print("\t\tpublic " + typeName + " " + getDeclaredName(obj.name) + "; /" + "/"); } // Write a brief comment. if (obj.required.booleanValue()) { out.println("required element"); } else { out.println("optional element"); } } else if (content instanceof MetaDef.Array) { // Write documentation (if any) MetaDef.Array array = (MetaDef.Array)content; if (array.doc != null) { writeJavaDoc(out, 2, array.doc); } MetaDef.Definition type = getType(array.type); String typeName = getTypeInfo(array.type, true).className; // Write content declaration. if (type instanceof MetaDef.Import) { // Get the info object for the import TypeInfo info = getTypeInfo(((MetaDef.Import)type).type, true); typeName = info.impName; out.print("\t\tpublic " + typeName + "[] " + getDeclaredName(array.name) + "; /" + "/"); } else if (type instanceof MetaDef.StringElement) { out.print("\t\tpublic String[] " + getDeclaredName(array.name) + "; /" + "/"); } else { out.print("\t\tpublic " + typeName + "[] " + getDeclaredName(array.name) + "; /" + "/"); } // Write a brief comment. if (array.min.intValue() <= 0 && array.max.intValue() <= 0) { out.println("optional array"); } else { if (array.min.intValue() > 0) { out.print("min " + array.min); } if (array.max.intValue() > 0) { out.print("max " + array.max); } out.println(); } } else { throw new XOMException("Unrecognized content type definition: " + content.getClass().getName()); } } public void writeJavaDeclareAnyContent(PrintWriter out, boolean mixed) { out.println("\t\tpublic org.eigenbase.xom." + (mixed ? "NodeDef" : "ElementDef") + "[] children; /" + "/holder for variable-type children"); out.println("\t\t// implement Any"); out.println("\t\tpublic org.eigenbase.xom.NodeDef[] getChildren()"); out.println("\t\t{"); out.println("\t\t\treturn children;"); out.println("\t\t}"); out.println("\t\t// implement Any"); out.println("\t\tpublic void setChildren(org.eigenbase.xom.NodeDef[] children)"); out.println("\t\t{"); out.println("\t\t\tthis.children = " + (mixed ? "" : "(org.eigenbase.xom.ElementDef[]) ") + "children;"); out.println("\t\t}"); } public void writeJavaDeclareCDataContent(PrintWriter out) { out.print("\t\tpublic String cdata; /" + "/ All text goes here"); } public void writeJavaDisplayContent(PrintWriter out, MetaDef.Content content) throws XOMException { if (content instanceof MetaDef.Object) { MetaDef.Object obj = (MetaDef.Object)content; MetaDef.Definition type = getType(obj.type); if (type instanceof MetaDef.StringElement) { out.println("\t\t\tdisplayString(_out, \"" + obj.name + "\", " + getDeclaredName(obj.name) + ", _indent+1);"); } else { out.println("\t\t\tdisplayElement(_out, \"" + obj.name + "\", (org.eigenbase.xom.ElementDef) " + getDeclaredName(obj.name) + ", _indent+1);"); } } else if (content instanceof MetaDef.Array) { MetaDef.Array array = (MetaDef.Array)content; MetaDef.Definition type = getType(array.type); if (type instanceof MetaDef.StringElement) { out.println("\t\t\tdisplayStringArray(_out, \"" + array.name + "\", " + getDeclaredName(array.name) + ", _indent+1);"); } else { out.println("\t\t\tdisplayElementArray(_out, \"" + array.name + "\", " + getDeclaredName(array.name) + ", _indent+1);"); } } else { throw new XOMException("Unrecognized content type definition: " + content.getClass().getName()); } } public void writeJavaDisplayAnyContent(PrintWriter out) { // Display the fixed children array out.println("\t\t\tdisplayElementArray(_out, \"children\"" + ", children, _indent+1);"); } public void writeJavaDisplayCDataContent(PrintWriter out) { // Display the text as "cdata" out.println("\t\t\tdisplayString(_out, \"cdata\", " + "cdata, _indent+1);"); } public void writeJavaDisplayXMLContent(PrintWriter out, MetaDef.Content content) throws XOMException { if (content instanceof MetaDef.Object) { MetaDef.Object obj = (MetaDef.Object)content; MetaDef.Definition type = getType(obj.type); if (type instanceof MetaDef.StringElement) { out.println("\t\t\tdisplayXMLString(_out, \"" + getTypeInfo(obj.type, true).tagName + "\", " + getDeclaredName(obj.name) + ");"); } else { out.println("\t\t\tdisplayXMLElement(_out," + " (org.eigenbase.xom.ElementDef) " + getDeclaredName(obj.name) + ");"); } } else if (content instanceof MetaDef.Array) { MetaDef.Array array = (MetaDef.Array)content; MetaDef.Definition type = getType(array.type); if (type instanceof MetaDef.StringElement) { out.println("\t\t\tdisplayXMLStringArray(_out, \"" + getTypeInfo(array.type, true).tagName + "\", " + getDeclaredName(array.name) + ");"); } else { out.println("\t\t\tdisplayXMLElementArray(_out, " + getDeclaredName(array.name) + ");"); } } else if (content instanceof MetaDef.Any) { // Display the fixed children array out.println("\t\t\tdisplayXMLElementArray(_out, children);"); } else if (content instanceof MetaDef.CData) { // Display the CDATA section out.println("\t\t\t_out.cdata(cdata);"); } else { throw new XOMException("Unrecognized content type definition: " + content.getClass().getName()); } } public void writeJavaDisplayXMLAnyContent(PrintWriter out) { // Display the fixed children array out.println("\t\t\tdisplayXMLElementArray(_out, children);"); } public void writeJavaDisplayXMLCDataContent(PrintWriter out) { // Display the CDATA section out.println("\t\t\t_out.cdata(cdata);"); } public void writeJavaDisplayDiffContent( PrintWriter out, int[] diffCount, MetaDef.Content content) throws XOMException { if (content instanceof MetaDef.Object) { MetaDef.Object obj = (MetaDef.Object)content; MetaDef.Definition type = getType(obj.type); if (type instanceof MetaDef.StringElement) { out.println("\t\t\t" + prefix(diffCount) + "displayStringDiff(\"" + obj.name + "\", " + getDeclaredName(obj.name) + ", " + "_cother." + getDeclaredName(obj.name) + ", " + "_out, _indent+1);"); } else { out.println("\t\t\t" + prefix(diffCount) + "displayElementDiff(\"" + obj.name + "\", " + getDeclaredName(obj.name) + ", " + "_cother." + getDeclaredName(obj.name) + ", " + "_out, _indent+1);"); } } else if (content instanceof MetaDef.Array) { MetaDef.Array array = (MetaDef.Array)content; MetaDef.Definition type = getType(array.type); if (type instanceof MetaDef.StringElement) { out.println("\t\t\t" + prefix(diffCount) + "displayStringArrayDiff(\"" + array.name + "\", " + getDeclaredName(array.name) + ", " + "_cother." + getDeclaredName(array.name) + ", " + "_out, _indent+1);"); } else { out.println("\t\t\t" + prefix(diffCount) + "displayElementArrayDiff(\"" + array.name + "\", " + getDeclaredName(array.name) + ", " + "_cother." + getDeclaredName(array.name) + ", " + "_out, _indent+1);"); } } else { throw new XOMException("Unrecognized content type definition: " + content.getClass().getName()); } } private String prefix(int[] diffCount) { if (diffCount[0]++ == 0) { return "boolean _diff = "; } else { return "_diff = _diff && "; } } public void writeJavaDisplayDiffAnyContent( PrintWriter out, int[] diffCount) { // Display the fixed children array out.println("\t\t\t" + prefix(diffCount) + "displayElementArrayDiff(\"children\", " + "children, _cother.children, _out, _indent+1);"); } public void writeJavaDisplayDiffCDataContent( PrintWriter out, int[] diffCount) { out.println("\t\t\t" + prefix(diffCount) + "displayStringDiff(\"cdata\", " + "cdata, _cother.cdata, _out, _indent+1);"); } public void writeJavaDeclarePluginAttributes(PrintWriter out) { writeJavaDoc(out, 2, "defPackage is a built-in attribute " + "defining the package of the plugin class."); out.println("\t\tpublic String defPackage;"); out.println(); writeJavaDoc(out, 2, "defClass is a built-in attribute " + "definition the plugin parser class."); out.println("\t\tpublic String defClass;"); out.println(); } public void writeJavaDisplayPluginAttributes(PrintWriter out) { // Generate two display lines out.println("\t\t\tdisplayAttribute(_out, \"defPackage\", " + "defPackage, _indent+1);"); out.println("\t\t\tdisplayAttribute(_out, \"defClass\", " + "defClass, _indent+1);"); } public void writeJavaDisplayXMLPluginAttributes(PrintWriter out) { out.println("\t\t\t\t.add(\"defPackage\", defPackage)"); out.println("\t\t\t\t.add(\"defClass\", defClass)"); } public void writeJavaDisplayDiffPluginAttributes( PrintWriter out, int[] diffCount) { out.println("\t\t\t" + prefix(diffCount) + "displayAttributeDiff(\"" + "defPackage\", defPackage, _cother.defPackage" + ", _out, _indent+1);"); out.println("\t\t\t" + prefix(diffCount) + "displayAttributeDiff(\"" + "defClass\", defClass, _cother.defClass" + ", _out, _indent+1);"); } public void writeJavaGetPluginContent(PrintWriter out, boolean mixed) { if (mixed) { out.println("\t\t\t\tchildren = getMixedChildren(" + "_def, _pluginClass, \"\");"); } else { out.println("\t\t\t\tchildren = getElementChildren(" + "_def, _pluginClass, \"\");"); } } public void writeJavaDeclarePluginContent(PrintWriter out, boolean mixed) { out.println("\t\tpublic org.eigenbase.xom." + (mixed ? "NodeDef" : "ElementDef") + "[] children; /" + "/holder for variable-type children"); } public void writeJavaDisplayPluginContent(PrintWriter out) { // Display the fixed children array out.println("\t\t\tdisplayElementArray(_out, \"children\"" + ", children, _indent+1);"); } public void writeJavaDisplayXMLPluginContent(PrintWriter out) { // Display the fixed children array out.println("\t\t\tdisplayXMLElementArray(_out, children);"); } public void writeJavaDisplayDiffPluginContent( PrintWriter out, int[] diffCount) { // Display the fixed children array out.println("\t\t\t" + prefix(diffCount) + "displayElementArrayDiff(\"children\", " + "children, _cother.children, _out, _indent+1);"); } /** * Write the name of the dtd file and java class to standard output. * This output is used by shell scripts to grab these values. * The output is only produced in test mode. */ public void writeOutputs() { if (testMode) { System.out.println(model.dtdName + " " + model.className); } } /** * Main function for MetaGenerator. Arguments: *

    *
  1. Name of XML file describing input model. *
  2. Name of output file directory. *
*/ public static void main(String[] args) { int firstArg = 0; boolean testMode = false; if (firstArg < args.length && args[firstArg].equals("-debug")) { System.err.println("MetaGenerator pausing for debugging. " + "Attach your debugger " + "and press return."); try { System.in.read(); firstArg++; } catch (IOException ex) { // Do nothing } } if (firstArg < args.length && args[firstArg].equals("-test")) { System.err.println("Ignoring package name."); testMode = true; firstArg++; } if (args.length != 2 + firstArg) { System.err.println( "Usage: java MetaGenerator [-debug] [-test] " + " "); System.exit(2); } try { MetaGenerator generator = new MetaGenerator( args[0 + firstArg], testMode); generator.writeFiles(args[1 + firstArg], null); generator.writeOutputs(); } catch (XOMException ex) { System.err.println("Generation of model failed:"); System.err.println(ex.toString()); ex.printStackTrace(); System.exit(1); } catch (IOException ex) { System.err.println("Generation of model failed:"); System.err.println(ex.toString()); ex.printStackTrace(); System.exit(1); } } /** * Display information about this generator for debug purposes. */ public void debugDisplay() { System.out.println("Model:"); System.out.println(model.toString()); } } // End MetaGenerator.java resgen/src/org/eigenbase/xom/Location.java0000444000175000017500000000641311543216467020766 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/Location.java#2 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2008-2008 The Eigenbase Project // Copyright (C) 2008-2008 Disruptive Tech // Copyright (C) 2008-2008 LucidEra, Inc. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.eigenbase.xom; /** * Represents the location of a node within its document. * *

Location is a span from a starting line and column to an ending line * and column; or alternatively, from a starting character position to an * ending character position. * * @author jhyde * @version $Id: //open/util/resgen/src/org/eigenbase/xom/Location.java#2 $ * @since Jun 6, 2008 */ public interface Location { /** * Returns the line where this node starts. * The first line in the document is 1. * * @return Line of the start of this node */ int getStartLine(); /** * Returns the column where this node starts. * The first column in the document is 1. * * @return column of the start of this node */ int getStartColumn(); /** * Returns the character position where this node starts. * The first character in the document is 0. * * @return Character position of the start of this node */ int getStartPos(); /** * Returns the line where this node ends. * The first line in the document is 1. * * @return Line of the end of this node */ int getEndLine(); /** * Returns the column where this node ends. * The first column in the document is 1. * * @return column of the end of this node */ int getEndColumn(); /** * Returns the character position where this node ends. * The first character in the document is 0. * * @return Character position of the end of this node */ int getEndPos(); /** * Returns the text of this location. * *

If this location is an element * and headOnly is true, returns only the text of the head * of the element. For example, * *

     * <Foo a="1" b="2">
     *   <Bar c="3">
     * </Foo>
     * 
* * returns "<Foo a='1' b='2'><Bar c='3'></Foo>" * if headOnly is false, "<Foo a='1' b='2'>" if it is * true. * * @param headOnly Whether to return only the head of elements * @return Source text underlying a location */ String getText(boolean headOnly); } // End Location.java resgen/src/org/eigenbase/xom/XOMException.java0000444000175000017500000000375211543216467021543 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/src/org/eigenbase/xom/XOMException.java#3 $ // Package org.eigenbase.xom is an XML Object Mapper. // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 LucidEra, Inc. // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version approved by The Eigenbase Project. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // jhyde, 18 June, 2001 */ package org.eigenbase.xom; /** * XOMException extends Exception and provides detailed error messages for * xom-specific exceptions. */ public class XOMException extends Exception { /** * Constructs a XOM exception with no message. */ public XOMException() { super(null,null); } /** * Constructs an exception with a detailed message. * *@param s - a detailed message describing the specific error */ public XOMException(String s) { super(s,null); } /** * Constructs an exception based on another exception, so that * the exceptions may be chained. * @param cause the exception on which this one is based. * @param s a message for this portion of the exception. */ public XOMException(Throwable cause, String s) { super(s,cause); } } // End XOMException.java resgen/example/0000755000175000017500000000000011543216467013701 5ustar drazzibdrazzibresgen/example/source/0000755000175000017500000000000011543216467015201 5ustar drazzibdrazzibresgen/example/source/happy/0000755000175000017500000000000011543216467016322 5ustar drazzibdrazzibresgen/example/source/happy/BirthdayResource.xml0000444000175000017500000000376711543216467022335 0ustar drazzibdrazzib Happy Birthday, {0}! You don''t look {1,number}. {0} has not been born yet. You don't look {1,number}, {0}! very.]]> resgen/example/source/happy/BirthdayResource_fr_FR.properties0000444000175000017500000000027411543216467024775 0ustar drazzibdrazzib# $Id: //open/util/resgen/example/source/happy/BirthdayResource_fr_FR.properties#2 $ # French properties file MonRG example. HappyBirthday=Bon anniversaire, {0}! {1,number}, quel bon âge. resgen/example/source/JarTest.java0000444000175000017500000000272511543216467017424 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/example/source/JarTest.java#1 $ // package org.eigenbase.resgen is an i18n resource generator // Copyright (C) 2008-2008 The Eigenbase Project // Copyright (C) 2008-2008 Disruptive Tech // Copyright (C) 2008-2008 LucidEra, Inc. // All Rights Reserved. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public // License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. // // ResGen test code. */ import java.lang.reflect.*; import java.net.*; public class JarTest { public static void main(String [] args) throws Exception { URL [] urls = new URL[1]; urls[0] = new URL(args[0]); URLClassLoader classLoader = new URLClassLoader(urls); Class c = classLoader.loadClass("Birthday"); Method m = c.getMethod("runTest", new Class[0]); m.invoke(null, new Object[0]); } } // End JarTest.java resgen/example/source/Birthday.java0000444000175000017500000000351311543216467017612 0ustar drazzibdrazzib/* // $Id: //open/util/resgen/example/source/Birthday.java#3 $ // package org.eigenbase.resgen is an i18n resource generator // Copyright (C) 2005-2005 The Eigenbase Project // Copyright (C) 2005-2005 Disruptive Tech // Copyright (C) 2005-2005 Red Square, Inc. // Portions Copyright (C) 2002-2005 Kana Software, Inc. and others. // All Rights Reserved. // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public // License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. // // ResGen example code. */ import happy.BirthdayResource; import java.util.Locale; public class Birthday { static void wishHappyBirthday(String name, int age) { if (age < 0) { throw BirthdayResource.instance().newTooYoung(name); } System.out.println(BirthdayResource.instance().getHappyBirthday(name, new Integer(age))); } public static void main(String[] args) { runTest(); } public static void runTest() { wishHappyBirthday("Fred", 33); try { wishHappyBirthday("Wilma", -3); } catch (Throwable e) { System.out.println("Received " + e); } BirthdayResource.setThreadLocale(Locale.FRANCE); wishHappyBirthday("Pierre", 22); } } resgen/example/build.xml0000444000175000017500000000640611543216467015526 0ustar drazzibdrazzib resgen/README0000444000175000017500000000077411543216467013134 0ustar drazzibdrazzibEigenbase ResGen An internationalization tool for Java applications. ---------------------------------------------------------------------- HOME PAGE http://eigenbase.sourceforge.net/resgen ---------------------------------------------------------------------- LICENSE See file COPYING for details. ------------------------------------------------------------ ACKNOWLEDGEMENTS The project is currently hosted on Sourceforge as part of The Eigenbase Project http://sourceforge.net/projects/eigenbase resgen/doc/0000755000175000017500000000000011543216467013013 5ustar drazzibdrazzibresgen/doc/Resource.xsl0000444000175000017500000000357011543216467015335 0ustar drazzibdrazzib
Static?
Locale
Exception class

Id Name Message text
resgen/doc/index.html0000444000175000017500000007212311543216467015013 0ustar drazzibdrazzib Eigenbase ResGen specification

ResGen: Eigenbase Resource Generator

Julian Hyde; last updated September, 2005.


ResGen (the Eigenbase Resource Generator) helps you build and maintain internationalized applications in Java. From a simple XML file, it generates classes to access those resources in a type-safe manner. It is tightly integrated with ANT, to make the development process painless; and it supports a variety of schemes to determine the current locale.

Let's take a look at a simple example.

Example

The following example shows how you would define a simple resource file, generate resource classes from it, and use those classes in your own code.

Create a resource file

First, create a resource file like the following, BirthdayResource_en_US.xml:

<?xml version="1.0" ?>
<?xml-stylesheet type="text/xsl" href="Resource.xsl" ?>
<resourceBundle locale="en_US">
  <message name="HappyBirthday">
    <text>Happy Birthday, {0}! You don''t look {1,number}.</text>
  </message>
  <exception name="TooYoung" className="RuntimeException">
    <text>{0} has not been born yet.</text>
  </exception>
</resourceBundle>

The top-level element of a resource file is always a <resourceBundle>, and the only necessary property is the locale of the current file. Its children are a mixture of <message> and <exception> elements. Each must have a name attribute and a <text> child holding the message string.

Create ANT target

Now modify your ANT build-file, build.xml, as follows:

<taskdef name="resgen" classname="org.eigenbase.resgen.ResourceGenTask">
  <classpath path="lib/eigenbase-resgen.jar:lib/eigenbase-xom.jar"/>
</taskdef>

<target name="generate.resources">
  <resgen srcdir="source" locales="en_US">
    <include name="happy/BirthdayResource_en_US.xml"/>
  </resgen>
</target>

<target name="compile" depends="generate.resources">
  <javac srcdir="source" destdir="classes">
    <include name="happy/BirthdayResource*.java"/>
  </javac>
  <copy todir="classes">
    <fileset dir="source" includes="**/*.properties"/>
  </copy>
</target>

I have assumed that your Java source files are held in the "source" directory, and classes are compiled to classes directory, but this ought to be easy to change. If you already have a target to compile Java source files, you don't need the "compile" target; just add its contents to your own target.

Compile

Build as follows. (You need 'ant' on your path, and you will need to edit the project.classpath property in build.xml.)

$ ant
Buildfile: build.xml

generate.resources:
[resgen] Generating source\happy\BirthdayResource.java
[resgen] Generating source\happy\BirthdayResource_en_US.java
[resgen] Generating source\happy\BirthdayResource_en_US.properties

compile:
[javac] Compiling 2 source files to classes
[copy] Copying 1 files to classes

BUILD SUCCESSFUL

Total time: 3 seconds

Four files are generated.

source/happy/BirthdayResource.java:

package happy;

import java.io.IOException;
import java.util.Locale;
import org.eigenbase.resgen.*;

class BirthdayResource extends ShadowResourceBundle {
    public BirthdayResource() throws IOException {
    }
    private static String baseName = "happy.BirthdayResource";
    /**
      * Retrieves the singleton instance of {@link BirthdayResource}. If
      * the application has called {@link #setThreadLocale}, returns the
      * resource for the thread's locale.
      */
    public static synchronized BirthdayResource instance() {
        return (BirthdayResource) instance(baseName);
    }
    /**
      * Retrieves the instance of {@link BirthdayResource} for the given locale.
      */
    public static synchronized BirthdayResource instance(Locale locale) {
        return (BirthdayResource) instance(baseName, locale);
    }
    /** HappyBirthday is 'Happy Birthday, {0}! You don''t look {1,number} at all.' */
    public static final ResourceDefinition HappyBirthday = new ResourceDefinition("HappyBirthday", "Happy Birthday, {0}! You don''t look {1,number} at all.");
    public static String getHappyBirthday(String p0, Number p1) {
        return HappyBirthday.instantiate(
            getInstance(), new Object[] {p0, p1}).toString();
    }
    /** TooYoung is '{0} has not been born yet.' */
    public static final ResourceDefinition TooYoung = new ResourceDefinition("TooYoung", "{0} has not been born yet.");
    public static String getTooYoung(String p0) {
        return HappyBirthday.instantiate(
            getInstance(), new Object[] {p0}).toString();
    }
     public static RuntimeException newTooYoung(String p0) {
        return new RuntimeException(TooYoung.instantiate(
            getInstance(), new Object[] {p0}), null);
    }
    public static RuntimeException newTooYoung(String p0, Throwable err) {
        return new RuntimeException(TooYoung.instantiate(
            getInstance(), new Object[] {p0}), err);
    }
}

source/happy/BirthdayResource_en_US.java:

package happy;
import java.io.IOException;

public class BirthdayResource_en_US extends BirthdayResource {
    public BirthdayResource_en_US() throws IOException {}
}

source/happy/BirthdayResource.properties:

HappyBirthday=Happy Birthday, {0}! You don''t look {1,number}.
TooYoung={0} has not been born yet.

source/happy/BirthdayResource_en_US.properties:

# This file is intentionally blank. Add property values
# to this file to override the translations in the base
# properties file, BirthdayResource.properties.

For each resource, a getXxx() method is generated to retrieve that resource in the current locale, substituting parameters appropriately. For exception resources, an additional two newXxx() methods are generated to create (but not throw) an exception.

Tokens such as {0} and {1,number} in the message are automatically converted to method parameters of the right type. This means that if you ever change the parameters in your error message, or accidentally delete it, you code will no longer build. (If your code doesn't compile, you can fix the problem immediately; better that than getting a phone call, "I just got this really weird error...", in a few months time.)

Here's how you might use it in your code:

import happy.BirthdayResource;

public class Birthday {
    static void wishHappyBirthday(String name, int age) {
        if (age < 0) {
            throw BirthdayResource.newTooYoung(name);
        }
        System.out.println(BirthdayResource.getHappyBirthday(name, age));
    }
    public static void main(String[] args) {
        wishHappyBirthday("Fred", 33);
        wishHappyBirthday("Wilma", -3);
    }
}

This produces the following output.

Happy Birthday, Fred! You don't look 33.
RuntimeException: Wilma has not been born yet.

So there are the basics. That was easy, wasn't it? Now let's look at how you can tell the system to switch to another locale, and how you go about producing resource files for that locale.

Of locales and threads

When you ask for a message, the system needs to know the locale in order to get the right translation. There are several strategies for this.

The simplest strategy is to do nothing. Most applications run in the same locale as their host machine, and so when the system calls Locale.getDefault(), it will return the right answer.

You can switch locale by calling Locale.getDefault(Locale newLocale), but this call will affect other applications running in the same Java Virtual Machine, and is not allowed in some application server environments.

ResGen provides a method ShadowResourceBundle.setThreadLocale(Locale) to allow threads to have different locales. Threads which are working in a different locale should call this method at their entry point. For example:

System.out.println(BirthdayResource.getHappyBirthday("Fred", 33));
ShadowResourceBundle.setThreadLocale(Locale.FR);
System.out.println(BirthdayResource.getHappyBirthday("Pierre", 22));

produces the output

Happy Birthday, Fred! You don't look 33.
Bon anniversaire, Pièrre! 22, quel bon âge.

Threads which have not made this call will remain in the default locale.

This strategy may not be possible if the threading model is complex. Here, you should use an explicit resource bundle object:

BirthdayResource myResource = BirthdayResource.instance();
System.out.println(myResource.getHappyBirthday("Fred", 33));
myResource = BirthdayResource.instance(Locale.FR);
System.out.println(myResource.getHappyBirthday("Pierre", 22));

The problem is that the accessor methods (getHappyBirthday, and so forth) are static. To make them non-static, change add static="false" to the <resgen> ANT task:

<target name="generate.resources">
  <resgen srcdir="source" style="dynamic">
    <include name="happy/BirthdayResource_en_US.xml"/>
  </resgen>
</target>

Translation

So far, we've just been dealing with one resource file, and you're probably wondering why you went to all the trouble of extracting your messages and exception strings! Have no fear, there will be more. A typical development process goes as follows.

First, you develop your application for a single locale, referred to as the base locale. I have been assuming that this American English (en_US), but you can develop in any locale you choose.

You create an XML file for this language containing all the messages and exceptions used by your application. Developers are often tempted to put in hard-coded strings, but ResGen's tight integration with ANT makes it painless to modify the XML file and re-generate the wrapper as you go.

So now you have an application in the beta stage. You're written most of the code, are getting through the pile of bugs, and would like to translate the product into French (fr_FR). Recall that in the above example, we were dealing with the following set of files.

Source files happy/BirthdayResource_en_US.xml
Generated files happy/BirthdayResource.java
happy/BirthdayResource.properties
happy/BirthdayResource_en_US.java
happy/BirthdayResource_en_US.properties
Runtime files happy/BirthdayResource.class
happy/BirthdayResource.properties
happy/BirthdayResource_en_US.class
happy/BirthdayResource_en_US.properties

Do the following steps:

  1. Copy happy/BirthdayResource.properties  to happy/BirthdayResource_fr_FR.properties, and translate the messages as appropriate for the new locale:
    HappyBirthday=Bon anniversaire, {0}! {1,number}, c'est un bon age.
    TooYoung={0} n'est pas encore né(e).

     

  2. Add happy/BirthdayResource_fr_FR.properties to the ANT task:
    <target name="generate.resources">
      <resgen srcdir="source" locales="en_US,fr_FR">
        <include name="happy/BirthdayResource_en_US.xml"/>
        <include name="happy/BirthdayResource_fr_FR.properties"/>
       </resgen>
    </target>
  3. Build.

ResGen treats happy/BirthdayResource_fr_FR.properties as a source file. It generates happy/BirthdayResource_fr_FR.java from it, and validates that every resource in happy/BirthdayResource_fr_FR.properties exists in happy/BirthdayResource_en_US.xml, and has the same number and types of parameters.

In this multi-language scenario, the source and generated files are as follows (new files are shown in italic):

Source files happy/BirthdayResource_en_US.xml
happy/BirthdayResource_fr_FR.properties
Generated files happy/BirthdayResource.java
happy/BirthdayResource.properties
happy/BirthdayResource_en_US.java
happy/BirthdayResource_en_US.properties
happy/BirthdayResource_fr_FR.java
Runtime files happy/BirthdayResource.class
happy/BirthdayResource.properties
happy/BirthdayResource_en_US.class
happy/BirthdayResource_en_US.properties
happy/BirthdayResource_fr_FR.class
happy/BirthdayResource_fr_FR.properties

(Validation is not implemented yet. As well as detecting modified and deleted messages, it should also have a mode which reminds us to add new messages.)

Styles of generated code

ResGen can generate Java code in three styles: static, dynamic and functor.

Static style

In the static style, the generated Java resource class contains a resource member and several methods for each resource. In the example, the TooYoung resource had a data member and three methods:

  • public static final ResourceDefinition TooYoung;
  • public static String getTooYoung(String)
  • public static RuntimeException newTooYoung(String)
  • public static RuntimeException newTooYoung(String, Throwable)

To change style, add an attribute to your ant target:

<resgen srcdir="source" style="functor" locales="en_US">
    <include name="happy/BirthdayResource_en_US.xml"/>
</resgen>

Dynamic style

In the dynamic style, the same data member and methods are generated, but they are not static. For example,

  • public final ResourceDefinition TooYoung;
  • public String getTooYoung(String)
  • public RuntimeException newTooYoung(String)
  • public RuntimeException newTooYoung(String, Throwable)

Because the methods are not static, they have different behavior if they are invoked on different objects. Typically you have an instance of the resource bundle for each locale. These instances are accessed via the instance() and instance(Locale) methods in the resource bundle:

  • BirthdayResource.instance() returns the instance of the resource bundle for the thread's default locale.
  • BirthdayResource.instance(Locale) returns the instance of the resource bundle for the given locale.

Here's the same code example using dynamic resources:

import happy.BirthdayResource;

public class Birthday {
    static void wishHappyBirthday(String name, int age) {
        if (age < 0) {
            throw BirthdayResource.instance().newTooYoung(name);
        }
        System.out.println(BirthdayResource.instance().getHappyBirthday(name, age));
    }
    public static void main(String[] args) {
        wishHappyBirthday("Fred", 33);
        wishHappyBirthday("Wilma", -3);
    }
}

 

Functor style

In the functor style, only one data member is generated per resource, but the data member belongs to a class which has all of the necessary accessor methods. For example,

  • public final _Def0 TooYoung;
  • public class _Def0 extends ResourceDefinition {
        public String getTooYoung(String);
        public RuntimeException newTooYoung(String);
        public RuntimeException newTooYoung(String, Throwable);
    }

The accessor methods have the same purpose as the generated methods in static or dynamic style, but have different names. The str accessor method corresponds to getTooYoung, and ex corresponds newTooYoung.

Let's see how the code example looks when rewritten to use functors.

import happy.BirthdayResource;

public class Birthday {
    static void wishHappyBirthday(String name, int age) {
        if (age < 0) {
            throw BirthdayResource.instance().TooYoung.ex(name);
        }
        System.out.println(BirthdayResource.instance().HappyBirthday.str(name, age));
    }
    public static void main(String[] args) {
        wishHappyBirthday("Fred", 33);
        wishHappyBirthday("Wilma", -3);
    }
}

The code is slightly more verbose, but functors have two advantages. First, functors are genuine objects, so can be passed as callbacks. Suppose that you are designing a library method which is to create, populate, and throw an exception if it encounters an error, but which cannot be dependent upon a particular resource file. You could design the method to receive a functor, and the method could call the functor's ex() method if it has an error.

Second, they make it easy to figure out which pieces of code are using a particular resource, because there is only one access point to that resource. For example, every piece of code which uses the TooYoung resource must do so via the BirthdayResource.TooYoung data member. If no code is using the data member, you can safely obsolete the resource.

C++ Resource Support

ResGen also includes support for building and maintaining internationalized applications in C++.

Resource file format

Element Attributes
<resourceBundle>

The top-level element.

Attributes:

name description
locale The locale of resources in this file. Required.
style If dynamic (the default), generate several accessor methods per resource; if functor, generate one member per resource, with several methods.
exceptionClassName The default class of exception to generate. Must be qualified by package name, unless it is in the package java.lang. Not required; default value is "java.lang.RuntimeException". The className attribute of <exception> overrides this for a specific exception.
cppNamespace The namespace used for generated C++ files. Only used if resources are generated in C++ mode. Optional.
cppCommonInclude The name of a header file to include at the start of all generated C++ files. Optional. Only used if resources are generated in C++ mode.
cppExceptionClassName The name of the exception class to be returned by exception resources. Optional. Only used if resources are generated in C++ mode.
cppExceptionClassLocation The name of the header file to include. Should define the class referred to in cppExceptionClassName. Required if cppExceptionClassName is given.

Children:

  • Zero or more <message> or <exception> elements.
<message>

Defines a localizable message.

Attributes:

name description
name The identifier of the message. Becomes the name of the property in the generated .properties file. Required, must be unique within the resource file, and must be a valid Java identifer.

Children:

  • Zero or more <property> elements, defining properties of the resource. These properties will be accessible at runtime via the ResourceDefinition.getProperties() method.
  • A single <text> element, holding the text of the message.
<exception> Defines an exception and its associated message.

Attributes:

name description
name The identifier of the exception. Becomes the name of the property in the generated .properties file. Required, must be unique within the resource file, and must be a valid Java identifer.
className The type of exception to generate. Must be fully qualified, unless it is in the package java.lang. If not
specified, the resource bundle's default exception class is used.
cppClassName The name of the C++ exception class returned by this exception. Either this attribute or <resourceBundle>'s cppExceptionClassName must be defined.
cppClassLocation The name of a C++ header file to be included. Required if cppClassName is used.
cppChainExceptions If false (the default), only a basic constructor is need. If true the basic and chained constructors are required (see the section on C++ resources.

Children:

  • A single <text> element, holding the text of the message.
<text> The text of the message or exception. Should be in Java message format (see class java.text.MessageFormat for more details).

If the message contains XML special characters such as '<' and '&', you may find it easier to enclose the message in <![CDATA[ ... ]]>.

<property> Property of a resource.

Attributes:

name description
name The name of the property.

Children:

  • The value of the property.

API

For details on the ResGen interfaces, please see the javadoc.

Conclusion

ResGen helps you build and maintain an internationalized application. Code generation helps to leverage the power of the compiler: it detects parameters which are missing or of the wrong type, spelling mistakes, and informational messages which are being used to describe error conditions.

About ResGen

ResGen is an Eigenbase utility package, and was derived from the MonRG utility in the Mondrian project (an open-source OLAP server). Packaged distributions are available from the Eigenbase project home page at SourceForge.net. For more information, email John Sichi.


Home | This file is $Id: //open/util/resgen/doc/index.html#3 $ (log) SourceForge.net Logo
resgen/doc/overview_cpp.html0000444000175000017500000003666311543216467016425 0ustar drazzibdrazzib ResGen C++ specification

ResGen: C++ Mode

Stephan Zuercher, February 18th, 2004.

C++ Resources

In practice, ResGen supports three modes of operation:

  • Java - resources are generated as described in the main ResGen documentation.
  • C++ - resource are generated as described in this document.
  • both - Java and C++ resources are generated.

The main overview document concerns itself exclusively with ResGen's Java mode. This document explains how ResGen operates in C++ mode. See the section on the resgen ANT task for more information on selecting ResGen's mode.

ResGen's C++ mode uses the same properties files as Java mode. In addition it generates a header (.h) and source (.cpp) file for each resource bundle.

C++ framework

C++ mode requires that project using the generated resouces provide a framework for managing the messages given. The framework has the following requirements:

  1. The presence of a class named Locale in the same namespace as the generated resource files.
    • The header file for Locale must be Locale.h.
    • The Locale class must be suitable for use as a a key value in a std::map (e.g. it should define operator<).
    • It must also define a method const Locale &getDefault() that returns a suitable default locale.
  2. The presence of a class named ResourceBundle in the same namespace as the generated resource files that may be used as a base class for generated resources.
    • The header file for ResourceBundle must be ResourceBundle.h
    • ResourceBundle's must have constructor ResourceBundle(const std::string &basename, const Locale &locale, const std::string &location) where basename is the name of the resource bundle (e.g. BirthdayResource in the previous example), locale is the Locale this ResourceBundle will handle and location is the path to the directory where the ResourceBundle can find its properties file.
    • ResourceBundle is responsible for loading the properties files, handling the Java format strings (e.g. "There are {0, number} letters in {1}."), and returning messages in a format usable by ResourceDefinition. One possible implementation is to convert the Java format strings into Boost format strings.
  3. The presence of a class name ResourceDefinition in the same namespace as the generated resource files.
    • ResourceDefinitions must have a constructor ResourceDefinition(ResourceBundle *bundle, const std::string &key).
    • ResourceDefinition must implement these methods: as well as templated methods that take varying numbers of arguments:
          std::string format() const;
          template<typename t0> string format(const t0 &p0) const;
              template<typename t0, typename t1>
            string format(const t0 &p0, const t1 &p1) const;
          .
          .
          .
      Each format method should lookup up the message associated with the key given in the constructor from the ResourceBundle given in the constructor and should format the message given the arguments, returning the resulting std::string. If a format template method doesn't exist of the number of parameters in your message, a compile time error will occur.
  4. The presence of this templated method:
    template<class _GRB, class _BC, class _BC_ITER>
    _GRB *makeInstance(
        _BC &bundleCache,
        const Locale &locale);
    

    The template's arguments are a class generated by ResGen in C++ mode (e.g. BirthdayResources in the examples below), a std::map<Locale, _GRB *>, and an iterator on that map.

    The method's purpose is to look up the generated resource bundle instance in the bundle cache for the given locale. If found, it should be returned to the caller. If not found, it should be instantiated for the locale, added to the map and returned. Normally, the method would also attempt to create an instance of the parent locale's bundle by calling itself recursively. For example, when instantiating a resource bundle for the "en_US" locale, one would also instantiate a bundle for the "en" locale and set it as a parent to the "en_US" locale. The "en" locale might have a nameless locale as its parent so that all message requests are guaranteed to be filled. This logic is controlled by the ResourceBundle class and need only be implemented if you wish locales to inherit messages from their parent locales.

An example of how to create a framework appropriate for ResGen C++ resources can be found in the Fennel project.

C++ exceptions

If exception resources are used (as opposed to just message resources), you will need to provide an exception class. A default exception class for all exception resources can be given (see <resourceBundle>, below), or you can override the default on a per-resource basis. The exception class must always have a basic constructor like this one:

Excn(const std::string &msg);

If chained exceptions are enabled for an exception resource, the exception class must also have a chained constructor:

Excn(const std::string &msg, const Excn * const chained);

C++ Example

The following examples assume you're familiar with the Java example given above.

Create a resource file

First, create a resource file like the following, BirthdayResource_en_US.xml:

<?xml version="1.0" ?>
<?xml-stylesheet type="text/xsl" href="Resource.xsl" ?>
<resourceBundle
    locale="en_US"
    cppExceptionClassName="Excn"
    cppExceptionClassLocation="Excn.h">
  <message name="HappyBirthday">
    <text>Happy Birthday, {0}! You don''t look {1,number}.</text>
  </message>
  <exception name="TooYoung">
    <text>{0} has not been born yet.</text>
  </exception>
</resourceBundle>

Create ANT target

Now modify (or create) your ANT build-file, build.xml, as follows:

<taskdef name="resgen" classname="org.eigenbase.resgen.ResourceGenTask">
  <classpath path="lib/eigenbase-resgen.jar:lib/eigenbase-xom.jar"/>
</taskdef>

<target name="generate.resources">
  <resgen srcdir="source" locales="en_US">
    <include name="BirthdayResource_en_US.xml"/>
  </resgen>
</target>
</target>

I have assumed that your C++ source files are held in the "source" directory. I also assume that you'll write your own Makefile or equivalent to compile the code generated (BirthdayResource.h and BirthdayResource.cpp in this example).

Compile

Build as follows. (You need 'ant' on your path, and you will need to edit the project.classpath property in build.xml.)

$ ant
Buildfile: build.xml

generate.resources:
[resgen] Generating source\BirthdayResource.properties
[resgen] Generating source\BirthdayResource_en_US.properties
[resgen] Generating source\BirthdayResource.h
[resgen] Generating source\BirthdayResource.cpp

BUILD SUCCESSFUL

Total time: 3 seconds

Four files are generated.

source/happy/BirthdayResource.h:

// This class is generated. Do NOT modify it, or
// add it to source control.

/**
 * This class was generated
 * by class mondrian.resource.ResourceGen
 * from /BirthdayResource_en_US.xml
 * on Wed Feb 18 13:10:31 PST 2004.
 * It contains a list of messages, and methods to
 * retrieve and format those messages.
 **/

#ifndef Fennel_BirthdayResource_Included
#define Fennel_BirthdayResource_Included

#include <ctime>
#include <string>

#include "Locale.h"
#include "ResourceDefinition.h"
#include "ResourceBundle.h"

// begin includes specified by BirthdayResource_en_US.xml
#include "Excn.h"
// end includes specified by BirthdayResource_en_US.xml

using namespace std;

    /** HappyBirthday is 'Happy Birthday, {0}! You don''t look {1,number}.'     */
class HappyBirthday : public ResourceDefinition
{
  public:
  HappyBirthday(ResourceBundle *bundle, const string &key);

  string operator()(const string &p0, int p1) const;
};


    /** TooYoung is '{0} has not been born yet.'    */
class TooYoung : public ResourceDefinition
{
  public:
  TooYoung(ResourceBundle *bundle, const string &key);

  string operator()(const string &p0) const;
};


class BirthdayResource;
typedef map BirthdayResourceBundleCache;

class BirthdayResource : ResourceBundle
{
  protected:
  BirthdayResource(Locale locale);

  public:
  virtual ~BirthdayResource() { }

  static const BirthdayResource &instance();
  static const BirthdayResource &instance(const Locale &locale);

  static void setResourceFileLocation(const string &location);

  HappyBirthday HappyBirthday;

  TooYoung TooYoung;
  Excn* newTooYoung(const string &p0) const;

  template
    friend _GRB *makeInstance(_BC &bundleCache, const Locale &locale);
};

#endif // Fennel_BirthdayResource_Included

source/happy/BirthdayResource.cpp:

// This class is generated. Do NOT modify it, or
// add it to source control.

/**
 * This class was generated
 * by class mondrian.resource.ResourceGen
 * from BirthdayResource_en_US.xml
 * on Wed Feb 18 13:14:30 PST 2004.
 * It contains a list of messages, and methods to
 * retrieve and format those messages.
 **/

#include "BirthdayResource.h"
#include "ResourceBundle.h"
#include "Locale.h"

#include <map>
#include <string>

using namespace std;

#define BASENAME ("BirthdayResource")

static BirthdayResourceBundleCache bundleCache;
static string bundleLocation("");

const BirthdayResource &BirthdayResource::instance()
{
  return BirthdayResource::instance(Locale::getDefault());
}

const BirthdayResource &BirthdayResource::instance(const Locale &locale)
{
  return *makeInstance(bundleCache, locale);
}

void BirthdayResource::setResourceFileLocation(const string &location)
{
  bundleLocation = location;
}

BirthdayResource::BirthdayResource(Locale locale)
  : ResourceBundle(BASENAME, locale, bundleLocation),
    HappyBirthday(this, "HappyBirthday"),
    TooYoung(this, "TooYoung")
{ }

Excn* BirthdayResource::newTooYoung(const string &p0) const
{
  return new Excn(TooYoung.operator()(p0));
}

HappyBirthday::HappyBirthday(ResourceBundle *bundle, const string &key)
  : ResourceDefinition(bundle, key)
{ }

string HappyBirthday::operator()(const string &p0, int p1) const
{
  return format(p0, p1);
}

TooYoung::TooYoung(ResourceBundle *bundle, const string &key)
  : ResourceDefinition(bundle, key)
{ }

string TooYoung::operator()(const string &p0) const
{
  return format(p0);
}

source/happy/BirthdayResource.properties:

HappyBirthday=Happy Birthday, {0}! You don''t look {1, number}.
TooYoung={0} has not been born yet.

source/happy/BirthdayResource_en_US.properties:

# This file is intentionally blank. Add property values
# to this file to override the translations in the base
# properties file, BirthdayResource.properties.

For each resource, a member variable is generated in the generated class. The member variable allows you to use operator() to generate the resource's message with appropriate arguments substituted. In addition a newXxx() function is generated for each exception resource to retrieve an instance of that exception.

To obtain an instance of the resource bundle (e.g. BirthdayResource), use the static instance() or instance(const Locale &) methods. The former returns an instance for the default locale and the latter returns an instance for the given locale.

Tokens such as {0} and {1, number} in the message are automatically converted to method parameters of the right type. This means that if you ever change the parameters in your error message, or accidentally delete it, you code will no longer build. (If your code doesn't compile, you can fix the problem immediately; better that than getting a phone call, "I just got this really weird error...", in a few months time.)

Here's how you might use it in your code:

#include "BirthdayResource.h"

#include <iostream>
#include <string>

using namespace std;

void wishHappyBirthday(const string &name, int age) {
  if (age < 0) {
    throw BirthdayResource::instance().newTooYoung(name);
  }

  cout << BirthdayResource::instance().HappyBirthday(name, age) << endl;
}

int main(int argc, char **argv) {
  BirthdayResources::setResourceFileLocation("./");

  try {
    wishHappyBirthday("Fred", 33);
    wishHappyBirthday("Wilma", -3);
  }
  catch(Excn *x) {
    cout << "Exception: " << x->getMessage() << endl;
  }

  return 0;
}

This produces the following output.

Happy Birthday, Fred! You don't look 33.
Exception: Wilma has not been born yet.

In ResGen C++ resources, it is the framework's responsibility to handle switching from locale to locale.