Package nexj.core.build

Source Code of nexj.core.build.PresentationLayerDoclet$TransientType

// Copyright 2010 NexJ Systems Inc. This software is licensed under the terms of the Eclipse Public License 1.0
package nexj.core.build;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.Doc;
import com.sun.javadoc.DocErrorReporter;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.RootDoc;
import com.sun.javadoc.Tag;

import nexj.core.meta.Argument;
import nexj.core.meta.Attribute;
import nexj.core.meta.Event;
import nexj.core.meta.Metaclass;
import nexj.core.meta.Type;
import nexj.core.meta.xml.XMLMetadataExporter;
import nexj.core.util.HashHolder;
import nexj.core.util.HashTab;
import nexj.core.util.IndentingXMLWriter;
import nexj.core.util.Lookup;
import nexj.core.util.ObjUtil;
import nexj.core.util.XMLUtil;
import nexj.core.util.XMLWriter;
import nexj.core.version.Version;

/**
* This class implements JavaDoc entry points to generate .meta files from a
* subset of the presentation layer Java source files. Note: Prints error and
* warning messages to System.err.
*/
public class PresentationLayerDoclet
{
   // constants

   /**
    * The command line argument to specify output directory
    */
   public final static String OUTPUT_DIR_OPTION = "-metaclassOutput";

   /**
    * This XML file will be generated in the output directory and contain a list
    * of generated metaclasses.
    */
   public final static String METADATA_FILENAME = "presentationLayer.metadata";

   /**
    * The event tag name
    */
   protected final static String EVENT_TAG = "event";

   /**
    * The attribute tag name
    */
   protected final static String ATTRIBUTE_TAG = "attribute";

   /**
    * The description tag name
    */
   protected final static String DESCRIPTION_TAG = "description";

   /**
    * The argument tag name
    */
   protected final static String ARG_TAG = "arg";

   /**
    * The return tag name
    */
   protected final static String RET_TAG = "ret";

   /**
    * The example tag name
    */
   protected final static String EXAMPLE_TAG = "example";

   /**
    * The type alias tag name
    */
   protected final static String TYPE_ALIAS_TAG = "class";

   /**
    * Pattern used to match whitespace
    */
   private final static Pattern WHITESPACE_PATTERN = Pattern.compile("\\s");

   /**
    * Pattern used to match words
    */
   private final static Pattern WORD_PATTERN = Pattern.compile("\\w+");

   /**
    * Matches a newline: \r\n, or \n. 
    */
   private final static String NEWLINE_REGEX = "\r?\n";

   /**
    * The string to use to separate lines in generated comments
    */
   private final static String NEWLINE = "\r\n";

   /**
    * Classes that should be considered part of the presentation layer classes
    * although they may not implement any scripting events.
    */
   private final static Set s_requiredClassSet = new HashHolder();

   static
   {
      s_requiredClassSet.add("nexj.core.controller.ApplicationController");
      s_requiredClassSet.add("nexj.core.controller.FormController");
   }

   // associations

   /**
    * The output directory to write .meta files to.
    */
   protected final File m_outputDir;

   /**
    * String[String]. Map from Java class name to its scripting type alias.
    */
   private Lookup m_typeAliasMap;

   // constructor

   /**
    * Create a new instance with the given output directory.
    *
    * @param outputDir The output directory to use. When
    *           {@link #process(RootDoc)} is called output will be placed in
    *           this directory.
    */
   public PresentationLayerDoclet(File outputDir)
   {
      m_outputDir = outputDir;
   }

   // operations

   /**
    * Entry point when run as a doclet. Called by JavaDoc. Uses
    * -metaclassOutput.
    *
    * @see com.sun.javadoc.Doclet#start(RootDoc)
    */
   public static boolean start(RootDoc root)
   {
      String[][] optionArray = root.options();
      String sPath = "";

      for (int i = 0; i < optionArray.length; i++)
      {
         String[] cur = optionArray[i];

         if (PresentationLayerDoclet.OUTPUT_DIR_OPTION.equals(cur[0]))
         {
            sPath = cur[1];
         }
      }

      File outputDir = new File(sPath);

      if (!outputDir.canWrite())
      {
         return false;
      }

      new PresentationLayerDoclet(outputDir).process(root);

      return true;
   }

   /**
    * Called by JavaDoc to validate the user supplied options
    *
    * @see com.sun.javadoc.Doclet#validOptions(String[][], DocErrorReporter)
    */
   public static boolean validOptions(String[][] optionArray, DocErrorReporter reporter)
   {
      return true;
   }

   /**
    * Called by JavaDoc when parsing arguments
    *
    * @see com.sun.javadoc.Doclet#optionLength(String)
    */
   public static int optionLength(String sOption)
   {
      if (OUTPUT_DIR_OPTION.equals(sOption))
      {
         return 2;
      }

      return 0;
   }

   /**
    * Process the Java classes that JavaDoc processed: select the subset that
    * are applicable to the scripting layer classes and then generate .meta
    * files in the output directory for that subset.
    *
    * @param root The DocRoot as supplied by JavaDoc. This contains all
    *           ClassDoc's for the processed packages.
    */
   public void process(RootDoc root)
   {
      final List scriptingClassDocList = findScriptingClasses(root.classes());
      final List treeList = new ArrayList();
      final long lStart = System.currentTimeMillis();

      // Calculate the tree roots in the inheritance hierarchy of only the scripting classes
      // Warning: ~ O(n^3)
      outer: for (Iterator it = scriptingClassDocList.iterator(); it.hasNext();)
      {
         ClassDoc candidate = (ClassDoc)it.next();

         for (Iterator innerIter = treeList.iterator(); innerIter.hasNext();)
         {
            ClassDoc existingRoot = (ClassDoc)innerIter.next();

            if (existingRoot.subclassOf(candidate))
            {
               innerIter.remove();
            }
            else if (candidate.subclassOf(existingRoot))
            {
               continue outer;
            }
         }

         treeList.add(candidate);
      }

      if (System.currentTimeMillis() - lStart > 1000)
      {
         warning(null, "Performance problem: " + getClass().getName());
      }

      for (ListIterator it = treeList.listIterator(); it.hasNext();)
      {
         it.set(new ClassHierarchy((ClassDoc)it.next()));
      }

      FileOutputStream fosStream = null;
      IndentingXMLWriter xmlWriter = null;

      try
      {
         fosStream = new FileOutputStream(new File(m_outputDir, METADATA_FILENAME));
         xmlWriter = new IndentingXMLWriter(new OutputStreamWriter(new BufferedOutputStream(fosStream), XMLUtil.ENCODING));

         m_typeAliasMap = findTypeAliases(scriptingClassDocList);

         startMetadata(xmlWriter);

         for (Iterator it = treeList.iterator(); it.hasNext();)
         {
            ClassHierarchy tree = (ClassHierarchy)it.next();

            tree.calculateMembers(scriptingClassDocList);
            tree.write();
            tree.writeMetadata(xmlWriter);
         }

         endMetadata(xmlWriter);
      }
      catch (IOException ioe)
      {
         error("Unexpected error. Output is not complete", ioe);
      }
      finally
      {
         closeOutput(fosStream, xmlWriter);
      }
   }

   /**
    * Generate the first part of the XML metadata - the part before the
    * ClassRefs
    */
   protected void startMetadata(XMLWriter writer) throws IOException
   {
      writer.openElement("Metadata");
      writer.writeAttribute("name", "NexJ Presentation Layer Documentation");
      writer.writeAttribute("version", Version.RELEASE);
      writer.writeAttribute("namespace", "http://www.nexjsystems.com/ns/presentationLayerDoc");
      writer.writeAttribute("revision", "0");
      writer.closeElement();

      writer.openElement("Classes");
      writer.closeElement();
   }

   /**
    * Generate the last part of the XML metadata - the part after the ClassRefs
    */
   protected void endMetadata(XMLWriter writer) throws IOException
   {
      writer.endElement("Classes");
      writer.endElement("Metadata");
   }

   /**
    * Find classes with event tags.
    *
    * @param classArray All classes as provided by JavaDoc
    * @return A list of ClassDoc's that have scripting events
    */
   protected List findScriptingClasses(ClassDoc[] classArray)
   {
      List classDocList = new ArrayList();

      for (int i = 0; i < classArray.length; i++)
      {
         ClassDoc classDoc = classArray[i];

         if (isScriptingType(classDoc))
         {
            classDocList.add(classDoc);
         }
      }

      return classDocList;
   }

   /**
    * Get type alias information from the list of classes
    *
    * @see #TYPE_ALIAS_TAG
    *
    * @param classDocList A list of ClassDoc
    * @return A map (String[String]) from Java class name to its scripting type
    *         alias.
    */
   protected Lookup findTypeAliases(List classDocList)
   {
      Lookup typeAliasMap = new HashTab();

      for (Iterator iterator = classDocList.iterator(); iterator.hasNext();)
      {
         ClassDoc classDoc = (ClassDoc)iterator.next();

         if (classDoc.tags(TYPE_ALIAS_TAG).length == 1)
         {
            typeAliasMap.put(classDoc.name(), classDoc.tags(TYPE_ALIAS_TAG)[0].text());
         }
      }

      return typeAliasMap;
   }

   /**
    * Determine if the given class has scheme events
    *
    * @param classDoc The class to check
    * @return Whether the class being examined is a presentation layer scripting
    *         type.
    */
   protected boolean isScriptingType(ClassDoc classDoc)
   {
      if (s_requiredClassSet.contains(classDoc.qualifiedName()))
      {
         return true;
      }

      if (classDoc.tags(DESCRIPTION_TAG).length > 0 || classDoc.tags(TYPE_ALIAS_TAG).length > 0)
      {
         return true;
      }

      MethodDoc[] methodDocArray = classDoc.methods();

      for (int i = 0; i < methodDocArray.length; i++)
      {
         MethodDoc method = methodDocArray[i];

         if (method.tags(EVENT_TAG).length > 0 || method.tags(ATTRIBUTE_TAG).length > 0)
         {
            return true;
         }
      }

      return false;
   }

   /**
    * Add the scripting events defined in the given ClassDoc to the given
    * metaclass.
    *
    * @param clazz (Output) The metaclass to add events to
    * @param classDoc The class to process. May be an inner class.
    */
   protected void addMembers(Metaclass clazz, ClassDoc classDoc) throws IOException
   {
      MethodDoc[] methodArray = classDoc.methods();

      for (int nMethod = 0; nMethod < methodArray.length; nMethod++)
      {
         addEvents(clazz, methodArray[nMethod]);
         addAttributes(clazz, methodArray[nMethod]);
      }
   }

   /**
    * Add the scripting events defined in the given MethodDoc to the given
    * metaclass.
    *
    * @param clazz (Output) The metaclass to add events to
    * @param methodDoc The method to process.
    */
   protected void addEvents(Metaclass clazz, MethodDoc methodDoc)
   {
      if (methodDoc.tags(EVENT_TAG).length == 0)
      {
         return;
      }

      Tag[] tagArray = methodDoc.tags();
      ScriptingEvent scriptingEvent = new ScriptingEvent(methodDoc);
      boolean bSeenEvent = false;

      for (int i = 0; i < tagArray.length; i++)
      {
         Tag tag = tagArray[i];

         if (EVENT_TAG.equals(tag.name().substring(1)))
         {
            if (bSeenEvent)
            {
               // Move on to the next event
               scriptingEvent.addToClass(clazz);
               scriptingEvent = new ScriptingEvent(methodDoc);
            }
            else
            {
               bSeenEvent = true;
            }
         }

         if (bSeenEvent)
         {
            scriptingEvent.applyTag(tag);
         }
      }

      scriptingEvent.addToClass(clazz);
   }

   /**
    * Add the scripting attributes defined in the given MethodDoc to the given
    * metaclass.
    *
    * @param clazz (Output) The metaclass to add events to
    * @param methodDoc The method to process.
    */
   protected void addAttributes(Metaclass clazz, MethodDoc methodDoc)
   {
      Tag[] attributes = methodDoc.tags(ATTRIBUTE_TAG);

      for (int i = 0; i < attributes.length; i++)
      {
         String sBody = attributes[i].text();
         Matcher matcher = WORD_PATTERN.matcher(sBody);

         if (!matcher.find())
         {
            error(methodDoc, "Attribute tag without a name");

            continue;
         }

         Attribute attr = new Attribute(matcher.group());

         if (!matcher.find())
         {
            warning(methodDoc, "Attribute " + attr.getName() + " does not include type");
         }
         else
         {
            attr.setType(new TransientType(matcher.group()));

            int nStart = matcher.end();

            // Optional modifiers
            while (matcher.find())
            {
               String sKeyword = matcher.group().trim();

               if ("readonly".equalsIgnoreCase(sKeyword))
               {
                  attr.setReadOnly(true);
               }
               else if ("static".equalsIgnoreCase(sKeyword))
               {
                  attr.setStatic(true);
               }
               else if ("collection".equalsIgnoreCase(sKeyword))
               {
                  attr.setCollection(true);
               }
               else
               {
                  break;
               }

               nStart = matcher.end();
            }

            // The description is the rest
            attr.setDescription(sBody.substring(nStart).trim());
         }

         clazz.addAttribute(attr);
         attr.setDeclarator(clazz);
      }
   }

   /**
    * Get an alias from the type alias map. If the given name isn't present in
    * the map then the original name is returned.
    *
    * @param sName The original class name
    * @return Non null string
    */
   protected String getAlias(String sName)
   {
      if (m_typeAliasMap.contains(sName))
      {
         return (String)m_typeAliasMap.get(sName);
      }

      return sName;
   }

   /**
    * Helper method to report a tag warning in the given method
    *
    * @param doc Entity identifying the location of the error
    * @param sMessage Description of the problem
    */
   protected void warning(Doc doc, String sMessage)
   {
      log(false, doc, sMessage, null);
   }

   /**
    * Helper method to report a tag error in the given method
    *
    * @param doc Entity identifying the location of the error
    * @param sMessage Description of the problem
    */
   protected void error(Doc doc, String sMessage)
   {
      log(true, doc, sMessage, null);
   }

   /**
    * Helper method to report a exception
    *
    * @param sMessage Description of the problem
    * @param e Exception caught
    */
   protected void error(String sMessage, Throwable e)
   {
      log(true, null, sMessage, e);
   }

   /**
    * Helper method to report an error
    *
    * @param doc Entity identifying the location of the error. May be null.
    * @param sMessage Description of the problem
    * @param e Exception caught. May be null.
    */
   protected void error(Doc doc, String sMessage, Throwable e)
   {
      log(true, doc, sMessage, e);
   }

   /**
    * Print an error or warning message to System.err.
    *
    * @param bError True to indicate an error, false to indicate a warning
    * @param doc Entity identifying the location of the error. May be null.
    * @param sMessage Message to display. Not null
    * @param e Exception to log. May be null.
    */
   protected void log(boolean bError, Doc doc, String sMessage, Throwable e)
   {
      String sPrefix = bError ? "Scripting error: " : "Scripting warning: ";

      if (e != null)
      {
         sMessage += ": " + ObjUtil.getMessage(e);
      }

      if (doc != null)
      {
         System.err.println(sPrefix + doc + ": " + sMessage);
      }
      else
      {
         System.err.println(sPrefix + sMessage);
      }
   }

   /**
    * Closes a writer and its underlying output stream. The writer is closed
    * first.
    *
    * Warning: if an exception is thrown by both stream and writer then only
    * stream's error will be reported.
    *
    * @param stream The output stream. May be null
    * @param writer The writer. May be null
    */
   protected void closeOutput(OutputStream stream, Writer writer)
   {
      try
      {
         try
         {
            if (writer != null)
            {
               writer.close();
            }
         }
         finally
         {
            if (stream != null)
            {
               stream.close();
            }
         }
      }
      catch (IOException ioe)
      {
         error("Error closing output file", ioe);
      }
   }

   // inner classes

   /**
    * Represents a class hierarchy. Also corresponds to a set of .meta files
    * specified by the hierarchy's members.
    */
   private class ClassHierarchy
   {
      // associations

      /**
       * The class hierarchy's root.
       */
      private final ClassDoc m_root;

      /**
       * Set of ClassDoc's that are descendants of root.
       */
      private final Set m_memberSet = new HashHolder();

      // constructor

      /**
       * Create a class hierarchy with the given root.
       *
       * @param root The hierarchy root to use.
       */
      public ClassHierarchy(ClassDoc root)
      {
         m_root = root;
      }

      // operations

      /**
       * From the list of classes with scripting layer events select those that
       * are part of this hierarchy.
       *
       * @param classList List of ClassDoc
       */
      public void calculateMembers(List classList)
      {
         for (Iterator it = classList.iterator(); it.hasNext();)
         {
            ClassDoc candidate = (ClassDoc)it.next();

            if (candidate.subclassOf(m_root))
            {
               m_memberSet.add(candidate);
            }
         }

         // Ensure all classes between the memberSet members and the tree root
         // are included in the memberSet, regardless of whether they have
         // scripting layer events.
         for (Iterator it = m_memberSet.iterator(); it.hasNext();)
         {
            for (ClassDoc classDoc = ((ClassDoc)it.next()).superclass(); classDoc != null && !m_memberSet.contains(classDoc)
               && !classDoc.name().equals("Object"); classDoc = classDoc.superclass())
            {
               m_memberSet.add(classDoc);
            }
         }
      }

      /**
       * Generate .meta output for all the members
       */
      public void write()
      {
         for (Iterator it = m_memberSet.iterator(); it.hasNext();)
         {
            try
            {
               write((ClassDoc)it.next());
            }
            catch (Throwable e)
            {
               error("Unexpected exception", e);
            }
         }
      }

      /**
       * Generate output for the given Java class with Scheme events
       *
       * @param classDoc The class to process
       */
      private void write(ClassDoc classDoc) throws IOException
      {
         Metaclass clazz;
         Tag[] tagArray;

         // Set up the current class
         clazz = new Metaclass(getAlias(classDoc.name()));
         tagArray = classDoc.tags(DESCRIPTION_TAG);

         // Class @description
         if (tagArray.length > 0)
         {
            clazz.setDescription(tagArray[0].text());

            if (tagArray.length != 1)
            {
               warning(classDoc, "Multiple description tags found for " + clazz.getName());
            }
         }

         if (classDoc.superclass() != null)
         {
            clazz.setBase(new Metaclass(getAlias(classDoc.superclass().name())));

            if (clazz.getName().equals(clazz.getBase().getName()))
            {
               error(classDoc, "Type aliases cause circular hierarchy");
               clazz.setBase(null);
            }
         }

         // Process the methods
         addMembers(clazz, classDoc);

         ClassDoc[] innerTypeArray = classDoc.innerClasses();

         for (int i = 0; i < innerTypeArray.length; i++)
         {
            addMembers(clazz, innerTypeArray[i]);
         }

         innerTypeArray = classDoc.interfaces();

         for (int i = 0; i < innerTypeArray.length; i++)
         {
            addMembers(clazz, innerTypeArray[i]);
         }

         // Export to file
         FileOutputStream fosStream = null;
         IndentingXMLWriter xmlWriter = null;

         try
         {
            fosStream = new FileOutputStream(new File(m_outputDir, clazz.getName() + ".meta"));
            xmlWriter = new IndentingXMLWriter(new OutputStreamWriter(new BufferedOutputStream(fosStream), XMLUtil.ENCODING));

            new XMLMetadataExporter(xmlWriter).exportMetaclass(clazz);
         }
         finally
         {
            closeOutput(fosStream, xmlWriter);
         }
      }

      /**
       * Write ClassRef XML for the tree's members
       */
      public void writeMetadata(XMLWriter writer) throws IOException
      {
         for (Iterator it = m_memberSet.iterator(); it.hasNext();)
         {
            writer.openElement("ClassRef");
            writer.writeAttribute("resource", getAlias(((ClassDoc)it.next()).name()) + ".meta");
            writer.closeEmptyElement();
         }
      }
   }

   /**
    * A collection of data applicable to a single scripting event.
    *
    * Typically, after instantiation {@link ScriptingEvent#applyTag(Tag)} is
    * called one or more times followed by a call to
    * {@link ScriptingEvent#addToClass(Metaclass)}.
    */
   private class ScriptingEvent
   {
      /**
       * If there is an error with this event then no output will be generated
       * for it, and this field will become false.
       */
      private boolean m_bValid = true;

      /**
       * If there is an example tag it will be stored here, otherwise null.
       */
      private String m_sExample;

      // associations

      /**
       * The current scripting event defined in a tag of method
       */
      private final Event m_event;

      /**
       * A list of String arrays. The first item corresponds to the return value
       * and may be null. If its not null it has at most 2 elements - type and
       * description. The remainder correspond to arguments and have between 1
       * and 3 elements - name, type and description.
       */
      private final List m_argList;

      /**
       * The Java method this Scripting event is defined in. Used when reporting
       * errors.
       */
      private MethodDoc m_methodDoc;

      // constructor

      /**
       * Create a new scripting event. It initially is empty and has its name
       * set to methodDoc's name.
       *
       * @param methodDoc The Java method that defined this event. Used for
       *           initialization and error reporting.
       */
      public ScriptingEvent(MethodDoc methodDoc)
      {
         m_event = new Event(methodDoc.name());
         m_argList = new ArrayList();
         m_argList.add(null);
         m_methodDoc = methodDoc;
      }

      // operations

      /**
       * Apply the given tag to this event.
       *
       * @param tag The tag to process. Not necessarily a recognized tag.
       */
      public void applyTag(Tag tag)
      {
         if (!m_bValid)
         {
            return;
         }

         String sTagName = tag.name().substring(1);

         if (EVENT_TAG.equals(sTagName))
         {
            String[] parts = WHITESPACE_PATTERN.split(tag.text());

            if (parts.length > 0 && parts[0].length() > 0)
            {
               m_event.setName(parts[0]);
            }
         }
         else if (ARG_TAG.equals(sTagName))
         {
            String[] parts = WHITESPACE_PATTERN.split(tag.text(), 3);

            if (parts.length == 0)
            {
               error(m_methodDoc, "@arg tag with no name");
               m_bValid = false;

               return;
            }
            else if (parts.length == 1)
            {
               warning(m_methodDoc, "@arg tag with no type");
            }

            m_argList.add(parts);
         }
         else if (RET_TAG.equals(sTagName))
         {
            String[] parts = WHITESPACE_PATTERN.split(tag.text(), 2);

            if (parts.length == 0)
            {
               warning(m_methodDoc, "@ret tag with no type");
            }

            m_argList.set(0, parts);
         }
         else if (DESCRIPTION_TAG.equals(sTagName))
         {
            m_event.setDescription(tag.text());
         }
         else if (EXAMPLE_TAG.equals(sTagName))
         {
            m_sExample = tag.text().replaceAll(NEWLINE_REGEX, NEWLINE);
         }
      }

      /**
       * Adds this event to the metaclass and generates SchemeDoc in the
       * description field.
       *
       * @param clazz (Output) The metaclass to add events to
       */
      public void addToClass(Metaclass clazz)
      {
         if (!m_bValid)
         {
            return;
         }

         String sOrigDescription = m_event.getDescription();

         StringBuilder buf = new StringBuilder(sOrigDescription != null ? sOrigDescription + NEWLINE : "");
         Iterator it = m_argList.iterator();
         String[] retTagContents = (String[])it.next();

         while (it.hasNext())
         {
            String[] argTagContents = (String[])it.next();
            String sArgName = argTagContents[0];

            // vararg
            if (sArgName.endsWith("..."))
            {
               m_event.setVarArg(true);
               sArgName = sArgName.substring(0, sArgName.length() - 3);
            }

            try
            {
               m_event.addArgument(new Argument(sArgName));
            }
            catch (Throwable t)
            {
               error(m_methodDoc, "Could not add argument", t);

               return;
            }

            buf.append("@arg ");
            buf.append(sArgName);

            for (int i = 1; i < argTagContents.length; i++)
            {
               buf.append(' ');
               buf.append(argTagContents[i]);
            }

            buf.append(NEWLINE);
         }

         if (retTagContents != null)
         {
            buf.append("@ret");

            for (int i = 0; i < retTagContents.length; i++)
            {
               buf.append(' ');
               buf.append(retTagContents[i]);
            }

            buf.append(NEWLINE);
         }

         if (m_sExample != null)
         {
            buf.append("@example ");
            buf.append(m_sExample);
            buf.append(NEWLINE);
         }

         if (buf.length() > 0)
         {
            m_event.setDescription(buf.substring(0));
         }

         try
         {
            m_event.setDeclarator(clazz);
            clazz.addEvent(m_event);
         }
         catch (Throwable ex)
         {
            error(m_methodDoc, "Could not add event", ex);
         }
      }
   }

   private static class TransientType extends Type
   {
      public TransientType(String sName)
      {
         super(sName);
      }

      /**
       * @see nexj.core.meta.Type#getBaseType()
       */
      public Type getBaseType()
      {
         throw new UnsupportedOperationException();
      }

      /**
       * @see nexj.core.meta.Type#isPrimitive()
       */
      public boolean isPrimitive()
      {
         throw new UnsupportedOperationException();
      }
   }
}
TOP

Related Classes of nexj.core.build.PresentationLayerDoclet$TransientType

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.