You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by ja...@apache.org on 2008/11/10 21:50:39 UTC

svn commit: r712830 - in /incubator/jspwiki/trunk: ./ src/com/ecyrd/jspwiki/ src/com/ecyrd/jspwiki/filters/ src/com/ecyrd/jspwiki/modules/ src/com/ecyrd/jspwiki/plugin/ src/com/ecyrd/jspwiki/ui/ src/com/ecyrd/jspwiki/ui/admin/beans/ src/org/apache/jspw...

Author: jalkanen
Date: Mon Nov 10 12:50:38 2008
New Revision: 712830

URL: http://svn.apache.org/viewvc?rev=712830&view=rev
Log:
JSPWIKI-423: Plugins and filters now use annotations instead of
jspwiki_module.xml.  Editors still do it the old way, though. 
jspwiki_module.xml still is used to optionally locate the packages,
through "<module package="org.mycompany"/>".  Please see PluginManager
for documentation.

Modified:
    incubator/jspwiki/trunk/ChangeLog
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/Release.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/FilterManager.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/ProfanityFilter.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/SpamFilter.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/modules/ModuleManager.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/modules/WikiModuleInfo.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/IfPlugin.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/Image.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/PluginManager.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/ui/EditorManager.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/ui/admin/beans/PluginBean.java
    incubator/jspwiki/trunk/src/org/apache/jspwiki/api/ModuleData.java
    incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/plugin/PluginManagerTest.java
    incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/plugin/SamplePlugin.java

Modified: incubator/jspwiki/trunk/ChangeLog
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/ChangeLog?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/ChangeLog (original)
+++ incubator/jspwiki/trunk/ChangeLog Mon Nov 10 12:50:38 2008
@@ -1,3 +1,15 @@
+2008-11-10  Janne Jalkanen <ja...@apache.org>
+
+        * 3.0.0-svn-5
+        
+        * Stripes-1.5 resides now in lib instead of tests/lib.  Yay!
+        
+        * JSPWIKI-423: Plugins and filters now use annotations instead of
+        jspwiki_module.xml.  Editors still do it the old way, though. 
+        jspwiki_module.xml still is used to optionally locate the packages,
+        through "<module package="org.mycompany"/>".  Please see PluginManager
+        for documentation.
+        
 2008-11-10 Harry Metske <me...@apache.org>
 
         * 3.0.0-svn-4

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/Release.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/Release.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/Release.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/Release.java Mon Nov 10 12:50:38 2008
@@ -77,7 +77,7 @@
      *  <p>
      *  If the build identifier is empty, it is not added.
      */
-    public static final String     BUILD         = "4";
+    public static final String     BUILD         = "5";
     
     /**
      *  This is the generic version string you should use

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/FilterManager.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/FilterManager.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/FilterManager.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/FilterManager.java Mon Nov 10 12:50:38 2008
@@ -27,6 +27,8 @@
 import java.net.URL;
 import java.util.*;
 
+import net.sourceforge.stripes.util.ResolverUtil;
+
 import org.apache.log4j.Logger;
 import org.jdom.Document;
 import org.jdom.Element;
@@ -41,6 +43,8 @@
 import com.ecyrd.jspwiki.event.WikiPageEvent;
 import com.ecyrd.jspwiki.modules.ModuleManager;
 import com.ecyrd.jspwiki.modules.WikiModuleInfo;
+import com.ecyrd.jspwiki.plugin.WikiPlugin;
+import com.ecyrd.jspwiki.plugin.PluginManager.WikiPluginInfo;
 import com.ecyrd.jspwiki.util.ClassUtil;
 import com.ecyrd.jspwiki.util.PriorityList;
 
@@ -210,7 +214,7 @@
 
         try
         {
-            registerFilters();
+            registerAllFilters();
             
             if( m_engine.getServletContext() != null )
             {
@@ -466,61 +470,29 @@
         return modules;
     }
 
-    private void registerFilters()
+    private void registerAllFilters()
     {
         log.info( "Registering filters" );
 
-        SAXBuilder builder = new SAXBuilder();
-
-        try
+        List<String> searchPath = buildPluginSearchPath( m_engine.getWikiProperties() );
+        
+        ResolverUtil<PageFilter> resolver = new ResolverUtil<PageFilter>();
+        
+        String[] paths = searchPath.toArray( new String[0] );
+        resolver.findImplementations( PageFilter.class, paths );
+        
+        Set<Class<? extends PageFilter>> resultSet = resolver.getClasses();
+        
+        log.debug( "Found "+resultSet.size()+" pagefilters" );
+        
+        for( Class<? extends PageFilter> clazz : resultSet )
         {
-            //
-            // Register all filters which have created a resource containing its properties.
-            //
-            // Get all resources of all plugins.
-            //
-
-            Enumeration resources = getClass().getClassLoader().getResources( PLUGIN_RESOURCE_LOCATION );
+            PageFilterInfo pluginInfo = PageFilterInfo.newInstance( clazz );
 
-            while( resources.hasMoreElements() )
+            if( pluginInfo != null )
             {
-                URL resource = (URL) resources.nextElement();
-
-                try
-                {
-                    log.debug( "Processing XML: " + resource );
-
-                    Document doc = builder.build( resource );
-
-                    List plugins = XPath.selectNodes( doc, "/modules/filter");
-
-                    for( Iterator i = plugins.iterator(); i.hasNext(); )
-                    {
-                        Element pluginEl = (Element) i.next();
-
-                        String className = pluginEl.getAttributeValue("class");
-
-                        PageFilterInfo pluginInfo = PageFilterInfo.newInstance( className, pluginEl );
-
-                        if( pluginInfo != null )
-                        {
-                            registerPlugin( pluginInfo );
-                        }
-                    }
-                }
-                catch( java.io.IOException e )
-                {
-                    log.error( "Couldn't load " + PLUGIN_RESOURCE_LOCATION + " resources: " + resource, e );
-                }
-                catch( JDOMException e )
-                {
-                    log.error( "Error parsing XML for filter: "+PLUGIN_RESOURCE_LOCATION );
-                }
-            }
-        }
-        catch( java.io.IOException e )
-        {
-            log.error( "Couldn't load all " + PLUGIN_RESOURCE_LOCATION + " resources", e );
+                registerPlugin( pluginInfo );
+            } 
         }
     }
 
@@ -536,17 +508,16 @@
      */
     private static final class PageFilterInfo extends WikiModuleInfo
     {
-        private PageFilterInfo( String name )
+        private PageFilterInfo( Class<? extends PageFilter> clazz )
         {
-            super(name);
+            super(clazz.getName());
+            initializeFromClass( clazz );
         }
         
-        protected static PageFilterInfo newInstance(String className, Element pluginEl)
+        protected static PageFilterInfo newInstance(Class<? extends PageFilter> clazz)
         {
-            if( className == null || className.length() == 0 ) return null;
-            PageFilterInfo info = new PageFilterInfo( className );
+            PageFilterInfo info = new PageFilterInfo( clazz );
 
-            info.initializeFromXML( pluginEl );
             return info;        
         }
     }

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/ProfanityFilter.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/ProfanityFilter.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/ProfanityFilter.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/ProfanityFilter.java Mon Nov 10 12:50:38 2008
@@ -39,6 +39,7 @@
  *  is case unsensitive.
  *
  */
+@Deprecated
 public class ProfanityFilter extends BasicPageFilter
 {
     private static Logger     log = Logger.getLogger(ProfanityFilter.class);

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/SpamFilter.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/SpamFilter.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/SpamFilter.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/filters/SpamFilter.java Mon Nov 10 12:50:38 2008
@@ -32,6 +32,7 @@
 import org.apache.commons.jrcs.diff.*;
 import org.apache.commons.jrcs.diff.myers.MyersDiff;
 import org.apache.commons.lang.time.StopWatch;
+import org.apache.jspwiki.api.ModuleData;
 import org.apache.log4j.Logger;
 import org.apache.oro.text.regex.*;
 
@@ -70,6 +71,7 @@
  *
  *  @since 2.1.112
  */
+@ModuleData( author = "JSPWiki development group" )
 public class SpamFilter
     extends BasicPageFilter
 {

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/modules/ModuleManager.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/modules/ModuleManager.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/modules/ModuleManager.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/modules/ModuleManager.java Mon Nov 10 12:50:38 2008
@@ -20,7 +20,15 @@
  */
 package com.ecyrd.jspwiki.modules;
 
-import java.util.Collection;
+import java.net.URL;
+import java.util.*;
+
+import org.apache.log4j.Logger;
+import org.jdom.Attribute;
+import org.jdom.Document;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+import org.jdom.xpath.XPath;
 
 import com.ecyrd.jspwiki.Release;
 import com.ecyrd.jspwiki.WikiEngine;
@@ -32,13 +40,20 @@
 {
 
     /**
+     *  The property name defining which packages will be searched for modules.
+     */
+    public static final String PROP_SEARCHPATH = "jspwiki.plugin.searchPath";
+
+    /**
      * Location of the property-files of plugins.
      *  (Each plugin should include this property-file in its jar-file)
      */
-    public static final String PLUGIN_RESOURCE_LOCATION = "ini/jspwiki_module.xml";
+    public static final String MODULE_RESOURCE_LOCATION = "ini/jspwiki_module.xml";
         
     protected WikiEngine m_engine;
     
+    private static Logger log = Logger.getLogger( ModuleManager.class );
+    
     private boolean m_loadIncompatibleModules = false;
     
     /**
@@ -78,4 +93,74 @@
      * @return A Collection of WikiModuleInfo instances.
      */
     public abstract Collection modules();
+
+    /**
+     *  Builds a search path from three components:
+     *  <ol>
+     *  <li>The default packages.
+     *  <li>The contents of {@value #PROP_SEARCHPATH}
+     *  <li>Whatever can be located from the contents of the ini-files
+     *  </ol>
+     *  
+     *  @param props
+     *  @return A List of package names which should be scanned for modules.
+     */
+    protected List<String> buildPluginSearchPath( Properties props )
+    {
+        ArrayList<String> list = new ArrayList<String>();
+        list.add( "com.ecyrd.jspwiki" );
+        list.add( "org.apache.jspwiki" );
+        
+        String packageNames = props.getProperty( PROP_SEARCHPATH );
+    
+        if( packageNames != null )
+        {
+            StringTokenizer tok = new StringTokenizer( packageNames, "," );
+    
+            while( tok.hasMoreTokens() )
+            {
+                list.add( tok.nextToken().trim() );
+            }
+        }
+    
+        SAXBuilder builder = new SAXBuilder();
+    
+        try
+        {
+            Enumeration resources = getClass().getClassLoader().getResources( MODULE_RESOURCE_LOCATION );
+    
+            while( resources.hasMoreElements() )
+            {
+                URL resource = (URL) resources.nextElement();
+    
+                try
+                {
+                    Document doc = builder.build( resource );
+    
+                    List packages = XPath.selectNodes( doc, "/modules/@package");
+    
+                    for( Iterator i = packages.iterator(); i.hasNext(); )
+                    {
+                        Attribute a = (Attribute) i.next();
+    
+                        list.add( a.getValue().trim() );
+                    }
+                }
+                catch( java.io.IOException e )
+                {
+                    log.error( "Couldn't load " + MODULE_RESOURCE_LOCATION + " resources: " + resource, e );
+                }
+                catch( JDOMException e )
+                {
+                    log.error( "Error parsing XML for plugin: "+MODULE_RESOURCE_LOCATION );
+                }
+            }
+        }
+        catch( java.io.IOException e )
+        {
+            log.error( "Couldn't load all " + MODULE_RESOURCE_LOCATION + " resources", e );
+        }
+        
+        return list;
+    }
 }

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/modules/WikiModuleInfo.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/modules/WikiModuleInfo.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/modules/WikiModuleInfo.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/modules/WikiModuleInfo.java Mon Nov 10 12:50:38 2008
@@ -25,6 +25,7 @@
 import java.io.IOException;
 import java.net.URL;
 
+import org.apache.jspwiki.api.ModuleData;
 import org.jdom.Element;
 
 import com.ecyrd.jspwiki.FileUtil;
@@ -39,9 +40,9 @@
     implements Comparable<WikiModuleInfo>
 {
     protected String m_name;
-    protected String m_scriptLocation;
+    protected String[] m_scriptLocation;
     protected String m_scriptText;
-    protected String m_stylesheetLocation;
+    protected String[] m_stylesheetLocation;
     protected String m_stylesheetText;
     protected String m_author;
     protected URL    m_resource;
@@ -94,14 +95,29 @@
      */
     protected void initializeFromXML( Element el )
     {
-        m_scriptLocation     = el.getChildText("script");
-        m_stylesheetLocation = el.getChildText("stylesheet");
+        m_scriptLocation     = new String[] { el.getChildText("script") };
+        m_stylesheetLocation = new String[] { el.getChildText("stylesheet") };
         m_author             = el.getChildText("author");
         m_minVersion         = el.getChildText("minVersion");
         m_maxVersion         = el.getChildText("maxVersion");
         m_adminBeanClass     = el.getChildText("adminBean");
     }
 
+    protected void initializeFromClass( Class<?> c )
+    {
+        ModuleData data = c.getAnnotation( ModuleData.class );
+        
+        if( data != null )
+        {
+            m_author = data.author();
+            m_minVersion = data.minVersion();
+            m_maxVersion = data.maxVersion();
+            m_scriptLocation = data.scripts();
+            m_stylesheetLocation = data.stylesheets();
+            m_adminBeanClass = data.adminBeanClass();
+        }
+    }
+    
     /**
      *  Returns the AdminBean class which is supposed to manage this module.
      *  
@@ -131,7 +147,7 @@
      *  
      *  @return The path to the location.
      */
-    public String getStylesheetLocation()
+    public String[] getStylesheetLocation()
     {
         return m_stylesheetLocation;
     }
@@ -141,7 +157,7 @@
      *  
      *  @return The path to the location.
      */
-    public String getScriptLocation()
+    public String[] getScriptLocation()
     {
         return m_scriptLocation;
     }
@@ -202,7 +218,7 @@
     
         // Replace the 'PLUGIN_RESOURCE_LOCATION' with the requested
         //   resourceLocation.
-        int length = ModuleManager.PLUGIN_RESOURCE_LOCATION.length();
+        int length = ModuleManager.MODULE_RESOURCE_LOCATION.length();
         spec = spec.substring(0, spec.length() - length) + resourceLocation;
     
         URL url = new URL(spec);

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/IfPlugin.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/IfPlugin.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/IfPlugin.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/IfPlugin.java Mon Nov 10 12:50:38 2008
@@ -25,6 +25,7 @@
 import java.util.Map;
 
 import org.apache.commons.lang.StringUtils;
+import org.apache.jspwiki.api.ModuleData;
 import org.apache.oro.text.regex.*;
 
 import com.ecyrd.jspwiki.TextUtil;
@@ -102,6 +103,7 @@
  *  @author Murray Altheim
  *  @since 2.6
  */
+@ModuleData( aliases = { "If" } )
 public class IfPlugin implements WikiPlugin
 {
     /** The parameter name for setting the group to check.  Value is <tt>{@value}</tt>. */

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/Image.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/Image.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/Image.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/Image.java Mon Nov 10 12:50:38 2008
@@ -21,6 +21,9 @@
 package com.ecyrd.jspwiki.plugin;
 
 import java.util.*;
+
+import org.apache.jspwiki.api.ModuleData;
+
 import com.ecyrd.jspwiki.*;
 import com.ecyrd.jspwiki.attachment.AttachmentManager;
 import com.ecyrd.jspwiki.attachment.Attachment;
@@ -50,6 +53,9 @@
 // FIXME: It is not yet possible to do wiki internal links.  In order to
 //        do this cleanly, a TranslatorReader revamp is needed.
 
+@ModuleData(
+    author = "JSPWiki development group"
+)
 public class Image
     implements WikiPlugin
 {

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/PluginManager.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/PluginManager.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/PluginManager.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/plugin/PluginManager.java Mon Nov 10 12:50:38 2008
@@ -21,19 +21,17 @@
 package com.ecyrd.jspwiki.plugin;
 
 import java.io.*;
-import java.net.URL;
 import java.text.MessageFormat;
 import java.util.*;
 
+import net.sourceforge.stripes.util.ResolverUtil;
+
 import org.apache.commons.lang.ClassUtils;
 import org.apache.ecs.xhtml.*;
+import org.apache.jspwiki.api.ModuleData;
 import org.apache.log4j.Logger;
 import org.apache.oro.text.regex.*;
-import org.jdom.Document;
 import org.jdom.Element;
-import org.jdom.JDOMException;
-import org.jdom.input.SAXBuilder;
-import org.jdom.xpath.XPath;
 
 import com.ecyrd.jspwiki.*;
 import com.ecyrd.jspwiki.modules.ModuleManager;
@@ -94,23 +92,29 @@
  *  <pre>
  *  [{Counter name='foo'}]
  *  </pre>
- *  <h3>Plugin property files</h3>
+ *  <h3>Plugin annotations</h3>
+ *  <p>
+ *  As of JSPWiki 3.0, plugins may be annotated using the ModuleData
+ *  annotation.  Please see the javadoc for ModuleData.
+ *  
+ *  <h3>Adding plugins to the automatic search path</h3>
+ *  <p>
+ *  You may add a plugin by defining a deployment file "ini/jspwiki_module.xml"
+ *  with a single modules-element:
+ *  <pre>
+ *  &lt;modules package="com.mycompany.plugins"/&gt;
+ *  </pre>
+ *  This adds the plugin path "com.mycompany.plugins" in the list of
+ *  packages which are searched for WikiPlugin instances.
  *  <p>
- *  Since 2.3.25 you can also define a generic plugin XML properties file per
- *  each JAR file.
+ *  Another possibility is to use the <tt>jspwiki.plugin.searchPath</tt> -property.
+ *  For example, the equivalent invocation to the previous example:
  *  <pre>
- *  <modules>
- *   <plugin class="com.ecyrd.jspwiki.foo.TestPlugin">
- *       <author>Janne Jalkanen</author>
- *       <script>foo.js</script>
- *       <stylesheet>foo.css</stylesheet>
- *       <alias>code</alias>
- *   </plugin>
- *   <plugin class="com.ecyrd.jspwiki.foo.TestPlugin2">
- *       <author>Janne Jalkanen</author>
- *   </plugin>
- *   </modules>
+ *  jspwiki.plugin.searchPath = com.mycompany.plugins
  *  </pre>
+ *  However, this needs you to modify the property file by hand for each installation.
+ *  It is a recommended practice to create a deployment file for your plugin JAR.
+ *  
  *  <h3>Plugin lifecycle</h3>
  *
  *  <p>Plugin can implement multiple interfaces to let JSPWiki know at which stages they should
@@ -147,11 +151,6 @@
     private static final String DEFAULT_FORMS_PACKAGE = "com.ecyrd.jspwiki.forms";
 
     /**
-     *  The property name defining which packages will be searched for properties.
-     */
-    public static final String PROP_SEARCHPATH = "jspwiki.plugin.searchPath";
-
-    /**
      *  The name of the body content.  Current value is "_body".
      */
     public static final String PARAM_BODY      = "_body";
@@ -173,7 +172,7 @@
      */
     public static final String PARAM_DEBUG     = "debug";
 
-    private ArrayList<String>  m_searchPath = new ArrayList<String>();
+    private List<String>  m_searchPath;
 
     private Pattern m_pluginPattern;
 
@@ -194,19 +193,10 @@
     public PluginManager( WikiEngine engine, Properties props )
     {
         super(engine);
-        String packageNames = props.getProperty( PROP_SEARCHPATH );
 
-        if( packageNames != null )
-        {
-            StringTokenizer tok = new StringTokenizer( packageNames, "," );
-
-            while( tok.hasMoreTokens() )
-            {
-                m_searchPath.add( tok.nextToken().trim() );
-            }
-        }
-
-        registerPlugins();
+        m_searchPath = buildPluginSearchPath( props );
+        
+        registerAllPlugins();
 
         //
         //  The default packages are always added.
@@ -278,7 +268,7 @@
      *
      *  @throws ClassNotFoundException if no such class exists.
      */
-    private Class findPluginClass( String classname )
+    private Class<? extends WikiPlugin> findPluginClass( String classname )
         throws ClassNotFoundException
     {
         return ClassUtil.findClass( m_searchPath, classname );
@@ -614,7 +604,6 @@
      *  @return A DOM element
      *  @throws PluginException If plugin invocation is faulty
      */
-   @SuppressWarnings("unchecked")
    public PluginContent parsePluginLine( WikiContext context, String commandline, int pos )
         throws PluginException
     {
@@ -681,12 +670,15 @@
             m_pluginClassMap.put(name, pluginClass);
         }
 
-        // Registrar the plugin with a short convenient name.
-        name = pluginClass.getAlias();
-        if(name != null)
+        // Register the plugin with a short convenient name.
+        String[] aliases = pluginClass.getAliases();
+        if(aliases != null)
         {
-            log.debug("Registering plugin [shortName]: " + name);
-            m_pluginClassMap.put(name, pluginClass);
+            for( String a : aliases )
+            {
+                log.debug("Registering plugin [shortName]: " + a);
+                m_pluginClassMap.put(a, pluginClass);
+            }
         }
 
         // Registrar the plugin with the className with the package-part
@@ -700,61 +692,31 @@
         pluginClass.initializePlugin( m_engine );
     }
 
-    private void registerPlugins()
+    private void registerAllPlugins()
     {
         log.info( "Registering plugins" );
 
-        SAXBuilder builder = new SAXBuilder();
-
-        try
+        //
+        //  We locate every single class which implements the "WikiPlugin" interface.
+        //
+        
+        ResolverUtil<WikiPlugin> resolver = new ResolverUtil<WikiPlugin>();
+        
+        String[] paths = m_searchPath.toArray( new String[0] );
+        resolver.findImplementations( WikiPlugin.class, paths );
+        
+        Set<Class<? extends WikiPlugin>> resultSet = resolver.getClasses();
+        
+        log.debug( "Found "+resultSet.size()+" plugins" );
+        
+        for( Class<? extends WikiPlugin> clazz : resultSet )
         {
-            //
-            // Register all plugins which have created a resource containing its properties.
-            //
-            // Get all resources of all plugins.
-            //
-
-            Enumeration resources = getClass().getClassLoader().getResources( PLUGIN_RESOURCE_LOCATION );
+            WikiPluginInfo pluginInfo = WikiPluginInfo.newInstance( clazz );
 
-            while( resources.hasMoreElements() )
+            if( pluginInfo != null )
             {
-                URL resource = (URL) resources.nextElement();
-
-                try
-                {
-                    log.debug( "Processing XML: " + resource );
-
-                    Document doc = builder.build( resource );
-
-                    List plugins = XPath.selectNodes( doc, "/modules/plugin");
-
-                    for( Iterator i = plugins.iterator(); i.hasNext(); )
-                    {
-                        Element pluginEl = (Element) i.next();
-
-                        String className = pluginEl.getAttributeValue("class");
-
-                        WikiPluginInfo pluginInfo = WikiPluginInfo.newInstance( className, pluginEl );
-
-                        if( pluginInfo != null )
-                        {
-                            registerPlugin( pluginInfo );
-                        }
-                    }
-                }
-                catch( java.io.IOException e )
-                {
-                    log.error( "Couldn't load " + PLUGIN_RESOURCE_LOCATION + " resources: " + resource, e );
-                }
-                catch( JDOMException e )
-                {
-                    log.error( "Error parsing XML for plugin: "+PLUGIN_RESOURCE_LOCATION );
-                }
-            }
-        }
-        catch( java.io.IOException e )
-        {
-            log.error( "Couldn't load all " + PLUGIN_RESOURCE_LOCATION + " resources", e );
+                registerPlugin( pluginInfo );
+            } 
         }
     }
 
@@ -762,116 +724,62 @@
      *  Contains information about a bunch of plugins.
      *
      *  @author Kees Kuip
-     *  @author Janne Jalkanen
-     *
-     *  @since
      */
-    // FIXME: This class needs a better interface to return all sorts of possible
-    //        information from the plugin XML.  In fact, it probably should have
-    //        some sort of a superclass system.
     public static final class WikiPluginInfo
         extends WikiModuleInfo
     {
-        private String m_className;
-        private String m_alias;
-        private Class  m_clazz;
-
-        private boolean m_initialized = false;
-
-        /**
-         *  Creates a new plugin info object which can be used to access a plugin.
-         *
-         *  @param className Either a fully qualified class name, or a "short" name which is then
-         *                   checked against the internal list of plugin packages.
-         *  @param el A JDOM Element containing the information about this class.
-         *  @return A WikiPluginInfo object.
-         */
-        protected static WikiPluginInfo newInstance( String className, Element el )
-        {
-            if( className == null || className.length() == 0 ) return null;
-            WikiPluginInfo info = new WikiPluginInfo( className );
-
-            info.initializeFromXML( el );
-            return info;
-        }
-        /**
-         *  Initializes a plugin, if it has not yet been initialized.
-         *
-         *  @param engine The WikiEngine
-         */
-        protected void initializePlugin( WikiEngine engine )
-        {
-            if( !m_initialized )
-            {
-                // This makes sure we only try once per class, even if init fails.
-                m_initialized = true;
-
-                try
-                {
-                    WikiPlugin p = newPluginInstance();
-                    if( p instanceof InitializablePlugin )
-                    {
-                        ((InitializablePlugin)p).initialize( engine );
-                    }
-                }
-                catch( Exception e )
-                {
-                    log.info( "Cannot initialize plugin "+m_className, e );
-                }
-            }
-        }
-
-        /**
-         *  {@inheritDoc}
-         */
-        @Override
-        protected void initializeFromXML( Element el )
-        {
-            super.initializeFromXML( el );
-            m_alias = el.getChildText("alias");
-        }
-
+        String[] m_aliases;
+        Class<? extends WikiPlugin> m_clazz;
+        boolean m_initialized = false;
+        
         /**
          *  Create a new WikiPluginInfo based on the Class information.
          *  
          *  @param clazz The class to check
          *  @return A WikiPluginInfo instance
          */
-        protected static WikiPluginInfo newInstance( Class clazz )
+        protected static WikiPluginInfo newInstance( Class<? extends WikiPlugin> clazz )
         {
-            WikiPluginInfo info = new WikiPluginInfo( clazz.getName() );
+            WikiPluginInfo info = new WikiPluginInfo( clazz );
 
             return info;
         }
 
-        private WikiPluginInfo( String className )
+        private WikiPluginInfo( Class<? extends WikiPlugin> clazz )
         {
-            super(className);
-            setClassName( className );
+            super(clazz.getName());
+            setClassName( clazz.getName() );
+            initializeFromClass( clazz );
+            m_clazz = clazz;
+            
+            ModuleData md = clazz.getAnnotation( ModuleData.class );
+            if( md != null )
+            {
+                m_aliases = md.aliases();
+            }
         }
 
         private void setClassName( String fullClassName )
         {
             m_name = ClassUtils.getShortClassName( fullClassName );
-            m_className = fullClassName;
         }
-
+        
         /**
          *  Returns the full class name of this object.
          *  @return The full class name of the object.
          */
         public String getClassName()
         {
-            return m_className;
+            return m_clazz.getCanonicalName();
         }
 
         /**
          *  Returns the alias name for this object.
          *  @return An alias name for the plugin.
          */
-        public String getAlias()
+        public String[] getAliases()
         {
-            return m_alias;
+            return m_aliases;
         }
 
         /**
@@ -887,12 +795,7 @@
                    InstantiationException,
                    IllegalAccessException
         {
-            if( m_clazz == null )
-            {
-                m_clazz = Class.forName(m_className);
-            }
-
-            return (WikiPlugin) m_clazz.newInstance();
+            return m_clazz.newInstance();
         }
 
         /**
@@ -938,7 +841,7 @@
 
             try
             {
-                m_scriptText = getTextResource(m_scriptLocation);
+                m_scriptText = getTextResource(m_scriptLocation[0]);
             }
             catch( IOException ex )
             {
@@ -965,7 +868,7 @@
 
             try
             {
-                m_stylesheetText = getTextResource(m_stylesheetLocation);
+                m_stylesheetText = getTextResource(m_stylesheetLocation[0]);
             }
             catch( IOException ex )
             {
@@ -978,6 +881,33 @@
         }
 
         /**
+         *  Initializes a plugin, if it has not yet been initialized.
+         *
+         *  @param engine The WikiEngine
+         */
+        protected void initializePlugin( WikiEngine engine )
+        {
+            if( !m_initialized )
+            {
+                // This makes sure we only try once per class, even if init fails.
+                m_initialized = true;
+
+                try
+                {
+                    WikiPlugin p = newPluginInstance();
+                    if( p instanceof InitializablePlugin )
+                    {
+                        ((InitializablePlugin)p).initialize( engine );
+                    }
+                }
+                catch( Exception e )
+                {
+                    log.info( "Cannot initialize plugin "+m_clazz.getCanonicalName(), e );
+                }
+            }
+        }
+
+        /**
          *  Returns a string suitable for debugging.  Don't assume that the format
          *  would stay the same.
          *  
@@ -985,20 +915,20 @@
          */
         public String toString()
         {
-            return "Plugin :[name=" + m_name + "][className=" + m_className + "]";
+            return "Plugin :[name=" + m_name + "][className=" + m_clazz.getCanonicalName() + "]";
         }
     } // WikiPluginClass
 
     /**
      *  {@inheritDoc}
      */
-    public Collection modules()
+    public Collection<WikiPluginInfo> modules()
     {
-        TreeSet<WikiModuleInfo> ls = new TreeSet<WikiModuleInfo>();
+        TreeSet<WikiPluginInfo> ls = new TreeSet<WikiPluginInfo>();
         
         for( Iterator i = m_pluginClassMap.values().iterator(); i.hasNext(); )
         {
-            WikiModuleInfo wmi = (WikiModuleInfo)i.next();
+            WikiPluginInfo wmi = (WikiPluginInfo) i.next();
             
             if( !ls.contains(wmi) ) ls.add(wmi);
         }

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/ui/EditorManager.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/ui/EditorManager.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/ui/EditorManager.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/ui/EditorManager.java Mon Nov 10 12:50:38 2008
@@ -37,7 +37,6 @@
 import com.ecyrd.jspwiki.WikiEngine;
 import com.ecyrd.jspwiki.modules.ModuleManager;
 import com.ecyrd.jspwiki.modules.WikiModuleInfo;
-import com.ecyrd.jspwiki.plugin.PluginManager;
 import com.ecyrd.jspwiki.preferences.Preferences;
 
 /**
@@ -123,7 +122,7 @@
             // Get all resources of all modules
             //
 
-            Enumeration resources = getClass().getClassLoader().getResources( PLUGIN_RESOURCE_LOCATION );
+            Enumeration resources = getClass().getClassLoader().getResources( MODULE_RESOURCE_LOCATION );
 
             while( resources.hasMoreElements() )
             {
@@ -159,17 +158,17 @@
                 }
                 catch( java.io.IOException e )
                 {
-                    log.error( "Couldn't load " + PluginManager.PLUGIN_RESOURCE_LOCATION + " resources: " + resource, e );
+                    log.error( "Couldn't load " + ModuleManager.MODULE_RESOURCE_LOCATION + " resources: " + resource, e );
                 }
                 catch( JDOMException e )
                 {
-                    log.error( "Error parsing XML for plugin: "+PluginManager.PLUGIN_RESOURCE_LOCATION );
+                    log.error( "Error parsing XML for plugin: "+ModuleManager.MODULE_RESOURCE_LOCATION );
                 }
             }
         }
         catch( java.io.IOException e )
         {
-            log.error( "Couldn't load all " + PLUGIN_RESOURCE_LOCATION + " resources", e );
+            log.error( "Couldn't load all " + MODULE_RESOURCE_LOCATION + " resources", e );
         }
     }
 

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/ui/admin/beans/PluginBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/ui/admin/beans/PluginBean.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/ui/admin/beans/PluginBean.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/ui/admin/beans/PluginBean.java Mon Nov 10 12:50:38 2008
@@ -76,7 +76,7 @@
 
         tr head = new tr();
         head.addElement( new th("Name") );
-        head.addElement( new th("Alias") );
+        head.addElement( new th("Aliases") );
         head.addElement( new th("Author") );
         head.addElement( new th("Notes") );
 
@@ -89,8 +89,16 @@
 
             WikiPluginInfo info = i.next();
 
+            StringBuilder aliases = new StringBuilder();
+            
+            for( String s : info.getAliases() )
+            {
+                if( aliases.length() > 0 ) aliases.append( ", " );
+                aliases.append( s );
+            }
+
             row.addElement( new td(info.getName()) );
-            row.addElement( new td(info.getAlias()) );
+            row.addElement( new td(aliases.toString()) );
             row.addElement( new td(info.getAuthor()) );
 
             String verWarning = "";

Modified: incubator/jspwiki/trunk/src/org/apache/jspwiki/api/ModuleData.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/org/apache/jspwiki/api/ModuleData.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/org/apache/jspwiki/api/ModuleData.java (original)
+++ incubator/jspwiki/trunk/src/org/apache/jspwiki/api/ModuleData.java Mon Nov 10 12:50:38 2008
@@ -65,13 +65,13 @@
      *  Defines the style sheets which should be included whenever this module
      *  is used.  For PageFilters this means almost every single request.
      */
-    String[] stylesheets()  default {};
+    String[] stylesheets()  default "";
     
     /**  
      *  Defines the Javascripts which should be included whenever this module
      *  is used.
      */
-    String[] scripts()      default {};
+    String[] scripts()      default "";
     
     /**
      *  Returns the class name for the AdminBean which governs the use of this

Modified: incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/plugin/PluginManagerTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/plugin/PluginManagerTest.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/plugin/PluginManagerTest.java (original)
+++ incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/plugin/PluginManagerTest.java Mon Nov 10 12:50:38 2008
@@ -1,6 +1,7 @@
 
 package com.ecyrd.jspwiki.plugin;
 
+import java.util.Collection;
 import java.util.Properties;
 
 import junit.framework.Test;
@@ -11,6 +12,7 @@
 import com.ecyrd.jspwiki.WikiContext;
 import com.ecyrd.jspwiki.WikiEngine;
 import com.ecyrd.jspwiki.WikiPage;
+import com.ecyrd.jspwiki.plugin.PluginManager.WikiPluginInfo;
 import com.ecyrd.jspwiki.providers.ProviderException;
 
 public class PluginManagerTest extends TestCase
@@ -198,6 +200,28 @@
         assertTrue( SamplePlugin.c_rendered );
     }
 
+    public void testAnnotations() throws Exception
+    {
+        Collection<WikiPluginInfo> plugins = manager.modules();
+        
+        for( WikiPluginInfo wpi : plugins )
+        {
+            if( wpi.getName().equals( "SamplePlugin" ) )
+            {
+                assertEquals("author", "Urgle Burgle", wpi.getAuthor());
+                String[] aliases = wpi.getAliases();
+                
+                assertNotNull("aliases",aliases);
+                assertEquals( "aliases len", 2, aliases.length );
+                assertTrue( "data", ( aliases[0].equals( "samplealias2" ) && aliases[1].equals( "samplealias" ) )
+                            || (aliases[0].equals("samplealias") && aliases[1].equals("samplealias2")) );
+                return; // We're done
+            }
+        }
+        
+        fail("No SamplePlugin found");
+    }
+    
     public static Test suite()
     {
         return new TestSuite( PluginManagerTest.class );

Modified: incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/plugin/SamplePlugin.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/plugin/SamplePlugin.java?rev=712830&r1=712829&r2=712830&view=diff
==============================================================================
--- incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/plugin/SamplePlugin.java (original)
+++ incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/plugin/SamplePlugin.java Mon Nov 10 12:50:38 2008
@@ -2,6 +2,8 @@
 
 import java.util.Map;
 
+import org.apache.jspwiki.api.ModuleData;
+
 import com.ecyrd.jspwiki.WikiContext;
 import com.ecyrd.jspwiki.parser.PluginContent;
 
@@ -10,9 +12,9 @@
  *  <P>
  *  Parameters: text - text to return.
  *  Any _body content gets appended between brackets.
- *
- *  @author Janne Jalkanen
  */
+@ModuleData( author = "Urgle Burgle", 
+             aliases = { "samplealias2", "samplealias" } )
 public class SamplePlugin
     implements WikiPlugin, ParserStagePlugin
 {