jspwiki-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ajaqu...@apache.org
Subject svn commit: r627255 [26/41] - in /incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src: ./ com/ com/ecyrd/ com/ecyrd/jspwiki/ com/ecyrd/jspwiki/action/ com/ecyrd/jspwiki/attachment/ com/ecyrd/jspwiki/auth/ com/ecyrd/jspwiki/auth/acl/ com/ecyrd/jspwiki...
Date Wed, 13 Feb 2008 05:54:24 GMT
Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/IfPlugin.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/IfPlugin.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/IfPlugin.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/IfPlugin.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,285 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2007 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package com.ecyrd.jspwiki.plugin;
+
+import java.security.Principal;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.oro.text.regex.*;
+
+import com.ecyrd.jspwiki.TextUtil;
+import com.ecyrd.jspwiki.WikiContext;
+import com.ecyrd.jspwiki.WikiProvider;
+
+/**
+ *  The IfPlugin allows parts of a WikiPage to be executed conditionally.
+ *  You can also use shorthand "If" to run it.
+ *  Parameters:
+ *  <ul>
+ *    <li>group - A "|" -separated list of group names.
+ *    <li>user  - A "|" -separated list of user names.
+ *    <li>ip    - A "|" -separated list of ip addresses.
+ *    <li>var   - A wiki variable
+ *    <li>page  - A page name
+ *    <li>contains - A Perl5 regexp pattern
+ *    <li>is    - A Perl5 regexp pattern
+ *    <li>exists - "true" or "false".
+ *  </ul>
+ *
+ *  <p>If any of them match, the body of the plugin is executed.  You can
+ *  negate the content by prefixing it with a "!".  For example, to greet
+ *  all admins, put the following in your LeftMenu:</p>
+ *  <pre>
+ *  [{If group='Admin'
+ *
+ *  Hello, Admin, and your mighty powers!}]
+ *  </pre>
+ *
+ *  <p>In order to send a message to everybody except Jack use</p>
+ *  <pre>
+ *  [{If user='!Jack'
+ *
+ *  %%warning
+ *  Jack's surprise birthday party at eleven!
+ *  %%}]
+ *  </pre>
+ *
+ *  <p>Note that you can't use "!Jack|!Jill", because for Jack, !Jill matches;
+ *  and for Jill, !Jack matches.  These are not regular expressions (though
+ *  they might become so in the future).<p>
+ *
+ *  <p>To check for page content, use</p>
+ *  <pre>
+ *  [{If page='TestPage' contains='xyzzy'
+ *
+ *  Page contains the text "xyzzy"}]
+ *  </pre>
+ *
+ *  <p>The difference between "contains" and "is" is that "is" is always an exact match,
+ *  whereas "contains" just checks if a pattern is available.</p>
+ *
+ *  <p>To check for page existence, use</p>
+ *  <pre>
+ *  [{If page='TestPage' exists='true'
+ *
+ *  Page "TestPage" exists.}]
+ *  </pre>
+ *  <p>With the same mechanism, it's also possible to test for the existence
+ *  of a variable - just use "var" instead of "page".</p>
+ *  
+ *  <p>Another caveat is that the plugin body content is not counted
+ *  towards ReferenceManager links.  So any links do not appear on any reference
+ *  lists.  Depending on your position, this may be a good or a bad
+ *  thing.</p>
+ *
+ *  <h3>Calling Externally</h3>
+ *
+ *  <p>The functional, decision-making part of this plugin may be called from
+ *  other code (e.g., other plugins) since it is available as a static method
+ *  {@link #ifInclude(WikiContext,Map)}. Note that the plugin body may contain
+ *  references to other plugins.</p>
+ *
+ *  @author Janne Jalkanen
+ *  @author Murray Altheim
+ *  @since 2.6
+ */
+public class IfPlugin implements WikiPlugin
+{
+    public static final String PARAM_GROUP    = "group";
+    public static final String PARAM_USER     = "user";
+    public static final String PARAM_IP       = "ip";
+    public static final String PARAM_PAGE     = "page";
+    public static final String PARAM_CONTAINS = "contains";
+    public static final String PARAM_VAR      = "var";
+    public static final String PARAM_IS       = "is";
+    public static final String PARAM_EXISTS   = "exists";
+
+    /**
+     *  {@inheritDoc}
+     */
+    public String execute(WikiContext context, Map params) throws PluginException
+    {
+        return ifInclude(context,params)
+                ? context.getEngine().textToHTML(
+                        context,(String)params.get(PluginManager.PARAM_BODY) )
+                : "" ;
+    }
+
+
+    /**
+     *  Returns a boolean result based on processing the WikiContext and
+     *  parameter Map as according to the rules stated in the IfPlugin
+     *  documentation. 
+     *  As a static method this may be called by other classes.
+     *
+     * @param context   The current WikiContext.
+     * @param params    The parameter Map which contains key-value pairs.
+     */
+    public static boolean ifInclude( WikiContext context, Map params ) throws PluginException
+    {
+        boolean include = false;
+
+        String group    = (String)params.get(PARAM_GROUP);
+        String user     = (String)params.get(PARAM_USER);
+        String ip       = (String)params.get(PARAM_IP);
+        String page     = (String)params.get(PARAM_PAGE);
+        String contains = (String)params.get(PARAM_CONTAINS);
+        String var      = (String)params.get(PARAM_VAR);
+        String is       = (String)params.get(PARAM_IS);
+        String exists   = (String)params.get(PARAM_EXISTS);
+
+        include |= checkGroup(context, group);
+        include |= checkUser(context, user);
+        include |= checkIP(context, ip);
+
+        if( page != null )
+        {
+            String content = context.getEngine().getPureText(page, WikiProvider.LATEST_VERSION).trim();
+            include |= checkContains(content,contains);
+            include |= checkIs(content,is);
+            include |= checkExists(context,page,exists);
+        }
+
+        if( var != null )
+        {
+            String content = context.getEngine().getVariable(context, var);
+            include |= checkContains(content,contains);
+            include |= checkIs(content,is);
+            include |= checkVarExists(content,exists);
+        }
+
+        return include;
+    }
+
+    private static boolean checkExists( WikiContext context, String page, String exists )
+    {
+        if( exists == null ) return false;
+        return !context.getEngine().pageExists(page) ^ TextUtil.isPositive(exists);
+    }
+
+    private static boolean checkVarExists( String varContent, String exists )
+    {
+        if( exists == null ) return false;
+        return (varContent == null ) ^ TextUtil.isPositive(exists);
+    }
+
+    private static boolean checkGroup( WikiContext context, String group )
+    {
+        if( group == null ) return false;
+        String[] groupList = StringUtils.split(group,'|');
+        boolean include = false;
+
+        for( int i = 0; i < groupList.length; i++ )
+        {
+            String gname = groupList[i];
+            boolean invert = false;
+            if( groupList[i].startsWith("!") )
+            {
+                gname = groupList[i].substring(1);
+                invert = true;
+            }
+
+            Principal g = context.getEngine().getAuthorizationManager().resolvePrincipal(gname);
+
+            include |= context.getEngine().getAuthorizationManager().isUserInRole( context.getWikiSession(), g ) ^ invert;
+        }
+        return include;
+    }
+
+    private static boolean checkUser( WikiContext context, String user )
+    {
+        if( user == null || context.getCurrentUser() == null ) return false;
+
+        String[] list = StringUtils.split(user,'|');
+        boolean include = false;
+
+        for( int i = 0; i < list.length; i++ )
+        {
+            boolean invert = false;
+            if( list[i].startsWith("!") )
+            {
+                invert = true;
+            }
+
+            include |= user.equals( context.getCurrentUser().getName() ) ^ invert;
+        }
+        return include;
+    }
+
+    // TODO: Add subnetwork matching, e.g. 10.0.0.0/8
+    private static boolean checkIP( WikiContext context, String ipaddr )
+    {
+        if( ipaddr == null || context.getHttpRequest() == null ) return false;
+
+        String[] list = StringUtils.split(ipaddr,'|');
+        boolean include = false;
+
+        for( int i = 0; i < list.length; i++ )
+        {
+            boolean invert = false;
+            if( list[i].startsWith("!") )
+            {
+                invert = true;
+            }
+
+            include |= ipaddr.equals( context.getHttpRequest().getRemoteAddr() ) ^ invert;
+        }
+        return include;
+    }
+
+    private static boolean doMatch( String content, String pattern )
+        throws PluginException
+    {
+        PatternCompiler compiler = new Perl5Compiler();
+        PatternMatcher  matcher  = new Perl5Matcher();
+
+        try
+        {
+            Pattern matchp = compiler.compile( pattern, Perl5Compiler.SINGLELINE_MASK );
+            // m_exceptPattern = compiler.compile( exceptPattern, Perl5Compiler.SINGLELINE_MASK );
+            return matcher.matches( content, matchp );
+        }
+        catch( MalformedPatternException e )
+        {
+            throw new PluginException("Faulty pattern "+pattern);
+        }
+
+    }
+
+    private static boolean checkContains( String pagecontent, String matchPattern )
+        throws PluginException
+    {
+        if( pagecontent == null || matchPattern == null ) return false;
+
+        return doMatch( pagecontent, ".*"+matchPattern+".*" );
+    }
+
+    private static boolean checkIs( String content, String matchPattern )
+        throws PluginException
+    {
+        if( content == null || matchPattern == null ) return false;
+
+        matchPattern = "^"+matchPattern+"$";
+
+        return doMatch(content, matchPattern);
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/Image.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/Image.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/Image.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/Image.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,192 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2002 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package com.ecyrd.jspwiki.plugin;
+
+import java.util.*;
+import com.ecyrd.jspwiki.*;
+import com.ecyrd.jspwiki.action.AttachActionBean;
+import com.ecyrd.jspwiki.attachment.AttachmentManager;
+import com.ecyrd.jspwiki.attachment.Attachment;
+import com.ecyrd.jspwiki.providers.ProviderException;
+
+/**
+ *  Provides an image plugin for better control than is possible with
+ *  a simple image inclusion.
+ *
+ *  @author Janne Jalkanen
+ *  @since 2.1.4.
+ */
+// FIXME: It is not yet possible to do wiki internal links.  In order to
+//        do this cleanly, a TranslatorReader revamp is needed.
+
+public class Image
+    implements WikiPlugin
+{
+    public static final String PARAM_SRC      = "src";
+    public static final String PARAM_ALIGN    = "align";
+    public static final String PARAM_HEIGHT   = "height";
+    public static final String PARAM_WIDTH    = "width";
+    public static final String PARAM_ALT      = "alt";
+    public static final String PARAM_CAPTION  = "caption";
+    public static final String PARAM_LINK     = "link";
+    public static final String PARAM_TARGET   = "target";
+    public static final String PARAM_STYLE    = "style";
+    public static final String PARAM_CLASS    = "class";
+    //    public static final String PARAM_MAP      = "map";
+    public static final String PARAM_BORDER   = "border";
+
+    /**
+     *  This method is used to clean away things like quotation marks which
+     *  a malicious user could use to stop processing and insert javascript.
+     */
+    private static final String getCleanParameter( Map params, String paramId )
+    {
+        return TextUtil.replaceEntities( (String) params.get( paramId ) );
+    }
+
+    public String execute( WikiContext context, Map params )
+        throws PluginException
+    {
+        WikiEngine engine = context.getEngine();
+        String src     = getCleanParameter( params, PARAM_SRC );
+        String align   = getCleanParameter( params, PARAM_ALIGN );
+        String ht      = getCleanParameter( params, PARAM_HEIGHT );
+        String wt      = getCleanParameter( params, PARAM_WIDTH );
+        String alt     = getCleanParameter( params, PARAM_ALT );
+        String caption = getCleanParameter( params, PARAM_CAPTION );
+        String link    = getCleanParameter( params, PARAM_LINK );
+        String target  = getCleanParameter( params, PARAM_TARGET );
+        String style   = getCleanParameter( params, PARAM_STYLE );
+        String cssclass= getCleanParameter( params, PARAM_CLASS );
+        // String map     = getCleanParameter( params, PARAM_MAP );
+        String border  = getCleanParameter( params, PARAM_BORDER );
+
+        if( src == null )
+        {
+            throw new PluginException("Parameter 'src' is required for Image plugin");
+        }
+
+        if( cssclass == null ) cssclass = "imageplugin";
+
+        if( target != null && !validTargetValue(target) )
+        {
+            target = null; // not a valid value so ignore
+        }
+
+        try
+        {
+            AttachmentManager mgr = engine.getAttachmentManager();
+            Attachment        att = mgr.getAttachmentInfo( context, src );
+
+            if( att != null )
+            {
+                src = context.getContext().getURL( AttachActionBean.class, att.getName() );
+            }
+        }
+        catch( ProviderException e )
+        {
+            throw new PluginException( "Attachment info failed: "+e.getMessage() );
+        }
+
+        StringBuffer result = new StringBuffer();
+
+        result.append( "<table border=\"0\" class=\""+cssclass+"\"" );
+        //if( align != null ) result.append(" align=\""+align+"\"");
+        //if( style != null ) result.append(" style=\""+style+"\"");
+        
+        //
+        //  Do some magic to make sure centering also work on FireFox
+        //
+        if( style != null ) 
+        {
+            result.append(" style=\""+style);
+
+            // Make sure that we add a ";" to the end of the style string
+            if( result.charAt( result.length()-1 ) != ';' ) result.append(";");
+                
+            if( align != null && align.equals("center") ) 
+            {
+                result.append(" margin-left: auto; margin-right: auto;");
+            }
+                
+            result.append("\"");
+        }
+        else
+        {
+            if( align != null && align.equals("center") ) result.append(" style=\"margin-left: auto; margin-right: auto;\"");
+        }
+        
+        if( align != null && !(align.equals("center")) ) result.append(" align=\""+align+"\"");
+        
+        result.append( ">\n" );
+
+        if( caption != null ) 
+        {
+            result.append("<caption align=bottom>"+TextUtil.replaceEntities(caption)+"</caption>\n");
+        }
+
+
+        result.append( "<tr><td>" );
+       
+        if( link != null ) 
+        {
+            result.append("<a href=\""+link+"\"");
+            if( target != null )
+            {
+                result.append(" target=\""+target+"\"");
+            }
+            result.append(">");
+        }
+
+        result.append( "<img src=\""+src+"\"" );
+       
+        if( ht != null )     result.append(" height=\""+ht+"\"");
+        if( wt != null )     result.append(" width=\""+wt+"\"");
+        if( alt != null )    result.append(" alt=\""+alt+"\"");
+        if( border != null ) result.append(" border=\""+border+"\"");
+        // if( map != null )    result.append(" map=\""+map+"\"");
+
+        result.append(" />");
+        if( link != null )  result.append("</a>");
+        result.append("</td></tr>\n");
+
+        result.append("</table>\n");
+
+        return result.toString();
+    }
+
+    private boolean validTargetValue( String s )
+    {
+        if( s.equals("_blank")
+                || s.equals("_self")
+                || s.equals("_parent")
+                || s.equals("_top") )
+        {
+            return true;
+        } 
+        else if( s.length() > 0 ) // check [a-zA-z]
+        {
+            char c = s.charAt(0);
+            return Character.isLowerCase(c) || Character.isUpperCase(c);
+        }
+        return false;
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/IndexPlugin.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/IndexPlugin.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/IndexPlugin.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/IndexPlugin.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,236 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2002 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package com.ecyrd.jspwiki.plugin;
+
+import java.io.StringWriter;
+import java.util.*;
+
+import org.apache.log4j.Logger;
+import org.apache.oro.text.GlobCompiler;
+import org.apache.oro.text.regex.*;
+
+import com.ecyrd.jspwiki.*;
+import com.ecyrd.jspwiki.action.ViewActionBean;
+import com.ecyrd.jspwiki.providers.ProviderException;
+
+/**
+ *  Builds an index of all pages.
+ *  <P>Parameters</P>
+ *  <UL>
+ *    <LI>itemsPerLine: How many items should be allowed per line before break.
+ *    If set to zero (the default), will not write breaks.
+ *    <LI>include: Include only these pages.
+ *    <LI>exclude: Exclude with this pattern.
+ *  </UL>
+ *
+ *  @author Alain Ravet
+ *  @author Janne Jalkanen
+ *  @since 1.9.9
+ */
+public class IndexPlugin implements WikiPlugin
+{
+    protected static final Logger log = Logger.getLogger(IndexPlugin.class);
+
+    public  static final String INITIALS_COLOR                  = "red" ;
+    private static final int    DEFAULT_ITEMS_PER_LINE          = 0     ;
+
+    private static final String PARAM_ITEMS_PER_LINE            = "itemsPerLine";
+    private static final String PARAM_INCLUDE                   = "include";
+    private static final String PARAM_EXCLUDE                   = "exclude";
+
+    private int                 m_currentNofPagesOnLine         = 0;
+    private int                 m_itemsPerLine;
+    protected String            m_previousPageFirstLetter       = "";
+    protected StringWriter      m_bodyPart      =   new StringWriter();
+    protected StringWriter      m_headerPart    =   new StringWriter();
+    private Pattern             m_includePattern;
+    private Pattern             m_excludePattern;
+
+
+    public String execute( WikiContext wikiContext , Map params )
+        throws PluginException
+    {
+        //
+        //  Parse arguments and create patterns.
+        //
+        PatternCompiler compiler = new GlobCompiler();
+        m_itemsPerLine = TextUtil.parseIntParameter( (String) params.get(PARAM_ITEMS_PER_LINE),
+                                                     DEFAULT_ITEMS_PER_LINE );
+        try
+        {
+            String ptrn = (String) params.get(PARAM_INCLUDE);
+            if( ptrn == null ) ptrn = "*";
+            m_includePattern = compiler.compile(ptrn);
+
+            ptrn = (String) params.get(PARAM_EXCLUDE);
+            if( ptrn == null ) ptrn = "";
+            m_excludePattern = compiler.compile(ptrn);
+        }
+        catch( MalformedPatternException e )
+        {
+            throw new PluginException("Illegal pattern detected."); // FIXME, make a proper error.
+        }
+
+        //
+        //  Get pages, then sort.
+        //
+
+        final Collection        allPages      = getAllPagesSortedByName( wikiContext );
+
+        //
+        //  Build the page.
+        //
+        buildIndexPageHeaderAndBody( wikiContext, allPages );
+
+        StringBuffer res = new StringBuffer();
+
+        res.append( "<div class=\"index\">\n" );
+        res.append( "<div class=\"header\">\n" );
+        res.append( m_headerPart.toString() );
+        res.append( "</div>\n" );
+        res.append( "<div class=\"body\">\n" );
+        res.append( m_bodyPart.toString() );
+        res.append( "</div>\n</div>\n" );
+
+        return res.toString();
+    }
+
+
+    private void buildIndexPageHeaderAndBody( WikiContext context,
+                                              final Collection allPages )
+    {
+        PatternMatcher matcher = new Perl5Matcher();
+
+        for( Iterator i = allPages.iterator (); i.hasNext ();)
+        {
+            WikiPage curPage = (WikiPage) i.next();
+
+            if( matcher.matches( curPage.getName(), m_includePattern ) )
+            {
+                if( !matcher.matches( curPage.getName(), m_excludePattern ) )
+                {
+                    ++m_currentNofPagesOnLine;
+
+                    String    pageNameFirstLetter           = curPage.getName().substring(0,1).toUpperCase();
+                    boolean   sameFirstLetterAsPreviousPage = m_previousPageFirstLetter.equals(pageNameFirstLetter);
+
+                    if( !sameFirstLetterAsPreviousPage )
+                    {
+                        addLetterToIndexHeader( pageNameFirstLetter );
+                        addLetterHeaderWithLine( pageNameFirstLetter );
+
+                        m_currentNofPagesOnLine   = 1;
+                        m_previousPageFirstLetter = pageNameFirstLetter;
+                    }
+
+                    addPageToIndex( context, curPage );
+                    breakLineIfTooLong();
+                }
+            }
+        } // for
+    }
+
+
+    /**
+     *  Gets all pages, then sorts them.
+     */
+    static Collection getAllPagesSortedByName( WikiContext wikiContext )
+    {
+        final WikiEngine engine = wikiContext.getEngine();
+
+        final PageManager pageManager = engine.getPageManager();
+        if( pageManager == null )
+            return null;
+
+        Collection result = new TreeSet( new Comparator() {
+            public int compare( Object o1, Object o2 )
+            {
+                if( o1 == null || o2 == null ) return 0;
+
+                WikiPage page1 = (WikiPage)o1;
+                WikiPage page2 = (WikiPage)o2;
+
+                return page1.getName().compareTo( page2.getName() );
+            }
+        });
+
+        try
+        {
+            Collection allPages = pageManager.getAllPages();
+            result.addAll( allPages );
+        }
+        catch( ProviderException e )
+        {
+            log.fatal("PageProvider is unable to list pages: ", e);
+        }
+
+        return result;
+    }
+
+
+    private void addLetterToIndexHeader( final String firstLetter )
+    {
+        final boolean noLetterYetInTheIndex = ! "".equals(m_previousPageFirstLetter);
+
+        if( noLetterYetInTheIndex )
+        {
+            m_headerPart.write(" - " );
+        }
+
+        m_headerPart.write("<a href=\"#"  + firstLetter + "\">" + firstLetter + "</a>" );
+    }
+
+
+    private void addLetterHeaderWithLine( final String firstLetter )
+    {
+        m_bodyPart.write("\n<br /><br />" +
+                         "<span class=\"section\">"+
+                         "<a name=\"" + firstLetter + "\">"+
+                         firstLetter+"</a></span>" +
+                         "<hr />\n" );
+    }
+
+    protected void addPageToIndex( WikiContext context, WikiPage curPage )
+    {
+        final boolean notFirstPageOnLine = 2 <= m_currentNofPagesOnLine;
+
+        if( notFirstPageOnLine )
+        {
+            m_bodyPart.write(",&nbsp; ");
+        }
+
+        m_bodyPart.write("<a href=\""+
+                         context.getContext().getURL(ViewActionBean.class, curPage.getName())+"\">"+
+                         context.getEngine().beautifyTitleNoBreak(curPage.getName())+
+                         "</a>");
+    }
+
+    protected void breakLineIfTooLong()
+    {
+        final boolean limitReached = m_itemsPerLine == m_currentNofPagesOnLine;
+
+        if( limitReached )
+        {
+            m_bodyPart.write( "<br />\n" );
+            m_currentNofPagesOnLine = 0;
+        }
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/InitializablePlugin.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/InitializablePlugin.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/InitializablePlugin.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/InitializablePlugin.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,47 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2001-2004 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package com.ecyrd.jspwiki.plugin;
+
+import com.ecyrd.jspwiki.WikiEngine;
+
+/**
+ *  If a plugin defines this interface, it is called exactly once
+ *  prior to the actual execute() routine.  If the plugin has its
+ *  own declaration in jspwiki_modules.xml, then it is called during
+ *  startup - otherwise it is called the first time the plugin is
+ *  encountered.
+ *  <p>
+ *  This method did not actually work until 2.5.30.  The method signature
+ *  has been changed in 2.6 to reflect the new operation.
+ *
+ *  @since 2.2
+ *
+ *  @author Janne Jalkanen
+ */
+public interface InitializablePlugin
+{
+    /**
+     *  Called whenever the plugin is being instantiated for
+     *  the first time.
+     */
+
+    public void initialize( WikiEngine engine )
+        throws PluginException;
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/InsertPage.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/InsertPage.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/InsertPage.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/InsertPage.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,174 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2002 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package com.ecyrd.jspwiki.plugin;
+
+import com.ecyrd.jspwiki.*;
+import com.ecyrd.jspwiki.action.EditActionBean;
+import com.ecyrd.jspwiki.action.ViewActionBean;
+import com.ecyrd.jspwiki.auth.*;
+import com.ecyrd.jspwiki.auth.permissions.PermissionFactory;
+
+import java.util.*;
+
+/**
+ *  Inserts page contents.  Muchos thanks to Scott Hurlbert for the initial code.
+ *
+ *  @since 2.1.37
+ *  @author Scott Hurlbert
+ *  @author Janne Jalkanen
+ */
+public class InsertPage
+    implements WikiPlugin
+{
+    public static final String PARAM_PAGENAME  = "page";
+    public static final String PARAM_STYLE     = "style";
+    public static final String PARAM_MAXLENGTH = "maxlength";
+    public static final String PARAM_CLASS     = "class";
+    public static final String PARAM_SECTION   = "section";
+    public static final String PARAM_DEFAULT   = "default";
+
+    private static final String DEFAULT_STYLE = "";
+
+    public static final String ATTR_RECURSE    = "com.ecyrd.jspwiki.plugin.InsertPage.recurseCheck";
+    
+    public String execute( WikiContext context, Map params )
+        throws PluginException
+    {
+        WikiEngine engine = context.getEngine();
+
+        StringBuffer res = new StringBuffer();
+
+        String clazz        = (String) params.get( PARAM_CLASS );
+        String includedPage = (String) params.get( PARAM_PAGENAME );
+        String style        = (String) params.get( PARAM_STYLE );
+        String defaultstr   = (String) params.get( PARAM_DEFAULT );
+        int    section      = TextUtil.parseIntParameter((String) params.get( PARAM_SECTION ), 
+                                                         -1 );
+        int    maxlen       = TextUtil.parseIntParameter((String) params.get( PARAM_MAXLENGTH ),
+                                                         -1 );
+
+        if( style == null ) style = DEFAULT_STYLE;
+
+        if( maxlen == -1 ) maxlen = Integer.MAX_VALUE;
+
+        if( includedPage != null )
+        {
+            WikiPage page = engine.getPage( includedPage );
+
+            
+            if( page != null )
+            {
+                //
+                //  Check for recursivity
+                //
+                
+                List previousIncludes = (List)context.getVariable( ATTR_RECURSE );
+                
+                if( previousIncludes != null )
+                {
+                    if( previousIncludes.contains( page.getName() ) )
+                    {
+                        return "<span class=\"error\">Error: Circular reference - you can't include a page in itself!</span>";
+                    }
+                }
+                else
+                {
+                    previousIncludes = new ArrayList();
+                }
+               
+                previousIncludes.add( page.getName() );
+                context.setVariable( ATTR_RECURSE, previousIncludes );
+                
+                //
+                // Check for permissions
+                //
+                AuthorizationManager mgr = engine.getAuthorizationManager();
+
+                if( !mgr.checkPermission( context.getWikiSession(),
+                                          PermissionFactory.getPagePermission( page, "view") ) )
+                {
+                    res.append("<span class=\"error\">You do not have permission to view this included page.</span>");
+                    return res.toString();
+                }
+
+                /**
+                 *  We want inclusion to occur within the context of
+                 *  its own page, because we need the links to be correct.
+                 */
+                
+                WikiContext includedContext = (WikiContext) context.clone();
+                includedContext.setPage( page );
+
+                String pageData = engine.getPureText( page );
+                String moreLink = "";
+
+                if( section != -1 )
+                {
+                    try
+                    {
+                        pageData = TextUtil.getSection( pageData, section );
+                    }
+                    catch( IllegalArgumentException e )
+                    {
+                        throw new PluginException( e.getMessage() );
+                    }
+                }
+
+                if( pageData.length() > maxlen ) 
+                {
+                    pageData = pageData.substring( 0, maxlen )+" ...";
+                    moreLink = "<p><a href=\""+context.getContext().getURL(ViewActionBean.class,includedPage)+"\">More...</a></p>";
+                }
+
+                res.append("<div style=\""+style+"\""+(clazz != null ? " class=\""+clazz+"\"" : "")+">");
+                res.append( engine.textToHTML( includedContext, pageData ) );
+                res.append( moreLink );
+                res.append("</div>");
+                
+                //
+                //  Remove the name from the stack; we're now done with this.
+                //
+                previousIncludes.remove( page.getName() );
+                context.setVariable( ATTR_RECURSE, previousIncludes );
+            }
+            else
+            {
+                if( defaultstr != null ) 
+                {
+                    res.append( defaultstr );
+                }
+                else
+                {
+                    res.append("There is no page called '"+includedPage+"'.  Would you like to ");
+                    res.append("<a href=\""+context.getContext().getURL( EditActionBean.class, includedPage )+"\">create it?</a>");
+                }
+            }
+        }
+        else
+        {
+            res.append("<span class=\"error\">");
+            res.append("You have to define a page!");
+            res.append("</span>");
+        }
+
+        return res.toString();
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/ListLocksPlugin.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/ListLocksPlugin.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/ListLocksPlugin.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/ListLocksPlugin.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,74 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2003 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package com.ecyrd.jspwiki.plugin;
+
+import com.ecyrd.jspwiki.*;
+import java.util.*;
+
+/**
+ *  This is a plugin for the administrator: It allows him to see in a single
+ *  glance who is editing what.
+ *
+ *  @author Janne Jalkanen
+ *  @since 2.0.22.
+ */
+public class ListLocksPlugin
+    implements WikiPlugin
+{
+    public String execute( WikiContext context, Map params )
+        throws PluginException
+    {
+        StringBuffer result = new StringBuffer();
+
+        PageManager mgr = context.getEngine().getPageManager();
+        List locks = mgr.getActiveLocks();
+
+        result.append("<table class=\"wikitable\">\n");
+        result.append("<tr>\n");
+        result.append("<th>Page</th><th>Locked by</th><th>Acquired</th><th>Expires</th>\n");
+        result.append("</tr>");
+
+        if( locks.size() == 0 )
+        {
+            result.append("<tr><td colspan=\"4\" class=\"odd\">No locks exist currently.</td></tr>\n");
+        }
+        else
+        {
+            int rowNum = 1;
+            for( Iterator i = locks.iterator(); i.hasNext(); )
+            {
+                PageLock lock = (PageLock) i.next();
+
+                result.append( rowNum % 2 != 0 ? "<tr class=\"odd\">" : "<tr>" );
+                result.append("<td>"+lock.getPage()+"</td>");
+                result.append("<td>"+lock.getLocker()+"</td>");
+                result.append("<td>"+lock.getAcquisitionTime()+"</td>");
+                result.append("<td>"+lock.getExpiryTime()+"</td>");
+                result.append("</tr>\n");
+                rowNum++;
+            }
+        }
+
+        result.append("</table>");
+
+        return result.toString();
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/Note.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/Note.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/Note.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/Note.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,92 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2007 JSPWiki Developer Group
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package com.ecyrd.jspwiki.plugin;
+
+import java.util.Map;
+
+import com.ecyrd.jspwiki.TextUtil;
+import com.ecyrd.jspwiki.WikiContext;
+import com.ecyrd.jspwiki.WikiEngine;
+import com.ecyrd.jspwiki.action.NoneActionBean;
+
+/**
+ * Outputs an image with the supplied text as the <tt>title</tt> which is shown as a tooltip by
+ * most browsers. This is intended for short one line comments.
+ * <p>
+ * See http://www.456bereastreet.com/archive/200412/the_alt_and_title_attributes/ for discussion on
+ * alt and title attributes.
+ * <p>
+ * Adaption of the CommentPlugin written by Scott Hulbert, cleaned up and generalized, but basically
+ * his concept.
+ * <p>
+ * 
+ * @author John Volkar
+ * @author Scott Hulbert
+ */
+public class Note implements WikiPlugin
+{
+    public static final String PROP_NOTE_IMAGE    = "notePlugin.imageName";
+    public static final String DEFAULT_NOTE_IMAGE = "note.png";
+
+    public String execute(WikiContext context, Map params) throws PluginException
+    {
+        String commandline = (String) params.get(PluginManager.PARAM_CMDLINE);
+        if (commandline == null || commandline.length() == 0)
+        {
+            return "Unable to obtain plugin command line from parameter'" + PluginManager.PARAM_CMDLINE + "'"; // I18N
+        }
+
+        String commentImage = imageUrl(context);
+
+        String commentText = clean(commandline);
+
+        return "<img src='" + commentImage + "' alt=\"Comment: " + 
+               commentText + "\" title=\"" + commentText + "\"/>";
+    }
+
+    private String imageUrl( WikiContext ctx )
+    {
+        WikiEngine engine = ctx.getEngine();
+        String commentImage = engine.getWikiProperties().getProperty(PROP_NOTE_IMAGE,
+                                                                     DEFAULT_NOTE_IMAGE);
+
+        commentImage = "images/"+commentImage;
+        
+        String resource = engine.getTemplateManager().findResource( ctx, 
+                                                                    engine.getTemplateDir(), 
+                                                                    commentImage );
+
+        return ctx.getContext().getURL( NoneActionBean.class, resource );
+    }
+
+
+    /**
+     *  Cleans the side.
+     * 
+     * @param commandline
+     * @return
+     */
+    private String clean(String commandline)
+    {
+        return TextUtil.replaceEntities( commandline );
+    }
+
+}
+

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/ParserStagePlugin.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/ParserStagePlugin.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/ParserStagePlugin.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/ParserStagePlugin.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,44 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2007 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package com.ecyrd.jspwiki.plugin;
+
+import java.util.Map;
+
+import com.ecyrd.jspwiki.WikiContext;
+import com.ecyrd.jspwiki.parser.PluginContent;
+
+/**
+ *  Implements a Plugin interface for the parser stage.  Please see PluginManager
+ *  for further documentation.
+ * 
+ *  @author jalkanen
+ *  @since 2.5.30
+ */
+public interface ParserStagePlugin
+{
+    /**
+     *  Method which is executed during parsing.
+     *  
+     *  @param element The JDOM element which has already been connected to the Document.
+     *  @param context WikiContext, as usual.
+     *  @param params  Parsed parameters for the plugin.
+     */
+    public void executeParser( PluginContent element, WikiContext context, Map params );
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginException.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginException.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginException.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginException.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,47 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2001 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package com.ecyrd.jspwiki.plugin;
+
+import com.ecyrd.jspwiki.WikiException;
+
+public class PluginException
+    extends WikiException
+{
+    private static final long serialVersionUID = 0L;
+
+    private final Throwable m_throwable;
+
+    public PluginException( String message )
+    {
+        super( message );
+        m_throwable = null;
+    }
+
+    public PluginException( String message, Throwable original )
+    {
+        super( message );
+        m_throwable = original;
+    }
+
+    public Throwable getRootThrowable()
+    {
+        return m_throwable;
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginManager.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginManager.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginManager.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginManager.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,1036 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2001 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package com.ecyrd.jspwiki.plugin;
+
+import java.io.*;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.*;
+
+import org.apache.commons.lang.ClassUtils;
+import org.apache.ecs.xhtml.*;
+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;
+import com.ecyrd.jspwiki.modules.WikiModuleInfo;
+import com.ecyrd.jspwiki.parser.PluginContent;
+import com.ecyrd.jspwiki.util.ClassUtil;
+
+/**
+ *  Manages plugin classes.  There exists a single instance of PluginManager
+ *  per each instance of WikiEngine, that is, each JSPWiki instance.
+ *  <P>
+ *  A plugin is defined to have three parts:
+ *  <OL>
+ *    <li>The plugin class
+ *    <li>The plugin parameters
+ *    <li>The plugin body
+ *  </ol>
+ *
+ *  For example, in the following line of code:
+ *  <pre>
+ *  [{INSERT com.ecyrd.jspwiki.plugin.FunnyPlugin  foo='bar'
+ *  blob='goo'
+ *
+ *  abcdefghijklmnopqrstuvw
+ *  01234567890}]
+ *  </pre>
+ *
+ *  The plugin class is "com.ecyrd.jspwiki.plugin.FunnyPlugin", the
+ *  parameters are "foo" and "blob" (having values "bar" and "goo",
+ *  respectively), and the plugin body is then
+ *  "abcdefghijklmnopqrstuvw\n01234567890".   The plugin body is
+ *  accessible via a special parameter called "_body".
+ *  <p>
+ *  If the parameter "debug" is set to "true" for the plugin,
+ *  JSPWiki will output debugging information directly to the page if there
+ *  is an exception.
+ *  <P>
+ *  The class name can be shortened, and marked without the package.
+ *  For example, "FunnyPlugin" would be expanded to
+ *  "com.ecyrd.jspwiki.plugin.FunnyPlugin" automatically.  It is also
+ *  possible to defined other packages, by setting the
+ *  "jspwiki.plugin.searchPath" property.  See the included
+ *  jspwiki.properties file for examples.
+ *  <P>
+ *  Even though the nominal way of writing the plugin is
+ *  <pre>
+ *  [{INSERT pluginclass WHERE param1=value1...}],
+ *  </pre>
+ *  it is possible to shorten this quite a lot, by skipping the
+ *  INSERT, and WHERE words, and dropping the package name.  For
+ *  example:
+ *
+ *  <pre>
+ *  [{INSERT com.ecyrd.jspwiki.plugin.Counter WHERE name='foo'}]
+ *  </pre>
+ *
+ *  is the same as
+ *  <pre>
+ *  [{Counter name='foo'}]
+ *  </pre>
+ *  <h3>Plugin property files</h3>
+ *  <p>
+ *  Since 2.3.25 you can also define a generic plugin XML properties file per
+ *  each JAR file.
+ *  <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>
+ *  </pre>
+ *  <h3>Plugin lifecycle</h3>
+ *
+ *  <p>Plugin can implement multiple interfaces to let JSPWiki know at which stages they should
+ *  be invoked:
+ *  <ul>
+ *  <li>InitializablePlugin: If your plugin implements this interface, the initialize()-method is
+ *      called once for this class
+ *      before any actual execute() methods are called.  You should use the initialize() for e.g.
+ *      precalculating things.  But notice that this method is really called only once during the
+ *      entire WikiEngine lifetime.  The InitializablePlugin is available from 2.5.30 onwards.</li>
+ *  <li>ParserStagePlugin: If you implement this interface, the executeParse() method is called
+ *      when JSPWiki is forming the DOM tree.  You will receive an incomplete DOM tree, as well
+ *      as the regular parameters.  However, since JSPWiki caches the DOM tree to speed up later
+ *      places, which means that whatever this method returns would be irrelevant.  You can do some DOM
+ *      tree manipulation, though.  The ParserStagePlugin is available from 2.5.30 onwards.</li>
+ *  <li>WikiPlugin: The regular kind of plugin which is executed at every rendering stage.  Each
+ *      new page load is guaranteed to invoke the plugin, unlike with the ParserStagePlugins.</li>
+ *  </ul>
+ *
+ *  @author Janne Jalkanen
+ *  @since 1.6.1
+ */
+public class PluginManager extends ModuleManager
+{
+    private static final String PLUGIN_INSERT_PATTERN = "\\{?(INSERT)?\\s*([\\w\\._]+)[ \\t]*(WHERE)?[ \\t]*";
+
+    private static Logger log = Logger.getLogger( PluginManager.class );
+
+    /**
+     *  This is the default package to try in case the instantiation
+     *  fails.
+     */
+    public static final String DEFAULT_PACKAGE = "com.ecyrd.jspwiki.plugin";
+
+    public 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";
+
+    /**
+     *  The name of the command line content parameter. The value is "_cmdline".
+     */
+    public static final String PARAM_CMDLINE   = "_cmdline";
+
+    /**
+     *  The name of the parameter containing the start and end positions in the
+     *  read stream of the plugin text (stored as a two-element int[], start
+     *  and end resp.).
+     */
+    public static final String PARAM_BOUNDS    = "_bounds";
+
+    /**
+     *  A special name to be used in case you want to see debug output
+     */
+    public static final String PARAM_DEBUG     = "debug";
+
+    private ArrayList<String> m_searchPath = new ArrayList<String>();
+
+    private Pattern m_pluginPattern;
+
+    private boolean m_pluginsEnabled = true;
+
+    /**
+     *  Keeps a list of all known plugin classes.
+     */
+    private Map<String,WikiPluginInfo> m_pluginClassMap = new HashMap<String,WikiPluginInfo>();
+
+
+    /**
+     *  Create a new PluginManager.
+     *
+     *  @param props Contents of a "jspwiki.properties" file.
+     */
+    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();
+
+        //
+        //  The default packages are always added.
+        //
+        m_searchPath.add( DEFAULT_PACKAGE );
+        m_searchPath.add( DEFAULT_FORMS_PACKAGE );
+
+        PatternCompiler compiler = new Perl5Compiler();
+
+        try
+        {
+            m_pluginPattern = compiler.compile( PLUGIN_INSERT_PATTERN );
+        }
+        catch( MalformedPatternException e )
+        {
+            log.fatal("Internal error: someone messed with pluginmanager patterns.", e );
+            throw new InternalWikiException( "PluginManager patterns are broken" );
+        }
+
+    }
+
+    /**
+     * Enables or disables plugin execution.
+     */
+    public void enablePlugins( boolean enabled )
+    {
+        m_pluginsEnabled = enabled;
+    }
+
+    /**
+     * Returns plugin execution status. If false, plugins are not
+     * executed when they are encountered on a WikiPage, and an
+     * empty string is returned in their place.
+     */
+    public boolean pluginsEnabled()
+    {
+        return m_pluginsEnabled;
+    }
+
+    /**
+     *  Returns true if the link is really command to insert
+     *  a plugin.
+     *  <P>
+     *  Currently we just check if the link starts with "{INSERT",
+     *  or just plain "{" but not "{$".
+     *
+     *  @param link Link text, i.e. the contents of text between [].
+     *  @return True, if this link seems to be a command to insert a plugin here.
+     */
+    public static boolean isPluginLink( String link )
+    {
+        return link.startsWith("{INSERT") ||
+               (link.startsWith("{") && !link.startsWith("{$"));
+    }
+
+    /**
+     *  Attempts to locate a plugin class from the class path
+     *  set in the property file.
+     *
+     *  @param classname Either a fully fledged class name, or just
+     *  the name of the file (that is,
+     *  "com.ecyrd.jspwiki.plugin.Counter" or just plain "Counter").
+     *
+     *  @return A found class.
+     *
+     *  @throws ClassNotFoundException if no such class exists.
+     */
+    private Class findPluginClass( String classname )
+        throws ClassNotFoundException
+    {
+        return ClassUtil.findClass( m_searchPath, classname );
+    }
+
+    /**
+     *  Outputs a HTML-formatted version of a stack trace.
+     */
+    private String stackTrace( Map params, Throwable t )
+    {
+        div d = new div();
+        d.setClass("debug");
+        d.addElement("Plugin execution failed, stack trace follows:");
+        StringWriter out = new StringWriter();
+        t.printStackTrace( new PrintWriter(out) );
+        d.addElement( new pre( out.toString() ) );
+        d.addElement( new b( "Parameters to the plugin" ) );
+
+        ul list = new ul();
+        for( Iterator i = params.entrySet().iterator(); i.hasNext(); )
+        {
+            Map.Entry e = (Map.Entry) i.next();
+            String key = (String)e.getKey();
+
+            list.addElement(new li( key+"'='"+e.getValue() ) );
+        }
+
+        d.addElement( list );
+
+        return d.toString();
+    }
+
+    /**
+     *  Executes a plugin class in the given context.
+     *  <P>Used to be private, but is public since 1.9.21.
+     *
+     *  @param context The current WikiContext.
+     *  @param classname The name of the class.  Can also be a
+     *  shortened version without the package name, since the class name is searched from the
+     *  package search path.
+     *
+     *  @param params A parsed map of key-value pairs.
+     *
+     *  @return Whatever the plugin returns.
+     *
+     *  @throws PluginException If the plugin execution failed for
+     *  some reason.
+     *
+     *  @since 2.0
+     */
+    public String execute( WikiContext context,
+                           String classname,
+                           Map params )
+        throws PluginException
+    {
+        if( !m_pluginsEnabled )
+            return "";
+
+        ResourceBundle rb = context.getBundle(WikiPlugin.CORE_PLUGINS_RESOURCEBUNDLE);
+        Object[] args = { classname };
+        try
+        {
+            WikiPlugin plugin;
+
+            boolean debug = TextUtil.isPositive( (String) params.get( PARAM_DEBUG ) );
+
+            WikiPluginInfo pluginInfo = m_pluginClassMap.get(classname);
+
+            if(pluginInfo == null)
+            {
+                pluginInfo = WikiPluginInfo.newInstance(findPluginClass( classname ));
+                registerPlugin(pluginInfo);
+            }
+
+            if( !checkCompatibility(pluginInfo) )
+            {
+                String msg = "Plugin '"+pluginInfo.getName()+"' not compatible with this version of JSPWiki";
+                log.info(msg);
+                return msg;
+            }
+
+            //
+            //   Create...
+            //
+            try
+            {
+                plugin = pluginInfo.newPluginInstance();
+            }
+            catch( InstantiationException e )
+            {
+                throw new PluginException( MessageFormat.format( rb.getString( "plugin.error.cannotinstantiate" ), args ), e );
+            }
+            catch( IllegalAccessException e )
+            {
+                throw new PluginException( MessageFormat.format( rb.getString( "plugin.error.notallowed" ), args ), e );
+            }
+            catch( Exception e )
+            {
+                throw new PluginException( MessageFormat.format( rb.getString( "plugin.error.instantationfailed" ), args), e );
+            }
+
+            //
+            //  ...and launch.
+            //
+            try
+            {
+                return plugin.execute( context, params );
+            }
+            catch( PluginException e )
+            {
+                if( debug )
+                {
+                    return stackTrace( params, e );
+                }
+
+                // Just pass this exception onward.
+                throw (PluginException) e.fillInStackTrace();
+            }
+            catch( Throwable t )
+            {
+                // But all others get captured here.
+                log.info( "Plugin failed while executing:", t );
+                if( debug )
+                {
+                    return stackTrace( params, t );
+                }
+
+                throw new PluginException( rb.getString( "plugin.error.pluginfailed" ), t );
+            }
+
+        }
+        catch( ClassNotFoundException e )
+        {
+            throw new PluginException( MessageFormat.format( rb.getString( "plugin.error.couldnotfind" ), args ), e );
+        }
+        catch( ClassCastException e )
+        {
+            throw new PluginException( MessageFormat.format( rb.getString( "plugin.error.notawikiplugin" ), args ), e );
+        }
+    }
+
+    /**
+     *  Parses plugin arguments.  Handles quotes and all other kewl stuff.
+     *
+     *  <h3>Special parameters</h3>
+     *  The plugin body is put into a special parameter defined by {@link #PARAM_BODY};
+     *  the plugin's command line into a parameter defined by {@link #PARAM_CMDLINE};
+     *  and the bounds of the plugin within the wiki page text by a parameter defined
+     *  by {@link #PARAM_BOUNDS}, whose value is stored as a two-element int[] array,
+     *  i.e., <tt>[start,end]</tt>.
+     *
+     * @param argstring The argument string to the plugin.  This is
+     *  typically a list of key-value pairs, using "'" to escape
+     *  spaces in strings, followed by an empty line and then the
+     *  plugin body.  In case the parameter is null, will return an
+     *  empty parameter list.
+     *
+     * @return A parsed list of parameters.
+     *
+     * @throws IOException If the parsing fails.
+     */
+    public Map<String,Object> parseArgs( String argstring )
+        throws IOException
+    {
+        HashMap<String,Object>arglist = new HashMap<String,Object>();
+
+        //
+        //  Protection against funny users.
+        //
+        if( argstring == null ) return arglist;
+
+        arglist.put( PARAM_CMDLINE, argstring );
+
+        StringReader    in      = new StringReader(argstring);
+        StreamTokenizer tok     = new StreamTokenizer(in);
+        int             type;
+
+
+        String param = null;
+        String value = null;
+
+        tok.eolIsSignificant( true );
+
+        boolean potentialEmptyLine = false;
+        boolean quit               = false;
+
+        while( !quit )
+        {
+            String s;
+
+            type = tok.nextToken();
+
+            switch( type )
+            {
+              case StreamTokenizer.TT_EOF:
+                quit = true;
+                s = null;
+                break;
+
+              case StreamTokenizer.TT_WORD:
+                s = tok.sval;
+                potentialEmptyLine = false;
+                break;
+
+              case StreamTokenizer.TT_EOL:
+                quit = potentialEmptyLine;
+                potentialEmptyLine = true;
+                s = null;
+                break;
+
+              case StreamTokenizer.TT_NUMBER:
+                s = Integer.toString( new Double(tok.nval).intValue() );
+                potentialEmptyLine = false;
+                break;
+
+              case '\'':
+                s = tok.sval;
+                break;
+
+              default:
+                s = null;
+            }
+
+            //
+            //  Assume that alternate words on the line are
+            //  parameter and value, respectively.
+            //
+            if( s != null )
+            {
+                if( param == null )
+                {
+                    param = s;
+                }
+                else
+                {
+                    value = s;
+
+                    arglist.put( param, value );
+
+                    // log.debug("ARG: "+param+"="+value);
+                    param = null;
+                }
+            }
+        }
+
+        //
+        //  Now, we'll check the body.
+        //
+
+        if( potentialEmptyLine )
+        {
+            StringWriter out = new StringWriter();
+            FileUtil.copyContents( in, out );
+
+            String bodyContent = out.toString();
+
+            if( bodyContent != null )
+            {
+                arglist.put( PARAM_BODY, bodyContent );
+            }
+        }
+
+        return arglist;
+    }
+
+    /**
+     *  Parses a plugin.  Plugin commands are of the form:
+     *  [{INSERT myplugin WHERE param1=value1, param2=value2}]
+     *  myplugin may either be a class name or a plugin alias.
+     *  <P>
+     *  This is the main entry point that is used.
+     *
+     *  @param context The current WikiContext.
+     *  @param commandline The full command line, including plugin
+     *  name, parameters and body.
+     *
+     *  @return HTML as returned by the plugin, or possibly an error
+     *  message.
+     */
+    public String execute( WikiContext context,
+                           String commandline )
+        throws PluginException
+    {
+        if( !m_pluginsEnabled )
+            return "";
+
+        ResourceBundle rb = context.getBundle(WikiPlugin.CORE_PLUGINS_RESOURCEBUNDLE);
+        Object[] obArgs = { commandline };
+        PatternMatcher  matcher  = new Perl5Matcher();
+
+        try
+        {
+            if( matcher.contains( commandline, m_pluginPattern ) )
+            {
+                MatchResult res = matcher.getMatch();
+
+                String plugin   = res.group(2);
+                String args     = commandline.substring(res.endOffset(0),
+                                                        commandline.length() -
+                                                        (commandline.charAt(commandline.length()-1) == '}' ? 1 : 0 ) );
+                Map arglist     = parseArgs( args );
+
+                return execute( context, plugin, arglist );
+            }
+        }
+        catch( NoSuchElementException e )
+        {
+            String msg =  "Missing parameter in plugin definition: "+commandline;
+            log.warn( msg, e );
+            throw new PluginException( MessageFormat.format( rb.getString( "plugin.error.missingparameter" ), obArgs ) );
+        }
+        catch( IOException e )
+        {
+            String msg = "Zyrf.  Problems with parsing arguments: "+commandline;
+            log.warn( msg, e );
+            throw new PluginException( MessageFormat.format( rb.getString( "plugin.error.parsingarguments" ), obArgs ) );
+        }
+
+        // FIXME: We could either return an empty string "", or
+        // the original line.  If we want unsuccessful requests
+        // to be invisible, then we should return an empty string.
+        return commandline;
+    }
+
+   public PluginContent parsePluginLine( WikiContext context, String commandline, int pos )
+        throws PluginException
+    {
+        PatternMatcher  matcher  = new Perl5Matcher();
+
+        try
+        {
+            if( matcher.contains( commandline, m_pluginPattern ) )
+            {
+                MatchResult res = matcher.getMatch();
+
+                String plugin   = res.group(2);
+                String args     = commandline.substring(res.endOffset(0),
+                                                        commandline.length() -
+                                                        (commandline.charAt(commandline.length()-1) == '}' ? 1 : 0 ) );
+                Map<String,Object> arglist = parseArgs( args );
+
+                // set wikitext bounds of plugin as '_bounds' parameter, e.g., [345,396]
+                if ( pos != -1 )
+                {
+                    int end = pos + commandline.length() + 2;
+                    int[] bounds = new int[] { pos, end };
+                    arglist.put( PARAM_BOUNDS, bounds );
+                }
+
+                PluginContent result = new PluginContent( plugin, arglist );
+
+                return result;
+            }
+        }
+        catch( ClassCastException e )
+        {
+            log.error( "Invalid type offered in parsing plugin arguments.", e );
+            throw new InternalWikiException("Oops, someone offered !String!");
+        }
+        catch( NoSuchElementException e )
+        {
+            String msg =  "Missing parameter in plugin definition: "+commandline;
+            log.warn( msg, e );
+            throw new PluginException( msg );
+        }
+        catch( IOException e )
+        {
+            String msg = "Zyrf.  Problems with parsing arguments: "+commandline;
+            log.warn( msg, e );
+            throw new PluginException( msg );
+        }
+
+        return null;
+    }
+
+    /**
+     *  Register a plugin.
+     */
+    private void registerPlugin(WikiPluginInfo pluginClass)
+    {
+        String name;
+
+        // Registrar the plugin with the className without the package-part
+        name = pluginClass.getName();
+        if(name != null)
+        {
+            log.debug("Registering plugin [name]: " + name);
+            m_pluginClassMap.put(name, pluginClass);
+        }
+
+        // Registrar the plugin with a short convenient name.
+        name = pluginClass.getAlias();
+        if(name != null)
+        {
+            log.debug("Registering plugin [shortName]: " + name);
+            m_pluginClassMap.put(name, pluginClass);
+        }
+
+        // Registrar the plugin with the className with the package-part
+        name = pluginClass.getClassName();
+        if(name != null)
+        {
+            log.debug("Registering plugin [className]: " + name);
+            m_pluginClassMap.put(name, pluginClass);
+        }
+
+        pluginClass.initializePlugin( m_engine );
+    }
+
+    private void registerPlugins()
+    {
+        log.info( "Registering plugins" );
+
+        SAXBuilder builder = new SAXBuilder();
+
+        try
+        {
+            //
+            // 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 );
+
+            while( resources.hasMoreElements() )
+            {
+                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 );
+        }
+    }
+
+    /**
+     *  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
+         */
+        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 );
+                }
+            }
+        }
+
+        protected void initializeFromXML( Element el )
+        {
+            super.initializeFromXML( el );
+            m_alias = el.getChildText("alias");
+        }
+
+        protected static WikiPluginInfo newInstance( Class clazz )
+        {
+            WikiPluginInfo info = new WikiPluginInfo( clazz.getName() );
+
+            return info;
+        }
+
+        private WikiPluginInfo( String className )
+        {
+            super(className);
+            setClassName( className );
+        }
+
+        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;
+        }
+
+        /**
+         *  Returns the alias name for this object.
+         *  @return An alias name for the plugin.
+         */
+        public String getAlias()
+        {
+            return m_alias;
+        }
+
+        /**
+         *  Creates a new plugin instance.
+         *
+         *  @return A new plugin.
+         *  @throws ClassNotFoundException If the class declared was not found.
+         *  @throws InstantiationException If the class cannot be instantiated-
+         *  @throws IllegalAccessException If the class cannot be accessed.
+         */
+        public WikiPlugin newPluginInstance()
+            throws ClassNotFoundException,
+                   InstantiationException,
+                   IllegalAccessException
+        {
+            if( m_clazz == null )
+            {
+                m_clazz = Class.forName(m_className);
+            }
+
+            return (WikiPlugin) m_clazz.newInstance();
+        }
+
+        /**
+         *  Returns a text for IncludeResources.
+         *
+         *  @param type Either "script" or "stylesheet"
+         *  @return Text, or an empty string, if there is nothing to be included.
+         */
+        public String getIncludeText(String type)
+        {
+            try
+            {
+                if( type.equals("script") )
+                {
+                    return getScriptText();
+                }
+                else if( type.equals("stylesheet") )
+                {
+                    return getStylesheetText();
+                }
+            }
+            catch( Exception ex )
+            {
+                // We want to fail gracefully here
+                return ex.getMessage();
+            }
+
+            return null;
+        }
+
+        private String getScriptText()
+            throws IOException
+        {
+            if( m_scriptText != null )
+            {
+                return m_scriptText;
+            }
+
+            if( m_scriptLocation == null )
+            {
+                return "";
+            }
+
+            try
+            {
+                m_scriptText = getTextResource(m_scriptLocation);
+            }
+            catch( IOException ex )
+            {
+                // Only throw this exception once!
+                m_scriptText = "";
+                throw ex;
+            }
+
+            return m_scriptText;
+        }
+
+        private String getStylesheetText()
+            throws IOException
+        {
+            if( m_stylesheetText != null )
+            {
+                return m_stylesheetText;
+            }
+
+            if( m_stylesheetLocation == null )
+            {
+                return "";
+            }
+
+            try
+            {
+                m_stylesheetText = getTextResource(m_stylesheetLocation);
+            }
+            catch( IOException ex )
+            {
+                // Only throw this exception once!
+                m_stylesheetText = "";
+                throw ex;
+            }
+
+            return m_stylesheetText;
+        }
+
+        /**
+         *  Returns a string suitable for debugging.  Don't assume that the format
+         *  would stay the same.
+         */
+        public String toString()
+        {
+            return "Plugin :[name=" + m_name + "][className=" + m_className + "]";
+        }
+    } // WikiPluginClass
+
+    /**
+     *  {@inheritDoc}
+     */
+    public Collection<WikiModuleInfo> modules()
+    {
+        TreeSet<WikiModuleInfo> ls = new TreeSet<WikiModuleInfo>();
+        
+        for( WikiModuleInfo wmi : m_pluginClassMap.values() )
+        {
+            if( !ls.contains(wmi) ) ls.add(wmi);
+        }
+        
+        return ls;
+    }
+
+    // FIXME: This method needs to be reintegrated with execute() above, since they
+    //        share plenty of code.
+    public void executeParse(PluginContent content, WikiContext context)
+        throws PluginException
+    {
+        if( !m_pluginsEnabled )
+            return;
+
+        ResourceBundle rb = context.getBundle(WikiPlugin.CORE_PLUGINS_RESOURCEBUNDLE);
+        Object[] args = { content.getPluginName() };
+        Map params = content.getParameters();
+        try
+        {
+            WikiPlugin plugin;
+
+            WikiPluginInfo pluginInfo = m_pluginClassMap.get( content.getPluginName() );
+
+            if(pluginInfo == null)
+            {
+                pluginInfo = WikiPluginInfo.newInstance(findPluginClass( content.getPluginName() ));
+                registerPlugin(pluginInfo);
+            }
+
+            if( !checkCompatibility(pluginInfo) )
+            {
+                String msg = "Plugin '"+pluginInfo.getName()+"' not compatible with this version of JSPWiki";
+                log.info(msg);
+                return;
+            }
+
+            plugin = pluginInfo.newPluginInstance();
+
+            if( plugin instanceof ParserStagePlugin )
+            {
+                ((ParserStagePlugin)plugin).executeParser( content, context, params );
+            }
+        }
+        catch( InstantiationException e )
+        {
+            throw new PluginException( MessageFormat.format( rb.getString( "plugin.error.cannotinstantiate" ), args), e );
+        }
+        catch( IllegalAccessException e )
+        {
+            throw new PluginException( MessageFormat.format( rb.getString( "plugin.error.notallowed" ), args), e );
+        }
+        catch( ClassNotFoundException e )
+        {
+            throw new PluginException( MessageFormat.format( rb.getString( "plugin.error.couldnotfind" ), args) );
+        }
+        catch( ClassCastException e )
+        {
+            throw new PluginException( MessageFormat.format( rb.getString( "plugin.error.notawikiplugin" ), args), e );
+        }
+        catch( Exception e )
+        {
+            throw new PluginException( MessageFormat.format( rb.getString( "plugin.error.instantationfailed" ), args), e );
+        }
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginResources.properties
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginResources.properties?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginResources.properties (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginResources.properties Tue Feb 12 21:53:55 2008
@@ -0,0 +1,56 @@
+# This is the English language bundle for JSPWiki core plugins
+# Don&#39;t add your own plugins to this file; create your own bundle, please.
+
+# Common things
+
+# Date format used across JSPWiki.  Please see "SimpleDateFormat" on information
+# how to handle this
+
+common.dateformat = HH:mm:ss dd-MMM-yyyy zzzz
+
+# Errors rendering plugins
+
+plugin.error.insertionfailed = Plugin insertion failed: {0}
+plugin.error.cannotinstantiate = Cannot instantiate plugin {0} 
+plugin.error.notallowed = Not allowed to access plugin {0}
+plugin.error.instantationfailed = Instantiation of plugin {0} failed.
+plugin.error.failed = Plugin failed
+plugin.error.couldnotfind = Could not find plugin {0}
+plugin.error.notawikiplugin = Class {0} is not a Wiki plugin.
+plugin.error.missingparameter = Missing parameter in plugin definition: {0}
+plugin.error.parsingarguments = Zyrf.  Problems with parsing arguments: {0}
+
+# TableOfContents
+tableofcontents.title = Table of Contents
+
+# BugReportHandler
+
+bugreporthandler.new = A new page has been created: {0}
+bugreporthandler.unable = Unable to create a new page!
+bugreporthandler.titlerequired = Title is required!
+
+# CurrentTimePlugin
+
+currenttimeplugin.badformat = You specified a bad format
+
+# WeblogEntryPlugin
+
+weblogentryplugin.newentry = New entry
+
+# ReferringPagesPlugin
+
+# This is in JSPWikiMarkup; {0} is where you put in the number, {1} is an URL
+referringpagesplugin.more = ...and [{0} more|{1}]\\\\
+referringpagesplugin.nobody = ...nobody
+
+# Forms plugins
+formclose.noneedtoshow = (no need to show close now)
+forminput.namemissing = Input element is missing parameter &#39;name&#39;.
+forminput.noneedtoshow = (no need to show input field now)
+formopen.missingparam = The FormOpen element is missing the &#39;{0}&#39; parameter.
+formopen.postorgetonly = Method must be either &#39;post&#39; or &#39;get&#39;
+formopen.noneedtoshow = (no need to show form open now)
+formoutput.missingargument = Argument &#39;{0}&#39; required for Form plugin
+formselect.namemissing = Select element is missing parameter &#39;name&#39;.
+formtextarea.noneedtoshow = (no need to show textarea field now)
+formtextarea.namemissing = Textarea element is missing parameter &#39;name&#39;.
\ No newline at end of file

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginResources_de.properties
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginResources_de.properties?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginResources_de.properties (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/plugin/PluginResources_de.properties Tue Feb 12 21:53:55 2008
@@ -0,0 +1,64 @@
+# This is the English language bundle for JSPWiki core plugins
+# Don't add your own plugins to this file; create your own bundle, please.
+
+# Common things
+
+# Date format used across JSPWiki.  Please see "SimpleDateFormat" on information
+# how to handle this
+
+common.dateformat = HH:mm:ss dd.MMM.yyyy zzzz
+
+# TableOfContents
+tableofcontents.title = Inhaltsverzeichnis
+
+# BugReportHandler
+
+bugreporthandler.new = Es wurde eine neue Seite erstellt: {0}
+bugreporthandler.unable = Erstellen einer neuen Seite nicht möglich!
+bugreporthandler.titlerequired = Titel muss angegeben werden!
+
+# CurrentTimePlugin
+
+currenttimeplugin.badformat = Du hast ein ungültiges Format angegeben
+
+# WeblogEntryPlugin
+
+weblogentryplugin.newentry = Neuer Eintrag
+
+# ReferringPagesPlugin
+
+# This is in JSPWikiMarkup; {0} is where you put in the number, and {1} is a link
+# to the page info with the full list
+referringpagesplugin.more = ...und [{0} mehr|{1}]\\\\
+referringpagesplugin.nobody = ...keine
+
+
+#
+# Diffferenz zwischen 2.5 (BETA) und 2.6 (RC, 16. Dezember 2007)
+# 
+# Die untere Liste wurde mit MissingTransations.java ermittelt.
+#
+# Es ist zu aufwendig, die richtige Reihenfolge rauszufinden,
+# wichtig ist, das es übersetzt wird. Für die richtige Reihenfolge
+# bitte in default.properties nachsehen.
+#
+
+formclose.noneedtoshow = (nicht nötig, form close jetzt anzuzeigen)
+forminput.namemissing = Eingabeelement erwartet Parameter &#39;name&#39;.
+forminput.noneedtoshow = (nicht nötig, Eingabefeld jetzt anzuzeigen)
+formopen.missingparam = Das FormOpen Element erwartet den &#39;{0}&#39; Parameter.
+formopen.noneedtoshow = (nicht nötig, form open jetzt anzuzeigen)
+formopen.postorgetonly = Methode muss entweder &#39;post&#39; oder &#39;get&#39 sein;
+formoutput.missingargument = Argument &#39;{0}&#39; wird im FormPlugin benötigt.
+formselect.namemissing = Select Element erwartet den Parameter &#39;name&#39;.
+formtextarea.namemissing = Textarea Element erwartet den Parameter &#39;name&#39;.
+formtextarea.noneedtoshow = (nicht nötig, Textarea Eingabefeld jetzt anzuzeigen)
+plugin.error.cannotinstantiate = Kann Plugin nicht instanziieren {0} 
+plugin.error.couldnotfind = Kann Plugin nicht finden {0}
+plugin.error.failed = Plugin gescheitert
+plugin.error.insertionfailed = Einfügen von Plugin gescheitert: {0}
+plugin.error.instantationfailed = Instanzierung von Plugin {0} gescheitert.
+plugin.error.missingparameter = Fehlender Parameter in Plugin Definition: {0}
+plugin.error.notallowed = Keine Berechtigung das Plugin zu benutzen {0}
+plugin.error.notawikiplugin = Klasse {0} ist kein Wiki Plugin.
+plugin.error.parsingarguments = Zyrf.  Probleme mit dem parsen von Argumenten: {0}
\ No newline at end of file



Mime
View raw message