1package sample.vector;
2
3import java.io.IOException;
4import javassist.*;
5import sample.preproc.Assistant;
6
7/**
8 * This is a Javassist program which produce a new class representing
9 * vectors of a given type.  For example,
10 *
11 * <ul>import java.util.Vector by sample.vector.VectorAssistant(int)</ul>
12 *
13 * <p>requests the Javassist preprocessor to substitute the following
14 * lines for the original import declaration:
15 *
16 * <ul><pre>
17 * import java.util.Vector;
18 * import sample.vector.intVector;
19 * </pre></ul>
20 *
21 * <p>The Javassist preprocessor calls <code>VectorAssistant.assist()</code>
22 * and produces class <code>intVector</code> equivalent to:
23 *
24 * <ul><pre>
25 * package sample.vector;
26 *
27 * public class intVector extends Vector {
28 *   pubilc void add(int value) {
29 *     addElement(new Integer(value));
30 *   }
31 *
32 *   public int at(int index) {
33 *     return elementAt(index).intValue();
34 *   }
35 * }
36 * </pre></ul>
37 *
38 * <p><code>VectorAssistant.assist()</code> uses
39 * <code>sample.vector.Sample</code> and <code>sample.vector.Sample2</code>
40 * as a template to produce the methods <code>add()</code> and
41 * <code>at()</code>.
42 */
43public class VectorAssistant implements Assistant {
44    public final String packageName = "sample.vector.";
45
46    /**
47     * Calls <code>makeSubclass()</code> and produces a new vector class.
48     * This method is called by a <code>sample.preproc.Compiler</code>.
49     *
50     * @see sample.preproc.Compiler
51     */
52    public CtClass[] assist(ClassPool pool, String vec, String[] args)
53	throws CannotCompileException
54    {
55	if (args.length != 1)
56	    throw new CannotCompileException(
57			"VectorAssistant receives a single argument.");
58
59	try {
60	    CtClass subclass;
61	    CtClass elementType = pool.get(args[0]);
62	    if (elementType.isPrimitive())
63		subclass = makeSubclass2(pool, elementType);
64	    else
65		subclass = makeSubclass(pool, elementType);
66
67	    CtClass[] results = { subclass, pool.get(vec) };
68	    return results;
69	}
70	catch (NotFoundException e) {
71	    throw new CannotCompileException(e);
72	}
73	catch (IOException e) {
74	    throw new CannotCompileException(e);
75	}
76    }
77
78    /**
79     * Produces a new vector class.  This method does not work if
80     * the element type is a primitive type.
81     *
82     * @param type	the type of elements
83     */
84    public CtClass makeSubclass(ClassPool pool, CtClass type)
85	throws CannotCompileException, NotFoundException, IOException
86    {
87	CtClass vec = pool.makeClass(makeClassName(type));
88	vec.setSuperclass(pool.get("java.util.Vector"));
89
90	CtClass c = pool.get("sample.vector.Sample");
91	CtMethod addmethod = c.getDeclaredMethod("add");
92	CtMethod atmethod = c.getDeclaredMethod("at");
93
94	ClassMap map = new ClassMap();
95	map.put("sample.vector.X", type.getName());
96
97	vec.addMethod(CtNewMethod.copy(addmethod, "add", vec, map));
98	vec.addMethod(CtNewMethod.copy(atmethod, "at", vec, map));
99	vec.writeFile();
100	return vec;
101    }
102
103    /**
104     * Produces a new vector class.  This uses wrapped methods so that
105     * the element type can be a primitive type.
106     *
107     * @param type	the type of elements
108     */
109    public CtClass makeSubclass2(ClassPool pool, CtClass type)
110	throws CannotCompileException, NotFoundException, IOException
111    {
112	CtClass vec = pool.makeClass(makeClassName(type));
113	vec.setSuperclass(pool.get("java.util.Vector"));
114
115	CtClass c = pool.get("sample.vector.Sample2");
116	CtMethod addmethod = c.getDeclaredMethod("add");
117	CtMethod atmethod = c.getDeclaredMethod("at");
118
119	CtClass[] args1 = { type };
120	CtClass[] args2 = { CtClass.intType };
121	CtMethod m
122	    = CtNewMethod.wrapped(CtClass.voidType, "add", args1,
123				  null, addmethod, null, vec);
124	vec.addMethod(m);
125	m = CtNewMethod.wrapped(type, "at", args2,
126				null, atmethod, null, vec);
127	vec.addMethod(m);
128	vec.writeFile();
129	return vec;
130    }
131
132    private String makeClassName(CtClass type) {
133	return packageName + type.getSimpleName() + "Vector";
134    }
135}
136