You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by aj...@apache.org on 2008/02/13 06:54:24 UTC

svn commit: r627255 [30/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...

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/VersioningFileProvider.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/VersioningFileProvider.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/VersioningFileProvider.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/VersioningFileProvider.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,766 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2001-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.providers;
+
+import java.io.*;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Date;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.log4j.Logger;
+
+import com.ecyrd.jspwiki.*;
+
+/**
+ *  Provides a simple directory based repository for Wiki pages.
+ *  Pages are held in a directory structure:
+ *  <PRE>
+ *    Main.txt
+ *    Foobar.txt
+ *    OLD/
+ *       Main/
+ *          1.txt
+ *          2.txt
+ *          page.properties
+ *       Foobar/
+ *          page.properties
+ *  </PRE>
+ *
+ *  In this case, "Main" has three versions, and "Foobar" just one version.
+ *  <P>
+ *  The properties file contains the necessary metainformation (such as author)
+ *  information of the page.  DO NOT MESS WITH IT!
+ *
+ *  <P>
+ *  All files have ".txt" appended to make life easier for those
+ *  who insist on using Windows or other software which makes assumptions
+ *  on the files contents based on its name.
+ *
+ *  @author Janne Jalkanen
+ */
+public class VersioningFileProvider
+    extends AbstractFileProvider
+    implements VersioningProvider
+{
+    private static final Logger     log = Logger.getLogger(VersioningFileProvider.class);
+   
+    public static final String      PAGEDIR      = "OLD";
+    public static final String      PROPERTYFILE = "page.properties";
+
+    private CachedProperties        m_cachedProperties;
+    
+    public void initialize( WikiEngine engine, Properties properties )
+        throws NoRequiredPropertyException,
+               IOException
+    {
+        super.initialize( engine, properties );
+    }
+
+    /**
+     *  Returns the directory where the old versions of the pages
+     *  are being kept.
+     */
+    private File findOldPageDir( String page )
+    {
+        if( page == null )
+        {
+            throw new InternalWikiException("Page may NOT be null in the provider!");
+        }
+
+        File oldpages = new File( getPageDirectory(), PAGEDIR );
+
+        return new File( oldpages, mangleName(page) );
+    }
+    
+    /**
+     *  Goes through the repository and decides which version is
+     *  the newest one in that directory.
+     *
+     *  @return Latest version number in the repository, or -1, if
+     *          there is no page in the repository.
+     */
+
+    // FIXME: This is relatively slow.
+    /*
+    private int findLatestVersion( String page )
+    {
+        File pageDir = findOldPageDir( page );
+
+        String[] pages = pageDir.list( new WikiFileFilter() );
+
+        if( pages == null )
+        {
+            return -1; // No such thing found.
+        }
+
+        int version = -1;
+
+        for( int i = 0; i < pages.length; i++ )
+        {
+            int cutpoint = pages[i].indexOf( '.' );
+            if( cutpoint > 0 )
+            {
+                String pageNum = pages[i].substring( 0, cutpoint );
+
+                try
+                {
+                    int res = Integer.parseInt( pageNum );
+
+                    if( res > version )
+                    {
+                        version = res;
+                    }
+                }
+                catch( NumberFormatException e ) {} // It's okay to skip these.
+            }
+        }
+
+        return version;
+    }
+*/
+    private int findLatestVersion( String page )
+        throws ProviderException
+    {
+        int version = -1;
+        
+        try
+        {
+            Properties props = getPageProperties( page );
+            
+            for( Iterator i = props.keySet().iterator(); i.hasNext(); )
+            {
+                String key = (String)i.next();
+                
+                if( key.endsWith(".author") )
+                {
+                    int cutpoint = key.indexOf('.');
+                    if( cutpoint > 0 )
+                    {
+                        String pageNum = key.substring(0,cutpoint);
+                        
+                        try
+                        {
+                            int res = Integer.parseInt( pageNum );
+                            
+                            if( res > version )
+                            {
+                                version = res;
+                            }
+                        }
+                        catch( NumberFormatException e ) {} // It's okay to skip these. 
+                    }
+                }
+            }
+        }
+        catch( IOException e )
+        {
+            log.error("Unable to figure out latest version - dying...",e);
+        }
+        
+        return version;
+    }
+
+    /**
+     *  Reads page properties from the file system.
+     */
+    private Properties getPageProperties( String page )
+        throws IOException
+    {
+        File propertyFile = new File( findOldPageDir(page), PROPERTYFILE );
+
+        if( propertyFile.exists() )
+        {
+            long lastModified = propertyFile.lastModified();
+
+            //
+            //   The profiler showed that when calling the history of a page the propertyfile
+            //   was read just as much times as there were versions of that file. The loading
+            //   of a propertyfile is a cpu-intensive jobs. So now hold on to the last propertyfile
+            //   read because the next method will with a high probability ask for the same propertyfile.
+            //   The time it took to show a historypage with 267 versions dropped with 300%. 
+            //
+            
+            CachedProperties cp = m_cachedProperties;
+            
+            if( cp != null 
+                && cp.m_page.equals(page) 
+                && cp.m_lastModified == lastModified)
+            {
+                return cp.m_props;
+            }
+            
+            InputStream in = null;
+            
+            try
+            {
+                in = new BufferedInputStream(new FileInputStream( propertyFile ));
+
+                Properties props = new Properties();
+
+                props.load(in);
+
+                cp = new CachedProperties();
+                cp.m_page = page;
+                cp.m_lastModified = lastModified;
+                cp.m_props = props;
+                
+                m_cachedProperties = cp; // Atomic
+                
+                return props;
+            }
+            finally
+            {
+                if( in != null ) in.close();
+            }
+        }
+        
+        return new Properties(); // Returns an empty object
+    }
+
+    /**
+     *  Writes the page properties back to the file system.
+     *  Note that it WILL overwrite any previous properties.
+     */
+    private void putPageProperties( String page, Properties properties )
+        throws IOException
+    {
+        File propertyFile = new File( findOldPageDir(page), PROPERTYFILE );
+        OutputStream out = null;
+        
+        try
+        {
+            out = new FileOutputStream( propertyFile );
+
+            properties.store( out, " JSPWiki page properties for "+page+". DO NOT MODIFY!" );
+        }
+        finally
+        {
+            if( out != null ) out.close();
+        }
+    }
+
+    /**
+     *  Figures out the real version number of the page and also checks
+     *  for its existence.
+     *
+     *  @throws NoSuchVersionException if there is no such version.
+     */
+    private int realVersion( String page, int requestedVersion )
+        throws NoSuchVersionException,
+               ProviderException
+    {
+        //
+        //  Quickly check for the most common case.
+        //
+        if( requestedVersion == WikiProvider.LATEST_VERSION )
+        {
+            return -1;
+        }
+
+        int latest = findLatestVersion(page);
+
+        if( requestedVersion == latest ||
+            (requestedVersion == 1 && latest == -1 ) )
+        {
+            return -1;
+        }
+        else if( requestedVersion <= 0 || requestedVersion > latest )
+        {
+            throw new NoSuchVersionException("Requested version "+requestedVersion+", but latest is "+latest );
+        }
+
+        return requestedVersion;
+    }
+
+    public synchronized String getPageText( String page, int version )
+        throws ProviderException
+    {
+        File dir = findOldPageDir( page );
+
+        version = realVersion( page, version );
+        if( version == -1 )
+        {
+            // We can let the FileSystemProvider take care
+            // of these requests.
+            return super.getPageText( page, WikiPageProvider.LATEST_VERSION );
+        }
+
+        File pageFile = new File( dir, ""+version+FILE_EXT );
+
+        if( !pageFile.exists() )
+            throw new NoSuchVersionException("Version "+version+"does not exist.");
+        
+        return readFile( pageFile );
+    }
+
+
+    // FIXME: Should this really be here?
+    private String readFile( File pagedata )
+        throws ProviderException
+    {
+        String      result = null;
+        InputStream in     = null;
+
+        if( pagedata.exists() )
+        {
+            if( pagedata.canRead() )
+            {
+                try
+                {          
+                    in = new FileInputStream( pagedata );
+                    result = FileUtil.readContents( in, m_encoding );
+                }
+                catch( IOException e )
+                {
+                    log.error("Failed to read", e);
+                    throw new ProviderException("I/O error: "+e.getMessage());
+                }
+                finally
+                {
+                    try
+                    {
+                        if( in  != null ) in.close();
+                    }
+                    catch( Exception e ) 
+                    {
+                        log.fatal("Closing failed",e);
+                    }
+                }
+            }
+            else
+            {
+                log.warn("Failed to read page from '"+pagedata.getAbsolutePath()+"', possibly a permissions problem");
+                throw new ProviderException("I cannot read the requested page.");
+            }
+        }
+        else
+        {
+            // This is okay.
+            // FIXME: is it?
+            log.info("New page");
+        }
+
+        return result;
+    }
+
+    // FIXME: This method has no rollback whatsoever.
+    
+    /*
+      This is how the page directory should look like:
+
+         version    pagedir       olddir
+          none       empty         empty
+           1         Main.txt (1)  empty
+           2         Main.txt (2)  1.txt
+           3         Main.txt (3)  1.txt, 2.txt
+    */
+    public synchronized void putPageText( WikiPage page, String text )
+        throws ProviderException
+    {
+        //
+        //  This is a bit complicated.  We'll first need to
+        //  copy the old file to be the newest file.
+        //
+
+        File pageDir = findOldPageDir( page.getName() );
+
+        if( !pageDir.exists() )
+        {
+            pageDir.mkdirs();
+        }
+
+        int  latest  = findLatestVersion( page.getName() );
+
+        try
+        {
+            //
+            // Copy old data to safety, if one exists.
+            //
+
+            File oldFile = findPage( page.getName() );
+
+            // Figure out which version should the old page be?
+            // Numbers should always start at 1.
+            // "most recent" = -1 ==> 1
+            // "first"       = 1  ==> 2
+
+            int versionNumber = (latest > 0) ? latest : 1;
+
+            if( oldFile != null && oldFile.exists() )
+            {
+                InputStream in = null;
+                OutputStream out = null;
+                
+                try
+                {
+                    in = new BufferedInputStream( new FileInputStream( oldFile ) );
+                    File pageFile = new File( pageDir, Integer.toString( versionNumber )+FILE_EXT );
+                    out = new BufferedOutputStream( new FileOutputStream( pageFile ) );
+
+                    FileUtil.copyContents( in, out );
+
+                    //
+                    // We need also to set the date, since we rely on this.
+                    //
+                    pageFile.setLastModified( oldFile.lastModified() );
+
+                    //
+                    // Kludge to make the property code to work properly.
+                    //
+                    versionNumber++;
+                }
+                finally
+                {
+                    if( out != null ) out.close();
+                    if( in  != null ) in.close();
+                }
+            }
+
+            //
+            //  Let superclass handler writing data to a new version.
+            //
+
+            super.putPageText( page, text );
+
+            //
+            //  Finally, write page version data.
+            //
+
+            // FIXME: No rollback available.
+            Properties props = getPageProperties( page.getName() );
+
+            props.setProperty( versionNumber+".author", (page.getAuthor() != null) ? page.getAuthor() : "unknown" );
+            
+            String changeNote = (String) page.getAttribute(WikiPage.CHANGENOTE);
+            if( changeNote != null )
+            {
+                props.setProperty( versionNumber+".changenote", changeNote );
+            }
+            
+            putPageProperties( page.getName(), props );
+        }
+        catch( IOException e )
+        {
+            log.error( "Saving failed", e );
+            throw new ProviderException("Could not save page text: "+e.getMessage());
+        }
+    }
+
+    public WikiPage getPageInfo( String page, int version )
+        throws ProviderException
+    {
+        int latest = findLatestVersion(page);
+        int realVersion;
+
+        WikiPage p = null;
+
+        if( version == WikiPageProvider.LATEST_VERSION ||
+            version == latest || 
+            (version == 1 && latest == -1) )
+        {
+            //
+            // Yes, we need to talk to the top level directory
+            // to get this version.
+            //
+            // I am listening to Press Play On Tape's guitar version of
+            // the good old C64 "Wizardry" -tune at this moment.
+            // Oh, the memories...
+            //
+            realVersion = (latest >= 0) ? latest : 1;
+
+            p = super.getPageInfo( page, WikiPageProvider.LATEST_VERSION );
+
+            if( p != null )
+            {
+                p.setVersion( realVersion );
+            }
+        }
+        else
+        {
+            //
+            //  The file is not the most recent, so we'll need to
+            //  find it from the deep trenches of the "OLD" directory
+            //  structure.
+            //
+            realVersion = version;
+            File dir = findOldPageDir( page );
+
+            if( !dir.exists() || !dir.isDirectory() )
+            {
+                return null;
+            }
+
+            File file = new File( dir, version+FILE_EXT );
+
+            if( file.exists() )
+            {
+                p = new WikiPage( m_engine, page );
+
+                p.setLastModified( new Date(file.lastModified()) );
+                p.setVersion( version );
+            }
+        }
+
+        //
+        //  Get author and other metadata information
+        //  (Modification date has already been set.)
+        //
+        if( p != null )
+        {
+            try
+            {
+                Properties props = getPageProperties( page );
+                String author = props.getProperty( realVersion+".author" );
+                if( author != null )
+                {
+                    p.setAuthor( author );
+                }
+                
+                String changenote = props.getProperty( realVersion+".changenote" );
+                if( changenote != null ) p.setAttribute( WikiPage.CHANGENOTE, changenote );
+                
+            }
+            catch( IOException e )
+            {
+                log.error( "Cannot get author for page"+page+": ", e );
+            }
+        }
+
+        return p;
+    }
+
+    public boolean pageExists( String pageName, int version )
+    {
+        File dir = findOldPageDir( pageName );
+
+        if( !dir.exists() || !dir.isDirectory() )
+        {
+            return false;
+        }
+
+        File file = new File( dir, version+FILE_EXT );
+
+        if( file.exists() )
+        {
+            return true;
+        }
+        
+        return false;
+    }
+
+    /**
+     *  FIXME: Does not get user information.
+     */
+    public List getVersionHistory( String page )
+    throws ProviderException
+    {
+        ArrayList list = new ArrayList();
+
+        int latest = findLatestVersion( page );
+
+        // list.add( getPageInfo(page,WikiPageProvider.LATEST_VERSION) );
+        
+        for( int i = latest; i > 0; i-- )
+        {
+            WikiPage info = getPageInfo( page, i );
+
+            if( info != null )
+            {
+                list.add( info );
+            }
+        }
+
+        return list;
+    }
+
+    /**
+     *  Removes the relevant page directory under "OLD" -directory as well,
+     *  but does not remove any extra subdirectories from it.  It will only
+     *  touch those files that it thinks to be WikiPages.
+     */
+    // FIXME: Should log errors.
+    public void deletePage( String page )
+        throws ProviderException
+    {
+        super.deletePage( page );
+
+        File dir = findOldPageDir( page );
+
+        if( dir.exists() && dir.isDirectory() )
+        {
+            File[] files = dir.listFiles( new WikiFileFilter() );
+
+            for( int i = 0; i < files.length; i++ )
+            {
+                files[i].delete();
+            }
+
+            File propfile = new File( dir, PROPERTYFILE );
+
+            if( propfile.exists() )
+            {
+                propfile.delete();
+            }
+
+            dir.delete();
+        }
+    }
+
+    public void deleteVersion( String page, int version )
+        throws ProviderException
+    {
+        File dir = findOldPageDir( page );
+
+        int latest = findLatestVersion( page );
+
+        if( version == WikiPageProvider.LATEST_VERSION ||
+            version == latest || 
+            (version == 1 && latest == -1) )
+        {
+            //
+            //  Delete the properties
+            //
+            try
+            {
+                Properties props = getPageProperties( page );
+                props.remove( ((latest > 0) ? latest : 1)+".author" );
+                putPageProperties( page, props );
+            }
+            catch( IOException e )
+            {
+                log.error("Unable to modify page properties",e);
+                throw new ProviderException("Could not modify page properties");
+            }
+
+            // We can let the FileSystemProvider take care
+            // of the actual deletion
+            super.deleteVersion( page, WikiPageProvider.LATEST_VERSION );
+            
+            //
+            //  Copy the old file to the new location
+            //
+            latest = findLatestVersion( page );
+            
+            File pageDir = findOldPageDir( page );
+            File previousFile = new File( pageDir, Integer.toString(latest)+FILE_EXT );
+
+            InputStream in = null;
+            OutputStream out = null;
+            
+            try
+            {
+                if( previousFile.exists() )
+                {
+                    in = new BufferedInputStream( new FileInputStream( previousFile ) );
+                    File pageFile = findPage(page);
+                    out = new BufferedOutputStream( new FileOutputStream( pageFile ) );
+
+                    FileUtil.copyContents( in, out );
+
+                    //
+                    // We need also to set the date, since we rely on this.
+                    //
+                    pageFile.setLastModified( previousFile.lastModified() );
+                }
+            }
+            catch( IOException e )
+            {
+                log.fatal("Something wrong with the page directory - you may have just lost data!",e);
+            }
+            finally
+            {
+                try
+                {
+                    if( in != null ) in.close();
+                    if( out != null) out.close();
+                }
+                catch( IOException ex )
+                {
+                    log.error("Closing failed",ex);
+                }
+            }
+            
+            return;
+        }
+
+        File pageFile = new File( dir, ""+version+FILE_EXT );
+
+        if( pageFile.exists() )
+        {
+            if( !pageFile.delete() )
+            {
+                log.error("Unable to delete page.");
+            }
+        }
+        else
+        {
+            throw new NoSuchVersionException("Page "+page+", version="+version);
+        }
+    }
+
+    // FIXME: This is kinda slow, we should need to do this only once.
+    public Collection getAllPages() throws ProviderException
+    {
+        Collection pages = super.getAllPages();
+        Collection returnedPages = new ArrayList();
+        
+        for( Iterator i = pages.iterator(); i.hasNext(); )
+        {
+            WikiPage page = (WikiPage) i.next();
+            
+            WikiPage info = getPageInfo( page.getName(), WikiProvider.LATEST_VERSION );
+ 
+            returnedPages.add( info );
+        }
+        
+        return returnedPages;
+    }
+    
+    public String getProviderInfo()
+    {
+        return "";
+    }
+
+    public void movePage( String from,
+                          String to )
+        throws ProviderException
+    {
+        // Move the file itself
+        File fromFile = findPage( from );
+        File toFile = findPage( to );
+        
+        fromFile.renameTo( toFile );
+        
+        // Move any old versions
+        File fromOldDir = findOldPageDir( from );
+        File toOldDir = findOldPageDir( to );
+        
+        fromOldDir.renameTo( toOldDir );
+    }
+    
+    private static class CachedProperties
+    {
+        String m_page;
+        Properties m_props;
+        long m_lastModified;
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/VersioningProvider.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/VersioningProvider.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/VersioningProvider.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/VersioningProvider.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,41 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2001-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.providers;
+
+/**
+ *  This is a provider interface which providers can implement, if they
+ *  support fast checks of versions.
+ *  <p>
+ *  Note that this interface is pretty much a hack to support certain functionality
+ *  before a complete refactoring of the complete provider interface.  Please
+ *  don't bug me too much about it...
+ *  
+ *  @author jalkanen
+ *
+ *  @since 2.3.29
+ */
+public interface VersioningProvider
+{
+    /**
+     *  Return true, if page with a particular version exists.
+     */
+
+    public boolean pageExists( String page, int version );
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/WikiAttachmentProvider.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/WikiAttachmentProvider.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/WikiAttachmentProvider.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/WikiAttachmentProvider.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,181 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2001-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.providers;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+import com.ecyrd.jspwiki.*;
+import com.ecyrd.jspwiki.attachment.Attachment;
+
+/**
+ *  Defines an attachment provider - a class which is capable of saving
+ *  binary data as attachments.
+ *  <P>
+ *  The difference between this class and WikiPageProvider is that there
+ *  PageProviders handle Unicode text, whereas we handle binary data.
+ *  While there are quite a lot of similarities in how we handle
+ *  things, many providers can really use just one.  In addition,
+ *  since binary files can be really large, we rely on
+ *  Input/OutputStreams.
+ *
+ *  @author Erik Bunn
+ *  @author Janne Jalkanen
+ */
+public interface WikiAttachmentProvider
+    extends WikiProvider
+{
+    /**
+     *  Put new attachment data.
+     *  
+     *  @param att Attachment object to add new data to
+     *  @param data The stream from which the provider should read the data
+     *  @throws IOException If writing fails
+     *  @throws ProviderException If there are other errors.
+     */
+    public void putAttachmentData( Attachment att, InputStream data )
+        throws ProviderException,
+               IOException;
+
+    /**
+     *  Get attachment data.
+     *  
+     *  @param att The attachment
+     *  @return An InputStream which you contains the raw data of the object. It's your
+     *          responsibility to close it.
+     *  @throws ProviderException If the attachment cannot be found
+     *  @throws IOException If the attachment cannot be opened
+     */
+
+    public InputStream getAttachmentData( Attachment att )
+        throws ProviderException,
+               IOException;
+
+    /**
+     *  Lists all attachments attached to a page.
+     *
+     *  @param page The page to list the attachments from.
+     *  @return A collection of Attachment objects.  May be empty, but never null.
+     *  @throws ProviderException If something goes wrong when listing the attachments.
+     */
+
+    public Collection<Attachment> listAttachments( WikiPage page )
+        throws ProviderException;
+
+    /**
+     * Finds attachments based on the query.
+     * @param query An array of QueryItem objects to search for
+     * @return A Collection of Attachment objects.  May be empty, but never null.
+     */
+    public Collection findAttachments( QueryItem[] query );
+
+    /**
+     *  Lists changed attachments since given date.  Can also be used to fetch
+     *  a list of all pages.
+     *  <P>
+     *  This is different from WikiPageProvider, where you basically get a list
+     *  of all pages, then sort them locally.  However, since some providers
+     *  can be more efficient in locating recently changed files (like any database) 
+     *  than our non-optimized Java
+     *  code, it makes more sense to fetch the whole list this way.
+     *  <P>
+     *  To get all files, call this with Date(0L);
+     *
+     *  @param timestamp List all files from this date onward.
+     *  @return A List of Attachment objects, in most-recently-changed first order.
+     *  @throws ProviderException If something goes wrong.
+     */
+    public List<Attachment> listAllChanged( Date timestamp )
+        throws ProviderException;
+
+    /**
+     *  Returns info about an attachment.
+     *  
+     *  @param page The parent page
+     *  @param name The name of the attachment
+     *  @param version The version of the attachment (it's okay to use WikiPage.LATEST_VERSION to find the latest one)
+     *  @return An attachment object
+     *  @throws ProviderException If the attachment cannot be found or some other error occurs.
+     */
+    public Attachment getAttachmentInfo( WikiPage page, String name, int version )
+        throws ProviderException;
+
+    /**
+     *  Returns version history.  Each element should be
+     *  an Attachment.
+     *  
+     *  @param att The attachment for which to find the version history for.
+     *  @return A List of Attachment objects.
+     */
+    public List getVersionHistory( Attachment att );
+
+    /**
+     *  Removes a specific version from the repository.  The implementations
+     *  should really do no more security checks, since that is the domain
+     *  of the AttachmentManager.  Just delete it as efficiently as you can.
+     *
+     *  @since 2.0.19.
+     *
+     *  @param att Attachment to be removed.  The version field is checked, and thus
+     *             only that version is removed.
+     *
+     *  @throws ProviderException If the attachment cannot be removed for some reason.
+     */
+
+    public void deleteVersion( Attachment att )
+        throws ProviderException;
+
+    /**
+     *  Removes an entire page from the repository.  The implementations
+     *  should really do no more security checks, since that is the domain
+     *  of the AttachmentManager.  Just delete it as efficiently as you can.  You should also
+     *  delete any auxiliary files and directories that belong to this attachment, 
+     *  IF they were created
+     *  by this provider.
+     *
+     *  @since 2.0.17.
+     *
+     *  @param att Attachment to delete.
+     *
+     *  @throws ProviderException If the page could not be removed for some reason.
+     */
+    public void deleteAttachment( Attachment att )
+        throws ProviderException;
+   
+    /**
+     * Move all the attachments for a given page so that they are attached to a
+     * new page.
+     *
+     * @param oldParent Name of the page we are to move the attachments from.
+     * @param newParent Name of the page we are to move the attachments to.
+     *
+     * @throws ProviderException If the attachments could not be moved for some
+     *                           reason.
+     */
+    public void moveAttachmentsForPage( String oldParent,
+                                        String newParent )
+        throws ProviderException;
+}
+
+

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/WikiPageProvider.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/WikiPageProvider.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/WikiPageProvider.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/providers/WikiPageProvider.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,169 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2001-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.providers;
+
+import java.util.List;
+import java.util.Collection;
+import java.util.Date;
+
+import com.ecyrd.jspwiki.*;
+
+/**
+ *  Each Wiki page provider should implement this interface.
+ *  <P>
+ *  You can build whatever page providers based on this, just
+ *  leave the unused methods do something useful.
+ *  <P>
+ *  WikiPageProvider uses Strings and ints to refer to pages.  This may
+ *  be a bit odd, since WikiAttachmentProviders all use Attachment
+ *  instead of name/version.  We will perhaps modify these in the
+ *  future.  In the mean time, name/version is quite sufficient.
+ *  <P>
+ *  FIXME: In reality we should have an AbstractWikiPageProvider,
+ *  which would provide intelligent backups for subclasses.
+ *
+ *  @author Janne Jalkanen
+ */
+public interface WikiPageProvider
+    extends WikiProvider
+{
+    /**
+     *  Attempts to save the page text for page "page".
+     */
+    public void putPageText( WikiPage page, String text )
+        throws ProviderException;
+
+    /**
+     *  Return true, if page exists.
+     */
+
+    public boolean pageExists( String page );
+
+    /**
+     *  Finds pages based on the query.
+     */
+    public Collection findPages( QueryItem[] query );
+
+    /**
+     *  Returns info about the page.
+     */
+    public WikiPage getPageInfo( String page, int version )
+        throws ProviderException;
+
+    /**
+     *  Returns all pages.  Each element in the returned
+     *  Collection should be a WikiPage.
+     */
+
+    public Collection getAllPages()
+        throws ProviderException;
+
+    /**
+     *  Gets a list of recent changes.
+     *  @since 1.6.4
+     */
+
+    public Collection getAllChangedSince( Date date );
+
+    /**
+     *  Gets the number of pages.
+     *  @since 1.6.4
+     */
+
+    public int getPageCount()
+        throws ProviderException;
+
+    /**
+     *  Returns version history.  Each element should be
+     *  a WikiPage.
+     *
+     *  @return A collection of wiki pages.
+     */
+
+    public List getVersionHistory( String page )
+        throws ProviderException;
+
+    /**
+     *  Gets a specific version out of the repository.
+     *
+     *  @param page Name of the page to fetch.
+     *  @param version Version of the page to fetch.
+     *
+     *  @return The content of the page, or null, if the page does not exist.
+     */
+
+    public String getPageText( String page, int version )
+        throws ProviderException;
+
+    /**
+     *  Removes a specific version from the repository.  The implementations
+     *  should really do no more security checks, since that is the domain
+     *  of the PageManager.  Just delete it as efficiently as you can.
+     *
+     *  @since 2.0.17.
+     *
+     *  @param pageName Name of the page to be removed.
+     *  @param version  Version of the page to be removed.  May be LATEST_VERSION.
+     *
+     *  @throws ProviderException If the page cannot be removed for some reason.
+     */
+
+    public void deleteVersion( String pageName, int version )
+        throws ProviderException;
+
+    /**
+     *  Removes an entire page from the repository.  The implementations
+     *  should really do no more security checks, since that is the domain
+     *  of the PageManager.  Just delete it as efficiently as you can.  You should also
+     *  delete any auxiliary files that belong to this page, IF they were created
+     *  by this provider.
+     *
+     *  <P>The reason why this is named differently from
+     *  deleteVersion() (logically, this method should be an
+     *  overloaded version) is that I want to be absolutely sure I
+     *  don't accidentally use the wrong method.  With overloading
+     *  something like that happens sometimes...
+     *
+     *  @since 2.0.17.
+     *
+     *  @param pageName Name of the page to be removed completely.
+     *
+     *  @throws ProviderException If the page could not be removed for some reason.
+     */
+    public void deletePage( String pageName )
+        throws ProviderException;
+
+     
+     /**
+      * Move a page
+      *
+      * @param from  Name of the page to move.
+      * @param to    New name of the page.
+      *
+      * @throws ProviderException If the page could not be moved for some reason.
+      */
+     public void movePage(String from, String to)
+         throws ProviderException;
+
+}
+
+
+
+

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/CleanTextRenderer.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/CleanTextRenderer.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/CleanTextRenderer.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/CleanTextRenderer.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,83 @@
+/* 
+  JSPWiki - a JSP-based WikiWiki clone.
+
+  Copyright (C) 2001-2006 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.render;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.jdom.JDOMException;
+import org.jdom.Text;
+import org.jdom.xpath.XPath;
+
+import com.ecyrd.jspwiki.WikiContext;
+import com.ecyrd.jspwiki.parser.WikiDocument;
+
+/**
+ *  A simple renderer that just renders all the text() nodes
+ *  from the DOM tree.  This is very useful for cleaning away
+ *  all of the XHTML.
+ *  
+ *  @author Janne Jalkanen
+ *  @since  2.4
+ */
+public class CleanTextRenderer
+    extends WikiRenderer
+{
+    private static final String ALL_TEXT_NODES = "//text()";
+    
+    protected static final Logger log = Logger.getLogger( CleanTextRenderer.class );
+    
+    public CleanTextRenderer( WikiContext context, WikiDocument doc )
+    {
+        super( context, doc );
+    }
+    
+    public String getString()
+        throws IOException
+    {
+        StringBuffer sb = new StringBuffer();
+        
+        try
+        {
+            XPath xp = XPath.newInstance( ALL_TEXT_NODES );
+        
+            List nodes = xp.selectNodes(m_document.getDocument());
+            
+            for( Iterator i = nodes.iterator(); i.hasNext(); )
+            {
+                Object el = i.next();
+                
+                if( el instanceof Text )
+                {
+                    sb.append( ((Text)el).getValue() );
+                }
+            }
+        }
+        catch( JDOMException e )
+        {
+            log.error("Could not parse XPATH expression");
+            throw new IOException( e.getMessage() );
+        }
+    
+        return sb.toString();
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/CreoleRenderer.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/CreoleRenderer.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/CreoleRenderer.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/CreoleRenderer.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,204 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2001-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.render;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.jdom.Content;
+import org.jdom.Element;
+import org.jdom.Text;
+
+import com.ecyrd.jspwiki.WikiContext;
+import com.ecyrd.jspwiki.parser.PluginContent;
+import com.ecyrd.jspwiki.parser.WikiDocument;
+
+/**
+ *  Implements DOM-to-Creole rendering.
+ *  <p>
+ *  FIXME: This class is not yet completely done.
+ *  
+ *  @author Janne Jalkanen
+ */
+public class CreoleRenderer extends WikiRenderer
+{
+    private static final String IMG_START = "{{";
+    private static final String IMG_END = "}}";
+    private static final String PLUGIN_START = "<<";
+    private static final String PLUGIN_END = ">>";
+    private static final String HREF_START = "[[";
+    private static final String HREF_DELIMITER = "|";
+    private static final String HREF_END = "]]";
+    private static final String PRE_START = "{{{";
+    private static final String PRE_END = "}}}";
+    private static final String PLUGIN_IMAGE = "Image";
+    private static final String PARAM_SRC = "src";
+    private static final String HREF_ATTRIBUTE = "href";
+    private static final String ONE_SPACE = " ";
+    private static final String EMPTY_STRING = "";
+    private static final String LINEBREAK = "\n";
+    private static final String LI = "li";
+    private static final String UL = "ul";
+    private static final String OL = "ol";
+    private static final String P  = "p";
+    private static final String A  = "a";
+    private static final String PRE = "pre";
+    
+    /**
+     * Contains element, start markup, end markup
+     */
+    private static final String[] ELEMENTS = {
+       "i" , "//"    , "//",
+       "b" , "**"    , "**",
+       "h2", "== "   , " ==",
+       "h3", "=== "  , " ===",
+       "h4", "==== " , " ====",
+       "hr", "----"  , EMPTY_STRING,
+       "tt", "<<{{>>", "<<}}>>"
+    };
+    
+    private int m_listCount = 0;
+    private char m_listChar = 'x';
+
+    private List m_plugins = new ArrayList();
+
+    public CreoleRenderer( WikiContext ctx, WikiDocument doc )
+    {
+        super( ctx, doc );
+    }
+    
+    /**
+     * Renders an element into the StringBuffer given
+     * @param ce
+     * @param sb
+     */
+    private void renderElement( Element ce, StringBuffer sb )
+    {
+        String endEl = EMPTY_STRING;
+        for( int i = 0; i < ELEMENTS.length; i+=3 )
+        {
+            if( ELEMENTS[i].equals(ce.getName()) )
+            {
+                sb.append( ELEMENTS[i+1] );
+                endEl = ELEMENTS[i+2];
+            }
+        }
+        
+        if( UL.equals(ce.getName()) )
+        {
+            m_listCount++;
+            m_listChar = '*';
+        }
+        else if( OL.equals(ce.getName()) )
+        {
+            m_listCount++;
+            m_listChar = '#';
+        }
+        else if( LI.equals(ce.getName()) )
+        {
+            for(int i = 0; i < m_listCount; i++ ) sb.append( m_listChar );
+            sb.append( ONE_SPACE );
+        }
+        else if( A.equals(ce.getName()) )
+        {
+            String href = ce.getAttributeValue( HREF_ATTRIBUTE );
+            String text = ce.getText();
+            
+            if( href.equals(text) )
+            {
+                sb.append( HREF_START + href + HREF_END );
+            }
+            else
+            {
+                sb.append( HREF_START + href+ HREF_DELIMITER + text +HREF_END);
+            }
+            // Do not render anything else 
+            return;
+        }
+        else if( PRE.equals(ce.getName()) )
+        {
+            sb.append( PRE_START );
+            sb.append( ce.getText() );
+            sb.append( PRE_END );
+            
+            return;
+        }
+        
+        //
+        //  Go through the children
+        //
+        for( Iterator i = ce.getContent().iterator(); i.hasNext(); )
+        {
+            Content c = (Content)i.next();
+            
+            if( c instanceof PluginContent )
+            {
+                PluginContent pc = (PluginContent)c;
+                
+                if( pc.getPluginName().equals( PLUGIN_IMAGE ) )
+                {
+                    sb.append( IMG_START + pc.getParameter( PARAM_SRC ) + IMG_END );
+                }
+                else
+                {
+                    m_plugins.add(pc);
+                    sb.append( PLUGIN_START + pc.getPluginName() + ONE_SPACE + m_plugins.size() + PLUGIN_END );
+                }
+            }
+            else if( c instanceof Text )
+            {
+                sb.append( ((Text)c).getText() );
+            }
+            else if( c instanceof Element )
+            {
+                renderElement( (Element)c, sb );
+            }
+        }
+
+        if( UL.equals( ce.getName() ) || OL.equals( ce.getName() ) )
+        {
+            m_listCount--;
+        }
+        else if( P.equals( ce.getName() ) )
+        {
+            sb.append( LINEBREAK );
+        }
+        
+        sb.append(endEl);
+    }
+    
+    public String getString() throws IOException
+    {
+        StringBuffer sb = new StringBuffer(1000);
+        
+        Element ce = m_document.getRootElement();
+        
+        //
+        //  Traverse through the entire tree of everything.
+        //
+        
+        renderElement( ce, sb );
+        
+        return sb.toString();
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/RenderingManager.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/RenderingManager.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/RenderingManager.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/RenderingManager.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,343 @@
+/*
+  JSPWiki - a JSP-based WikiWiki clone.
+
+  Copyright (C) 2001-2006 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.render;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.lang.reflect.Constructor;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Properties;
+
+import org.apache.log4j.Logger;
+
+import com.ecyrd.jspwiki.TextUtil;
+import com.ecyrd.jspwiki.WikiContext;
+import com.ecyrd.jspwiki.WikiEngine;
+import com.ecyrd.jspwiki.WikiException;
+import com.ecyrd.jspwiki.event.WikiEvent;
+import com.ecyrd.jspwiki.event.WikiEventListener;
+import com.ecyrd.jspwiki.event.WikiEventUtils;
+import com.ecyrd.jspwiki.event.WikiPageEvent;
+import com.ecyrd.jspwiki.modules.InternalModule;
+import com.ecyrd.jspwiki.parser.JSPWikiMarkupParser;
+import com.ecyrd.jspwiki.parser.MarkupParser;
+import com.ecyrd.jspwiki.parser.WikiDocument;
+import com.ecyrd.jspwiki.providers.CachingProvider;
+import com.opensymphony.oscache.base.Cache;
+import com.opensymphony.oscache.base.NeedsRefreshException;
+
+/**
+ *  This class provides a facade towards the differing rendering routines.  You should
+ *  use the routines in this manager instead of the ones in WikiEngine, if you don't
+ *  want the different side effects to occur - such as WikiFilters.
+ *  <p>
+ *  This class also manages a rendering cache, i.e. documents are stored between calls.
+ *  You may control the size of the cache by using the "jspwiki.renderingManager.cacheSize"
+ *  parameter in jspwiki.properties.  The property value is the number of items that
+ *  are stored in the cache.  By default, the value of this parameter is taken from
+ *  the "jspwiki.cachingProvider.cacheSize" parameter (i.e. the rendering cache is
+ *  the same size as the page cache), but you may control them separately.
+ *  <p>
+ *  You can turn caching completely off by stating a cacheSize of zero.
+ *
+ *  @author jalkanen
+ *  @since  2.4
+ */
+public class RenderingManager implements WikiEventListener, InternalModule
+{
+    private static Logger log = Logger.getLogger( RenderingManager.class );
+
+    private              int    m_cacheExpiryPeriod = 24*60*60; // This can be relatively long
+
+    private          WikiEngine m_engine;
+
+    public  static final String PROP_CACHESIZE    = "jspwiki.renderingManager.capacity";
+    private static final int    DEFAULT_CACHESIZE = 1000;
+    private static final String VERSION_DELIMITER = "::";
+    private static final String OSCACHE_ALGORITHM = "com.opensymphony.oscache.base.algorithm.LRUCache";
+    private static final String PROP_RENDERER     = "jspwiki.renderingManager.renderer";
+    public  static final String DEFAULT_RENDERER  = XHTMLRenderer.class.getName();
+
+    /**
+     *  Stores the WikiDocuments that have been cached.
+     */
+    private              Cache  m_documentCache;
+
+    /**
+     *
+     */
+    private         Constructor m_rendererConstructor;
+
+    public static final String WYSIWYG_EDITOR_MODE = "WYSIWYG_EDITOR_MODE";
+
+    public static final String VAR_EXECUTE_PLUGINS = "_PluginContent.execute";
+
+    /**
+     *  Initializes the RenderingManager.
+     *  Checks for cache size settings, initializes the document cache.
+     *  Looks for alternative WikiRenderers, initializes one, or the default
+     *  XHTMLRenderer, for use.
+     *
+     *  @param engine A WikiEngine instance.
+     *  @param properties A list of properties to get parameters from.
+     */
+    public void initialize( WikiEngine engine, Properties properties )
+    throws WikiException
+    {
+        m_engine = engine;
+        int cacheSize = TextUtil.getIntegerProperty( properties, PROP_CACHESIZE, -1 );
+
+        if( cacheSize == -1 )
+        {
+            cacheSize = TextUtil.getIntegerProperty( properties,
+                                                     CachingProvider.PROP_CACHECAPACITY,
+                                                     DEFAULT_CACHESIZE );
+        }
+
+        if( cacheSize > 0 )
+        {
+            m_documentCache = new Cache(true,false,false,false,
+                                        OSCACHE_ALGORITHM,
+                                        cacheSize);
+        }
+        else
+        {
+            log.info( "RenderingManager caching is disabled." );
+        }
+
+        String renderImplName = properties.getProperty( PROP_RENDERER );
+        if( renderImplName == null )
+        {
+            renderImplName = DEFAULT_RENDERER;
+        }
+        Class[] rendererParams = { WikiContext.class, WikiDocument.class };
+        try
+        {
+            Class c = Class.forName( renderImplName );
+            m_rendererConstructor = c.getConstructor( rendererParams );
+        }
+        catch( ClassNotFoundException e )
+        {
+            log.error( "Unable to find WikiRenderer implementation " + renderImplName );
+        }
+        catch( SecurityException e )
+        {
+            log.error( "Unable to access the WikiRenderer(WikiContext,WikiDocument) constructor for "  + renderImplName );
+        }
+        catch( NoSuchMethodException e )
+        {
+            log.error( "Unable to locate the WikiRenderer(WikiContext,WikiDocument) constructor for "  + renderImplName );
+        }
+        if( m_rendererConstructor == null )
+        {
+            throw new WikiException( "Failed to get WikiRenderer '" + renderImplName + "'." );
+        }
+        log.info( "Rendering content with " + renderImplName + "." );
+
+        WikiEventUtils.addWikiEventListener(m_engine, WikiPageEvent.POST_SAVE_BEGIN, this);
+    }
+
+    /**
+     *  Returns the default Parser for this context.
+     *
+     *  @param context the wiki context
+     *  @param pagedata the page data
+     *  @return A MarkupParser instance.
+     */
+    public MarkupParser getParser( WikiContext context, String pagedata )
+    {
+        MarkupParser parser = new JSPWikiMarkupParser( context, new StringReader(pagedata) );
+
+        return parser;
+    }
+
+    /**
+     *  Returns a cached document, if one is found.
+     *
+     * @param context the wiki context
+     * @param pagedata the page data
+     * @return the rendered wiki document
+     * @throws IOException
+     */
+    // FIXME: The cache management policy is not very good: deleted/changed pages
+    //        should be detected better.
+    protected WikiDocument getRenderedDocument( WikiContext context, String pagedata )
+        throws IOException
+    {
+        String pageid = context.getRealPage().getName()+VERSION_DELIMITER+context.getRealPage().getVersion();
+
+        boolean wasUpdated = false;
+
+        if( m_documentCache != null )
+        {
+            try
+            {
+                WikiDocument doc = (WikiDocument) m_documentCache.getFromCache( pageid,
+                                                                                m_cacheExpiryPeriod );
+
+                wasUpdated = true;
+
+                //
+                //  This check is needed in case the different filters have actually
+                //  changed the page data.
+                //  FIXME: Figure out a faster method
+                if( pagedata.equals(doc.getPageData()) )
+                {
+                    if( log.isDebugEnabled() ) log.debug("Using cached HTML for page "+pageid );
+                    return doc;
+                }
+            }
+            catch( NeedsRefreshException e )
+            {
+                if( log.isDebugEnabled() ) log.debug("Re-rendering and storing "+pageid );
+            }
+        }
+
+        //
+        //  Refresh the data content
+        //
+        try
+        {
+            MarkupParser parser = getParser( context, pagedata );
+            WikiDocument doc = parser.parse();
+            doc.setPageData( pagedata );
+            if( m_documentCache != null )
+            {
+                m_documentCache.putInCache( pageid, doc );
+                wasUpdated = true;
+            }
+            return doc;
+        }
+        catch( IOException ex )
+        {
+            log.error("Unable to parse",ex);
+        }
+        finally
+        {
+            if( m_documentCache != null && !wasUpdated ) m_documentCache.cancelUpdate( pageid );
+        }
+
+        return null;
+    }
+
+    /**
+     *  Simply renders a WikiDocument to a String.  This version does not get the document
+     *  from the cache - in fact, it does not cache the document at all.  This is
+     *  very useful, if you have something that you want to render outside the caching
+     *  routines.  Because the cache is based on full pages, and the cache keys are
+     *  based on names, use this routine if you're rendering anything for yourself.
+     *
+     *  @param context The WikiContext to render in
+     *  @param doc A proper WikiDocument
+     *  @return Rendered HTML.
+     *  @throws IOException If the WikiDocument is poorly formed.
+     */
+    public String getHTML( WikiContext context, WikiDocument doc )
+        throws IOException
+    {
+        WikiRenderer rend = getRenderer( context, doc );
+
+        return rend.getString();
+    }
+
+    /**
+     * Returns a WikiRenderer instance, initialized with the given
+     * context and doc. The object is an XHTMLRenderer, unless overridden
+     * in jspwiki.properties with PROP_RENDERER.
+     */
+    public WikiRenderer getRenderer( WikiContext context, WikiDocument doc )
+    {
+        Object[] params = { context, doc };
+        WikiRenderer rval = null;
+
+        try
+        {
+            rval = (WikiRenderer)m_rendererConstructor.newInstance( params );
+        }
+        catch( Exception e )
+        {
+            log.error( "Unable to create WikiRenderer", e );
+        }
+        return rval;
+    }
+
+    /**
+     *   Convinience method for rendering, using the default parser and renderer.  Note that
+     *   you can't use this method to do any arbitrary rendering, as the pagedata MUST
+     *   be the data from the that the WikiContext refers to - this method caches the HTML
+     *   internally, and will return the cached version.  If the pagedata is different
+     *   from what was cached, will re-render and store the pagedata into the internal cache.
+     *
+     *   @param context the wiki context
+     *   @param pagedata the page data
+     *   @return XHTML data.
+     */
+    public String getHTML( WikiContext context, String pagedata )
+    {
+        try
+        {
+            WikiDocument doc = getRenderedDocument( context, pagedata );
+
+            return getHTML( context, doc );
+        }
+        catch( IOException e )
+        {
+            log.error("Unable to parse",e);
+        }
+
+        return null;
+    }
+
+    /**
+     * Flushes the document cache in response to a POST_SAVE_BEGIN event.
+     *
+     * @see com.ecyrd.jspwiki.event.WikiEventListener#actionPerformed(com.ecyrd.jspwiki.event.WikiEvent)
+     */
+    // @SuppressWarnings("deprecation")
+    public void actionPerformed(WikiEvent event)
+    {
+        if( (event instanceof WikiPageEvent) && (event.getType() == WikiPageEvent.POST_SAVE_BEGIN) )
+        {
+            if( m_documentCache != null )
+            {
+                String pageName = ((WikiPageEvent) event).getPageName();
+                m_documentCache.flushPattern( pageName );
+                Collection referringPages = m_engine.getReferenceManager().findReferrers( pageName );
+
+                //
+                //  Flush also those pages that refer to this page (if an nonexistant page
+                //  appears; we need to flush the HTML that refers to the now-existant page
+                //
+                if( referringPages != null )
+                {
+                    Iterator i = referringPages.iterator();
+                    while (i.hasNext())
+                    {
+                        String page = (String) i.next();
+                        if( log.isDebugEnabled() ) log.debug( "Flushing " + page );
+                        m_documentCache.flushPattern( page );
+                    }
+                }
+            }
+        }
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/WikiRenderer.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/WikiRenderer.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/WikiRenderer.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/WikiRenderer.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,71 @@
+/* 
+  JSPWiki - a JSP-based WikiWiki clone.
+
+  Copyright (C) 2001-2006 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.render;
+
+import java.io.IOException;
+
+import com.ecyrd.jspwiki.TextUtil;
+import com.ecyrd.jspwiki.WikiContext;
+import com.ecyrd.jspwiki.WikiEngine;
+import com.ecyrd.jspwiki.parser.MarkupParser;
+import com.ecyrd.jspwiki.parser.WikiDocument;
+
+/**
+ *  Provides an interface to the basic rendering engine.
+ *  This class is an abstract class instead of an interface because
+ *  it is expected that rendering capabilities are increased at some
+ *  point, and I would hate if renderers broke.  This class allows
+ *  some sane defaults to be implemented.
+ *  
+ *  @author jalkanen
+ *  @since  2.4
+ */
+public abstract class WikiRenderer
+{
+    protected WikiContext     m_context;
+    protected WikiDocument    m_document;
+    protected boolean         m_enablePlugins = true;
+    
+    protected WikiRenderer( WikiContext context, WikiDocument doc )
+    {
+        m_context = context;
+        m_document = doc;
+        doc.setContext( context ); // Make sure it is set
+        
+        //
+        //  Do some sane defaults
+        //
+        WikiEngine engine = m_context.getEngine();
+        String runplugins = engine.getVariable( m_context, MarkupParser.PROP_RUNPLUGINS );
+        if( runplugins != null ) enablePlugins( TextUtil.isPositive(runplugins));
+    }
+
+    /**
+     *  Can be used to turn on plugin execution on a translator-reader basis
+     */
+    public void enablePlugins( boolean toggle )
+    {
+        m_enablePlugins = toggle;
+    }
+
+    public abstract String getString()
+        throws IOException;
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/WysiwygEditingRenderer.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/WysiwygEditingRenderer.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/WysiwygEditingRenderer.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/WysiwygEditingRenderer.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,159 @@
+/*
+  JSPWiki - a JSP-based WikiWiki clone.
+
+  Copyright (C) 2001-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.render;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Iterator;
+
+import org.jdom.Attribute;
+import org.jdom.Element;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+
+import com.ecyrd.jspwiki.WikiContext;
+import com.ecyrd.jspwiki.htmltowiki.XHtmlToWikiConfig;
+import com.ecyrd.jspwiki.parser.WikiDocument;
+
+/**
+ *  Implements a WikiRendered that outputs XHTML in a format that is suitable
+ *  for use by a WYSIWYG XHTML editor.
+ *
+ *  @author David Au
+ *  @since  2.5
+ */
+public class WysiwygEditingRenderer
+    extends WikiRenderer
+{
+
+    private static final String A_ELEMENT = "a";
+    private static final String PRE_ELEMENT = "pre";
+    private static final String CLASS_ATTRIBUTE = "class";
+    private static final String HREF_ATTRIBUTE = "href";
+    private static final String TITLE_ATTRIBUTE = "title";
+    private static final String EDITPAGE = "createpage";
+    private static final String WIKIPAGE = "wikipage";
+    private static final String LINEBREAK = "\n";
+    private static final String LINKS_TRANSLATION = "$1#$2";
+    private static final String LINKS_SOURCE = "(.+)#section-.+-(.+)";
+
+    public WysiwygEditingRenderer( WikiContext context, WikiDocument doc )
+    {
+        super( context, doc );
+    }
+
+    /*
+     * Recursively walk the XHTML DOM tree and manipulate specific elements to
+     * make them better for WYSIWYG editing.
+     */
+    private void processChildren(Element baseElement)
+    {
+        for( Iterator itr = baseElement.getChildren().iterator(); itr.hasNext(); )
+        {
+            Object childElement = itr.next();
+            if( childElement instanceof Element )
+            {
+                Element element = (Element)childElement;
+                String elementName = element.getName().toLowerCase();
+                Attribute classAttr = element.getAttribute( CLASS_ATTRIBUTE );
+
+                if( elementName.equals( A_ELEMENT ) )
+                {
+                    if( classAttr != null )
+                    {
+                        String classValue = classAttr.getValue();
+                        Attribute hrefAttr = element.getAttribute( HREF_ATTRIBUTE );
+
+                        XHtmlToWikiConfig wikiConfig = new XHtmlToWikiConfig( m_context );
+
+                        // Get the url for wiki page link - it's typically "Wiki.jsp?page=MyPage"
+                        // or when using the ShortURLConstructor option, it's "wiki/MyPage" .
+                        String wikiPageLinkUrl = wikiConfig.getWikiJspPage();
+                        String editPageLinkUrl = wikiConfig.getEditJspPage();
+
+                        if( classValue.equals( WIKIPAGE )
+                            || ( hrefAttr != null && hrefAttr.getValue().startsWith( wikiPageLinkUrl ) ) )
+                        {
+                            // Remove the leading url string so that users will only see the
+                            // wikipage's name when editing an existing wiki link.
+                            // For example, change "Wiki.jsp?page=MyPage" to just "MyPage".
+                            String newHref = hrefAttr.getValue().substring( wikiPageLinkUrl.length() );
+
+                            // Convert "This%20Pagename%20Has%20Spaces" to "This Pagename Has Spaces"
+                            newHref = m_context.getEngine().decodeName( newHref );
+
+                            // Handle links with section anchors.
+                            // For example, we need to translate the html string "TargetPage#section-TargetPage-Heading2"
+                            // to this wiki string: "TargetPage#Heading2".
+                            hrefAttr.setValue( newHref.replaceFirst( LINKS_SOURCE, LINKS_TRANSLATION ) );
+                        }
+                        else if ( classValue.equals( EDITPAGE )
+                            || ( hrefAttr != null && hrefAttr.getValue().startsWith( editPageLinkUrl ) ) )
+                        {
+                            Attribute titleAttr = element.getAttribute( TITLE_ATTRIBUTE );
+                            if( titleAttr != null )
+                            {
+                                // remove the title since we don't want to eventually save the default undefined page title.
+                                titleAttr.detach();
+                            }
+
+                            String newHref = hrefAttr.getValue().substring( editPageLinkUrl.length() );
+                            newHref = m_context.getEngine().decodeName( newHref );
+
+                            hrefAttr.setValue( newHref );
+                        }
+                    }
+                } // end of check for "a" element
+                else if( elementName.equals( PRE_ELEMENT ) )
+                {
+                    // We need to trim the surrounding whitespace to accomodate a FCK bug: when the first line
+                    // of a <pre> tag contains only whitespace, then all the linebreaks in the <pre>
+                    // tag will be lost due to FCK's html tidying.
+                    String text = element.getTextTrim();
+                    element.setText( text );
+                }
+
+                processChildren( element );
+            }
+        }
+    }
+
+    public String getString()
+        throws IOException
+    {
+        Element rootElement = m_document.getRootElement();
+        processChildren( rootElement );
+
+        m_document.setContext( m_context );
+
+        XMLOutputter output = new XMLOutputter();
+
+        StringWriter out = new StringWriter();
+
+        Format fmt = Format.getRawFormat();
+        fmt.setExpandEmptyElements( false );
+        fmt.setLineSeparator( LINEBREAK );
+
+        output.setFormat( fmt );
+        output.outputElementContent( m_document.getRootElement(), out );
+
+        return out.toString();
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/XHTMLRenderer.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/XHTMLRenderer.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/XHTMLRenderer.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/render/XHTMLRenderer.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,67 @@
+/* 
+  JSPWiki - a JSP-based WikiWiki clone.
+
+  Copyright (C) 2001-2006 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.render;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+
+import com.ecyrd.jspwiki.WikiContext;
+import com.ecyrd.jspwiki.parser.WikiDocument;
+
+/**
+ *  Implements a WikiRendered that outputs XHTML.  Because the internal DOM
+ *  representation is in XHTML already, this just basically dumps out everything
+ *  out in a non-prettyprinted format.
+ *   
+ *  @author jalkanen
+ *  @since  2.4
+ */
+public class XHTMLRenderer
+    extends WikiRenderer 
+{
+    private static final String LINEBREAK = "\n";
+
+    public XHTMLRenderer( WikiContext context, WikiDocument doc )
+    {
+        super( context, doc );
+    }
+    
+    public String getString()
+        throws IOException
+    {
+        m_document.setContext( m_context );
+
+        XMLOutputter output = new XMLOutputter();
+        
+        StringWriter out = new StringWriter();
+        
+        Format fmt = Format.getRawFormat();
+        fmt.setExpandEmptyElements( false );
+        fmt.setLineSeparator( LINEBREAK );
+
+        output.setFormat( fmt );
+        output.outputElementContent( m_document.getRootElement(), out );
+        
+        return out.toString();
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/rpc/RPCCallable.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/rpc/RPCCallable.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/rpc/RPCCallable.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/rpc/RPCCallable.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,30 @@
+/* 
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2001-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.rpc;
+
+/**
+ *  Defines an interface for anything which can be called using the RPC methods.
+ *  @author Janne Jalkanen
+ *  @since  2.5.4
+ */
+public interface RPCCallable
+{
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/rpc/RPCManager.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/rpc/RPCManager.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/rpc/RPCManager.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/rpc/RPCManager.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,48 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2001-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.rpc;
+
+/**
+ *  A base class for managing RPC calls.
+ *  
+ *  @author jalkanen
+ *  @since 2.5.4
+ */
+public class RPCManager
+{
+    
+    /**
+     *  Gets an unique RPC ID for a callable object.  This is required because a plugin
+     *  does not know how many times it is already been invoked.
+     *  <p>
+     *  The id returned contains only upper and lower ASCII characters and digits, and
+     *  it always starts with an ASCII character.  Therefore the id is suitable as a
+     *  programming language construct directly (e.g. object name).
+     *  
+     *  @param c An RPCCallable
+     *  @return An unique id for the callable.
+     */
+    public static String getId( RPCCallable c )
+    {
+        return "RPC"+c.hashCode();
+    }
+    
+
+}