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();
+ }
+
+
+}