001: package org.uispec4j.extension;
002:
003: import org.objectweb.asm.ClassReader;
004: import org.uispec4j.AbstractUIComponent;
005: import org.uispec4j.Panel;
006: import org.uispec4j.UIComponent;
007:
008: import java.io.File;
009: import java.io.FileOutputStream;
010: import java.util.ArrayList;
011: import java.util.List;
012: import java.util.StringTokenizer;
013: import java.util.zip.ZipEntry;
014: import java.util.zip.ZipOutputStream;
015:
016: /**
017: * Provides a means for extending UISpec4J to support user-defined components.
018: * <p>This class offers a <code>main()</code> function which generates a JAR file containing extended
019: * versions of some UISpec4J classes (for instance {@link Panel}).
020: * This JAR file is intended to be placed before the UISpec4J JAR in your classpath.
021: * <p>Arguments:
022: * <pre><code>
023: * <path> <name:class> <name:class> ...
024: * </code></pre>
025: * where:
026: * <ul>
027: * <li><code><output></code> is the path of the JAR file to be generated</li>
028: * <li>each <code><name:class></code> defines an extension, where:
029: * <ul>
030: * <li><code>name</code> is the name of the component to be integrated</li>
031: * <li><code>class</code> is the name of the component class</li>
032: * </ul>
033: * </li>
034: * </ul>
035: * For instance:
036: * <pre><code>
037: * java -cp ... org.uispec4j.extension.ExtensionGenerator lib/uispec_ext.jar Calendar:com.xxx.Calendar
038: * </code></pre>
039: * Note: When runnning this class, the UISpec4J and ASM JARs must be included in the classpath
040: * (please refer to the
041: * <a href="http://www.uispec4j.org/dependencies.html">dependencies</a> page for a list of specific JARs to be
042: * used).
043: * <p/>
044: * The component class and the associated Swing class must adhere to certain conventions:
045: * <ul>
046: * <li>The Calendar class must implement {@link UIComponent} (or better yet extend
047: * {@link AbstractUIComponent})</li>
048: * <li>The Calendar class must declare a static field TYPE_NAME providing the related type name</li>
049: * <li>The Calendar class must declare a static field SWING_CLASSES providing the related swing classes</li>
050: * <li>The Calendar class must provide one public constructor with a JCalendar parameter</li>
051: * <li>The JCalendar class must extend java.awt.Component</li>
052: * <li>The given name ("calendar") must not be already used within UISpec4J.</li>
053: * </ul>
054: * For instance:
055: * <code><pre>
056: * public class Calendar extends AbstractUIComponent {
057: * public static final String TYPE_NAME = "calendar";
058: * public static final Class[] SWING_CLASSES = {JCalendar.class};
059: * public Calendar(JCalendar calendar) {
060: * ...
061: * }
062: * }
063: * </pre></code>
064: *
065: * @see <a href="http://www.uispec4j.org/extension.html">Extending UISpec4J</a>
066: */
067: public class ExtensionGenerator {
068:
069: public static void main(String[] args) throws Exception {
070: if (args.length < 2) {
071: System.out.println("--- UISpec4J Extension Generator ---");
072: System.out.println("Arguments: <path> <name:class> "
073: + "<name:class> ...");
074: System.out.println("where:");
075: System.out
076: .println(" <path> is the path of the JAR file to be generated");
077: System.out
078: .println(" <name:class:swingClass> defines an extension, where:");
079: System.out.println(" - name is the name of the component");
080: System.out
081: .println(" - class is the name of the component class");
082: return;
083: }
084:
085: File output = new File(args[0]);
086: List extensions = new ArrayList();
087: for (int i = 1; i < args.length; i++) {
088: StringTokenizer tokenizer = new StringTokenizer(args[i],
089: ":");
090: String name = tokenizer.nextToken();
091: String className = tokenizer.nextToken();
092: extensions.add(new Extension(name, className));
093: }
094: run(output, (Extension[]) extensions
095: .toArray(new Extension[extensions.size()]));
096: }
097:
098: private static void run(File output, Extension[] extensions)
099: throws Exception {
100: String panelClassName = Panel.class.getName();
101: byte[] panelBytecode = PanelClassEnhancer.transformClass(
102: new ClassReader(panelClassName), extensions);
103:
104: ZipOutputStream outputStream = null;
105: try {
106: outputStream = new ZipOutputStream(new FileOutputStream(
107: output));
108: outputStream.putNextEntry(new ZipEntry(
109: computeClassPath(panelClassName)));
110: outputStream.write(panelBytecode);
111: outputStream.closeEntry();
112: } finally {
113: if (outputStream != null) {
114: outputStream.close();
115: }
116: }
117: }
118:
119: private static String computeClassPath(String className) {
120: return className.replace('.', '/') + ".class";
121: }
122: }
|