31fad52004-05-31Marc Dirix import com.roxen.roxen.*;
d18e472000-03-29Marcus Comstedt  import java.util.HashMap; import java.lang.reflect.Modifier; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Constructor;
0d72ab2000-04-05Marcus Comstedt  /*
31fad52004-05-31Marc Dirix  * This is an example Roxen location module.
d69ba52001-09-03Martin Nilsson  * Copyright (c) 2000 - 2001, Roxen IS
0d72ab2000-04-05Marcus Comstedt  */
d18e472000-03-29Marcus Comstedt public class JavaReflector extends AbstractLocationModule {
0d72ab2000-04-05Marcus Comstedt  String modifierFont, typeFont, variableFont, methodFont, keywordFont;
d18e472000-03-29Marcus Comstedt  public String queryName() { return "Java Class Reflector"; } public String info() { return "A location module providing an HTML interface to Java Reflection."; }
31fad52004-05-31Marc Dirix  protected RoxenResponse response(String title, String body)
d18e472000-03-29Marcus Comstedt  {
0d72ab2000-04-05Marcus Comstedt  /* * Package the content in an HTML page and return it with * RXML parsing. */
d18e472000-03-29Marcus Comstedt  String page = "<html><head><title>"+title+"</title>\n"+ "<body bgcolor=\"white\" text=\"black\" link=\"#6699cc\" "+ "alink=\"red\" vlink=\"#6677cc\">\n"+ body+ "</body></html>\n";
31fad52004-05-31Marc Dirix  return RoxenLib.httpRXMLAnswer(page);
d18e472000-03-29Marcus Comstedt  }
31fad52004-05-31Marc Dirix  public RoxenResponse packageList(RoxenRequest id)
d18e472000-03-29Marcus Comstedt  {
0d72ab2000-04-05Marcus Comstedt  /* * Default page, lists known packages. */
d18e472000-03-29Marcus Comstedt  StringBuffer page = new StringBuffer(); page.append("<h1>All packages</h1>\n<ul>\n"); Package[] packages = Package.getPackages(); for(int i=0; i<packages.length; i++) { Package p = packages[i]; page.append(" <li>"); HashMap args = new HashMap(); args.put("href", queryLocation()+p.getName());
31fad52004-05-31Marc Dirix  page.append(RoxenLib.makeContainer("a", args, p.getName()));
d18e472000-03-29Marcus Comstedt  page.append("</li>\n"); } page.append("</ul>\n");
0d72ab2000-04-05Marcus Comstedt  /* * Include a link to the reflection of this class, just * to get people started... */ page.append("Class of module: "); HashMap args = new HashMap(); Class c = getClass(); args.put("href", queryLocation()+c.getName());
31fad52004-05-31Marc Dirix  page.append(RoxenLib.makeContainer("a", args, c.getName()));
0d72ab2000-04-05Marcus Comstedt  page.append("\n");
d18e472000-03-29Marcus Comstedt  return response("Packages", page.toString()); }
31fad52004-05-31Marc Dirix  public RoxenResponse describePackage(Package p, RoxenRequest id)
d18e472000-03-29Marcus Comstedt  {
0d72ab2000-04-05Marcus Comstedt  /* * Unfortunately, there is no way to list all classes * in a package. So this page only contains some manifest info. */
d18e472000-03-29Marcus Comstedt  StringBuffer page = new StringBuffer(); page.append("<h1>Package "+p.getName()+"</h1>\n"); page.append("<table border=1>\n<tr><td></td><th>Title</th>"+ "<th>Vendor</th><th>Version</th></tr>\n"); page.append("<tr><th>Specification</th><td>");
31fad52004-05-31Marc Dirix  page.append(RoxenLib.htmlEncodeString(p.getSpecificationTitle()+""));
d18e472000-03-29Marcus Comstedt  page.append("</td><td>");
31fad52004-05-31Marc Dirix  page.append(RoxenLib.htmlEncodeString(p.getSpecificationVendor()+""));
d18e472000-03-29Marcus Comstedt  page.append("</td><td>");
31fad52004-05-31Marc Dirix  page.append(RoxenLib.htmlEncodeString(p.getSpecificationVersion()+""));
d18e472000-03-29Marcus Comstedt  page.append("</td></tr>\n<tr><th>Implementation</th><td>");
31fad52004-05-31Marc Dirix  page.append(RoxenLib.htmlEncodeString(p.getImplementationTitle()+""));
d18e472000-03-29Marcus Comstedt  page.append("</td><td>");
31fad52004-05-31Marc Dirix  page.append(RoxenLib.htmlEncodeString(p.getImplementationVendor()+""));
d18e472000-03-29Marcus Comstedt  page.append("</td><td>");
31fad52004-05-31Marc Dirix  page.append(RoxenLib.htmlEncodeString(p.getImplementationVersion()+""));
d18e472000-03-29Marcus Comstedt  page.append("</td></tr></table>\n"); return response("Package "+p.getName(), page.toString()); } static protected void indentedLine(StringBuffer buf, String txt, int indent) {
0d72ab2000-04-05Marcus Comstedt  /* Append a line with indentation to a StringBuffer */
d18e472000-03-29Marcus Comstedt  while(indent-->0) buf.append("&nbsp;"); buf.append(txt); buf.append("<br>\n"); }
0d72ab2000-04-05Marcus Comstedt  protected String modifierNames(int modifiers)
d18e472000-03-29Marcus Comstedt  {
0d72ab2000-04-05Marcus Comstedt  /* Translate a mask of modifiers to clear text */
d18e472000-03-29Marcus Comstedt  if((modifiers&Modifier.INTERFACE)>0) modifiers &= ~(Modifier.ABSTRACT | Modifier.STATIC | Modifier.INTERFACE); return (modifiers==0? "" : modifierFont+Modifier.toString(modifiers)+"</font> "); } protected String simpleClassName(String name) {
0d72ab2000-04-05Marcus Comstedt  /* Translate a qualified name to a simple name */
d18e472000-03-29Marcus Comstedt  int i = name.lastIndexOf('$'); if(i<0) i = name.lastIndexOf('.'); return (i<0? name : name.substring(i+1)); } protected String classLink(Class c) {
0d72ab2000-04-05Marcus Comstedt  /* Translate a type to clear text with hyperlinks where applicable */
d18e472000-03-29Marcus Comstedt  if(c.isArray()) return classLink(c.getComponentType())+"[]"; String n = c.getName(); String t = typeFont+n.replace('$', '.')+"</font>"; if(c.isPrimitive()) return t; int i = n.lastIndexOf('$'); HashMap args = new HashMap(); args.put("href", queryLocation()+(i<0? n : n.substring(0, i)));
31fad52004-05-31Marc Dirix  return RoxenLib.makeContainer("a", args, t);
d18e472000-03-29Marcus Comstedt  } protected String classLink(Class[] c) {
0d72ab2000-04-05Marcus Comstedt  /* Translate a list of types to clear text with hyperlinks */
d18e472000-03-29Marcus Comstedt  StringBuffer buf = new StringBuffer(); for(int i=0; i<c.length; i++) { if(i>0) buf.append(", "); buf.append(classLink(c[i])); } return buf.toString(); }
31fad52004-05-31Marc Dirix  protected void describe(StringBuffer page, Field f, RoxenRequest id,
d18e472000-03-29Marcus Comstedt  int indent) {
0d72ab2000-04-05Marcus Comstedt  /* Append description of a field to a StringBuffer */ indentedLine(page, modifierNames(f.getModifiers())+
d18e472000-03-29Marcus Comstedt  classLink(f.getType())+" "+variableFont+ f.getName()+"</font>;", indent); }
31fad52004-05-31Marc Dirix  protected void describe(StringBuffer page, Method m, RoxenRequest id,
d18e472000-03-29Marcus Comstedt  int indent) {
0d72ab2000-04-05Marcus Comstedt  /* Append description of a method to a StringBuffer */
d18e472000-03-29Marcus Comstedt  Class[] th = m.getExceptionTypes();
0d72ab2000-04-05Marcus Comstedt  indentedLine(page, modifierNames(m.getModifiers())+
d18e472000-03-29Marcus Comstedt  classLink(m.getReturnType())+" "+methodFont+ m.getName()+"</font>("+classLink(m.getParameterTypes())+ ")"+(th.length>0? " "+keywordFont+"throws</font> "+ classLink(th):"")+";", indent); }
31fad52004-05-31Marc Dirix  protected void describe(StringBuffer page, Constructor c, RoxenRequest id,
d18e472000-03-29Marcus Comstedt  int indent) {
0d72ab2000-04-05Marcus Comstedt  /* Append description of a constructor to a StringBuffer */
d18e472000-03-29Marcus Comstedt  Class[] th = c.getExceptionTypes();
0d72ab2000-04-05Marcus Comstedt  indentedLine(page, modifierNames(c.getModifiers())+
d18e472000-03-29Marcus Comstedt  methodFont+simpleClassName(c.getName())+ "</font>("+classLink(c.getParameterTypes())+ ")"+(th.length>0? " "+keywordFont+"throws</font> "+ classLink(th):"")+";", indent); }
31fad52004-05-31Marc Dirix  protected void describe(StringBuffer page, Class c, RoxenRequest id,
d18e472000-03-29Marcus Comstedt  int indent) {
0d72ab2000-04-05Marcus Comstedt  /* Append description of a class or interface to a StringBuffer */
d18e472000-03-29Marcus Comstedt  Class[] ifcs = c.getInterfaces(); if(c.isInterface())
0d72ab2000-04-05Marcus Comstedt  indentedLine(page, modifierNames(c.getModifiers())+
d18e472000-03-29Marcus Comstedt  keywordFont+"interface</font> "+ methodFont+simpleClassName(c.getName())+"</font> "+ (ifcs.length>0? keywordFont+"extends</font> "+ classLink(ifcs)+" ":"")+ "{", indent); else { Class s = c.getSuperclass();
0d72ab2000-04-05Marcus Comstedt  indentedLine(page, modifierNames(c.getModifiers())+
d18e472000-03-29Marcus Comstedt  keywordFont+"class</font> "+ methodFont+simpleClassName(c.getName())+"</font> "+ (s!=null? keywordFont+"extends</font> "+ classLink(s)+" ":"")+ (ifcs.length>0? keywordFont+"implements</font> "+ classLink(ifcs)+" ":"")+ "{", indent); } indent += 2; Class[] dclasses = c.getDeclaredClasses(); for(int i=0; i<dclasses.length; i++) { indentedLine(page, "", indent); describe(page, dclasses[i], id, indent); } Field[] fields = c.getDeclaredFields(); if(fields.length>0) indentedLine(page, "", indent); for(int i=0; i<fields.length; i++) describe(page, fields[i], id, indent); Method[] methods = c.getDeclaredMethods(); if(methods.length>0) indentedLine(page, "", indent); for(int i=0; i<methods.length; i++) describe(page, methods[i], id, indent); Constructor[] constructors = c.getDeclaredConstructors(); if(constructors.length>0) indentedLine(page, "", indent); for(int i=0; i<constructors.length; i++) describe(page, constructors[i], id, indent); indentedLine(page, "", indent); indent -= 2; indentedLine(page, "}", indent); }
31fad52004-05-31Marc Dirix  public RoxenResponse describeClass(Class c, RoxenRequest id)
d18e472000-03-29Marcus Comstedt  {
0d72ab2000-04-05Marcus Comstedt  /* * Page describing a class or interface (including inner classes) */
d18e472000-03-29Marcus Comstedt  StringBuffer page = new StringBuffer(); String ci = (c.isInterface()? "Interface":"Class"); page.append("<h1>"+ci+" "+c.getName()+"</h1>\n"); page.append("\n<tt>\n"); Package p = c.getPackage(); if(p != null) { page.append(keywordFont+"package</font> "); HashMap args = new HashMap(); args.put("href", queryLocation()+p.getName());
31fad52004-05-31Marc Dirix  page.append(RoxenLib.makeContainer("a", args,
d18e472000-03-29Marcus Comstedt  modifierFont+p.getName()+"</font>")); page.append(";<br><br>\n"); } describe(page, c, id, 0); page.append("</tt>\n"); return response(ci+" "+c.getName(), page.toString()); }
31fad52004-05-31Marc Dirix  public RoxenResponse findFile(String f, RoxenRequest id)
d18e472000-03-29Marcus Comstedt  {
0d72ab2000-04-05Marcus Comstedt  /* If no class or package name is given, show a default page */
d18e472000-03-29Marcus Comstedt  if("".equals(f)) return packageList(id); try {
0d72ab2000-04-05Marcus Comstedt  /* Is it a class/interface ? */
d18e472000-03-29Marcus Comstedt  Class c = Class.forName(f); if(c != null && c.getDeclaringClass() == null && !c.isArray() && !c.isPrimitive()) return describeClass(c, id); } catch (ClassNotFoundException e) { }
0d72ab2000-04-05Marcus Comstedt  /* No? Maybe a package? */
d18e472000-03-29Marcus Comstedt  Package p = Package.getPackage(f); if(p != null) return describePackage(p, id);
0d72ab2000-04-05Marcus Comstedt  /* Nope. No appropriate page found. */
d18e472000-03-29Marcus Comstedt  return null; } protected void start() {
0d72ab2000-04-05Marcus Comstedt  /* * Prefabricate font tags using the customizable colors, * for speed and simplicity. */
d18e472000-03-29Marcus Comstedt  modifierFont = "<font color=\""+queryString("modifier_color")+"\">"; typeFont = "<font color=\""+queryString("type_color")+"\">"; variableFont = "<font color=\""+queryString("variable_color")+"\">"; methodFont = "<font color=\""+queryString("method_color")+"\">"; keywordFont = "<font color=\""+queryString("keyword_color")+"\">"; } public JavaReflector() { defvar("location", "/reflector/", "Mount point", TYPE_LOCATION, "This is where the module will be inserted in the "+ "namespace of your server.");
0d72ab2000-04-05Marcus Comstedt  /* To get some interresting config variables, all the syntactic highlight colors are customizable. :-) */
d18e472000-03-29Marcus Comstedt  defvar("modifier_color", "red", "Modifier font color", TYPE_STRING, "Color to use for names of modifiers."); defvar("type_color", "steelblue", "Type font color", TYPE_STRING, "Color to use for names of types."); defvar("variable_color", "purple", "Variable font color", TYPE_STRING, "Color to use for names of variables and fields."); defvar("method_color", "brown", "Method font color", TYPE_STRING, "Color to use for names of methods and constructors."); defvar("keyword_color", "green", "Keyword font color", TYPE_STRING, "Color to use for names of keywords."); } }