Author: metskem
Date: Sun Aug 30 10:00:37 2009
New Revision: 809290

URL: http://svn.apache.org/viewvc?rev=809290&view=rev
Log:
* 2.8.3-svn-17
                
        * Introduced the new PageViewPlugin written by Andre van Dalen.
        This plugin counts page views and presents the statistics on page views
        See http://www.jspwiki.org/wiki/PageViewPlugin for the complete
        documentation.
        
        * Minor javadoc error in WikiSecurityException
        
        * Commented out log4j logger stmt in jspwiki.properties.tmpl causing 
duplicate
        log entries during tests

Added:
    
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/plugin/PageViewPlugin.java
    
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/com/ecyrd/jspwiki/plugin/PageViewPluginTest.java
Modified:
    incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/ChangeLog
    
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/Release.java
    
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java
    
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/com/ecyrd/jspwiki/plugin/AllTests.java
    
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/etc/jspwiki.properties.tmpl

Modified: incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/ChangeLog
URL: 
http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/ChangeLog?rev=809290&r1=809289&r2=809290&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/ChangeLog (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/ChangeLog Sun Aug 30 10:00:37 
2009
@@ -1,3 +1,17 @@
+2009-08-30 Harry Metske <[email protected]>
+
+        * 2.8.3-svn-17
+                
+        * Introduced the new PageViewPlugin written by Andre van Dalen.
+        This plugin counts page views and presents the statistics on page views
+        See http://www.jspwiki.org/wiki/PageViewPlugin for the complete
+        documentation.
+        
+        * Minor javadoc error in WikiSecurityException
+        
+        * Commented out log4j logger stmt in jspwiki.properties.tmpl causing 
duplicate
+        log entries during tests
+        
 2009-08-30 Dirk Frederickx <[email protected]>
 
         * 2.8.3-svn-16

Modified: 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/Release.java
URL: 
http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/Release.java?rev=809290&r1=809289&r2=809290&view=diff
==============================================================================
--- 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/Release.java
 (original)
+++ 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/Release.java
 Sun Aug 30 10:00:37 2009
@@ -77,7 +77,7 @@
      *  <p>
      *  If the build identifier is empty, it is not added.
      */
-    public static final String     BUILD         = "16";
+    public static final String     BUILD         = "17";
     
     /**
      *  This is the generic version string you should use

Modified: 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java
URL: 
http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java?rev=809290&r1=809289&r2=809290&view=diff
==============================================================================
--- 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java
 (original)
+++ 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java
 Sun Aug 30 10:00:37 2009
@@ -46,7 +46,7 @@
     /**
      *  Constructs an exception with a supplied cause.
      *  @param msg the message to supply to the exception
-     *  @param the cause
+     *  @param cause the cause
      */
     public WikiSecurityException( String msg, Throwable cause )
     {

Added: 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/plugin/PageViewPlugin.java
URL: 
http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/plugin/PageViewPlugin.java?rev=809290&view=auto
==============================================================================
--- 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/plugin/PageViewPlugin.java
 (added)
+++ 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/src/com/ecyrd/jspwiki/plugin/PageViewPlugin.java
 Sun Aug 30 10:00:37 2009
@@ -0,0 +1,809 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.  
+ */
+package com.ecyrd.jspwiki.plugin;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+import java.util.Map.Entry;
+
+import com.ecyrd.jspwiki.ReferenceManager;
+import com.ecyrd.jspwiki.TextUtil;
+import com.ecyrd.jspwiki.WikiContext;
+import com.ecyrd.jspwiki.WikiEngine;
+import com.ecyrd.jspwiki.WikiPage;
+import com.ecyrd.jspwiki.event.WikiEngineEvent;
+import com.ecyrd.jspwiki.event.WikiEvent;
+import com.ecyrd.jspwiki.event.WikiEventListener;
+import com.ecyrd.jspwiki.plugin.InitializablePlugin;
+import com.ecyrd.jspwiki.plugin.PluginException;
+import com.ecyrd.jspwiki.plugin.PluginManager;
+import com.ecyrd.jspwiki.plugin.WikiPlugin;
+import com.ecyrd.jspwiki.util.WikiBackgroundThread;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.apache.oro.text.GlobCompiler;
+import org.apache.oro.text.regex.MalformedPatternException;
+import org.apache.oro.text.regex.Pattern;
+import org.apache.oro.text.regex.PatternCompiler;
+import org.apache.oro.text.regex.PatternMatcher;
+import org.apache.oro.text.regex.Perl5Matcher;
+
+/**
+ * Counts the number of times each page has been viewed. Parameters:
+ * count=yes|no show=none|count|list entries=max number of list entries
+ * min=minimum page count to be listed sort=name|count Default values are
+ * show=none and sort=name.
+ * 
+ * @author Andre van dalen
+ * @since 2.8
+ */
+public class PageViewPlugin extends AbstractReferralPlugin implements 
WikiPlugin, InitializablePlugin
+{
+    private static final Logger log = Logger.getLogger( PageViewPlugin.class );
+
+    /** The page view manager. */
+    private static PageViewManager c_singleton = null;
+
+    /** Constant for the 'count' parameter / value. */
+    private static final String PARAM_COUNT = "count";
+
+    /** Name of the 'entries' parameter. */
+    private static final String PARAM_MAX_ENTRIES = "entries";
+
+    /** Name of the 'max' parameter. */
+    private static final String PARAM_MAX_COUNT = "max";
+
+    /** Name of the 'min' parameter. */
+    private static final String PARAM_MIN_COUNT = "min";
+
+    /** Name of the 'refer' parameter. */
+    private static final String PARAM_REFER = "refer";
+
+    /** Name of the 'sort' parameter. */
+    private static final String PARAM_SORT = "sort";
+
+    /** Constant for the 'none' parameter value. */
+    private static final String STR_NONE = "none";
+
+    /** Constant for the 'list' parameter value. */
+    private static final String STR_LIST = "list";
+
+    /** Constant for the 'yes' parameter value. */
+    private static final String STR_YES = "yes";
+
+    /** Constant for empty string. */
+    private static final String STR_EMPTY = "";
+
+    /** Constant for Wiki markup separator. */
+    private static final String STR_SEPARATOR = "----";
+
+    /** Constant for comma-separated list separator. */
+    private static final String STR_COMMA = ",";
+
+    /** Constant for no-op glob exression. */
+    private static final String STR_GLOBSTAR = "*";
+
+    /** Constant for file storage. */
+    private static final String COUNTER_PAGE = "PageCount.txt";
+
+    /** Constant for storage interval in seconds. */
+    private static final int STORAGE_INTERVAL = 60;
+
+    /**
+     * Initialize the PageViewPlugin and its singleton.
+     * 
+     * @param engine The wiki engine.
+     */
+    public void initialize( WikiEngine engine )
+    {
+
+        log.error( "initializing PageViewPlugin" );
+
+        synchronized( this )
+        {
+            if( c_singleton == null )
+            {
+
+                c_singleton = new PageViewManager(  );
+
+                c_singleton.initialize( engine );
+            }
+        }
+    }
+
+    /**
+     * Cleanup the singleton reference.
+     */
+    private void cleanup()
+    {
+
+        log.error( "cleaning up PageView Manager" );
+
+        c_singleton = null;
+    }
+
+    /**
+     *  {...@inheritdoc}
+     */
+    public String execute( WikiContext context, Map params ) throws 
PluginException
+    {
+
+        PageViewManager manager = c_singleton;
+        String result = STR_EMPTY;
+
+        if( manager != null )
+        {
+
+            result = manager.execute( context, params );
+        }
+
+        return result;
+    }
+
+    /**
+     * Page view manager, handling all storage.
+     */
+    public final class PageViewManager implements WikiEventListener
+    {
+        /** Are we initialized? */
+        private boolean m_initialized = false;
+
+        /** The page counters. */
+        private Map<String, Counter> m_counters = null;
+
+        /** The page counters in storage format. */
+        private Properties m_storage = null;
+
+        /** Are all changes stored? */
+        private boolean m_dirty = false;
+
+        /** The page count storage background thread. */
+        private Thread m_pageCountSaveThread = null;
+
+        /** The work directory. */
+        private String m_workDir = null;
+
+        /** Comparator for descending sort on page count. */
+        private final Comparator<Object> m_compareCountDescending = new 
Comparator<Object>() {
+            public int compare( Object o1, Object o2 )
+            {
+                final int v1 = getCount( o1 );
+                final int v2 = getCount( o2 );
+                return (v1 == v2) ? ((String) o1).compareTo( (String) o2 ) : 
(v1 < v2) ? 1 : -1;
+            }
+        };
+
+        /**
+         * Initialize the page view manager.
+         * 
+         * @param engine The wiki engine.
+         */
+        public synchronized void initialize( WikiEngine engine )
+        {
+
+            log.error( "initializing PageView Manager" );
+
+            m_workDir = engine.getWorkDir();
+
+            engine.addWikiEventListener( this );
+
+            if( m_counters == null )
+            {
+
+                // Load the counters into a collection
+                m_storage = new Properties();
+                m_counters = new TreeMap<String, Counter>();
+
+                loadCounters();
+            }
+
+            // backup counters every 5 minutes
+            if( m_pageCountSaveThread == null )
+            {
+                m_pageCountSaveThread = new CounterSaveThread( engine, 5 * 
STORAGE_INTERVAL, this );
+                m_pageCountSaveThread.start();
+            }
+
+            m_initialized = true;
+
+        }
+
+        /**
+         * Handle the shutdown event via the page counter thread.
+         * 
+         */
+        private synchronized void handleShutdown()
+        {
+
+            log.error( "handleShutdown: The counter store thread was shut 
down." );
+
+            cleanup();
+
+            if( m_counters != null )
+            {
+
+                m_dirty = true;
+                storeCounters();
+
+                m_counters.clear();
+                m_counters = null;
+
+                m_storage.clear();
+                m_storage = null;
+            }
+
+            m_initialized = false;
+
+            m_pageCountSaveThread = null;
+        }
+
+        /**
+         * Inspect wiki events for shutdown.
+         * 
+         * @param event The wiki event to inspect.
+         */
+        public void actionPerformed( WikiEvent event )
+        {
+
+            if( event instanceof WikiEngineEvent )
+            {
+                if( event.getType() == WikiEngineEvent.SHUTDOWN )
+                {
+
+                    log.error( "Detected wiki engine shutdown" );
+                    handleShutdown();
+                }
+            }
+        }
+
+        /**
+         * Count a page hit, present a pages' counter or output a list of
+         * pagecounts.
+         * 
+         * @param context the wiki context
+         * @param params the plugin parameters
+         * @return String Wiki page snippet
+         * @throws PluginException Malformed pattern parameter.
+         */
+        public String execute( WikiContext context, Map params ) throws 
PluginException
+        {
+            WikiEngine engine = context.getEngine();
+            WikiPage page = context.getPage();
+            String result = STR_EMPTY;
+
+            if( page != null )
+            {
+                // get parameters
+                String pagename = page.getName();
+                String count = (String) params.get( PARAM_COUNT );
+                String show = (String) params.get( PARAM_SHOW );
+                int entries = TextUtil.parseIntParameter( (String) params.get( 
PARAM_MAX_ENTRIES ), Integer.MAX_VALUE );
+                final int max = TextUtil.parseIntParameter( (String) 
params.get( PARAM_MAX_COUNT ), Integer.MAX_VALUE );
+                final int min = TextUtil.parseIntParameter( (String) 
params.get( PARAM_MIN_COUNT ), Integer.MIN_VALUE );
+                String sort = (String) params.get( PARAM_SORT );
+                String body = (String) params.get( PluginManager.PARAM_BODY );
+                Pattern[] exclude = compileGlobs( PARAM_EXCLUDE, (String) 
params.get( PARAM_EXCLUDE ) );
+                Pattern[] include = compileGlobs( PARAM_INCLUDE, (String) 
params.get( PARAM_INCLUDE ) );
+                Pattern[] refer = compileGlobs( PARAM_REFER, (String) 
params.get( PARAM_REFER ) );
+                PatternMatcher matcher = (null != exclude || null != include 
|| null != refer) ? new Perl5Matcher() : null;
+                boolean increment = false;
+
+                // increment counter?
+                if( STR_YES.equals( count ) )
+                {
+                    increment = true;
+                }
+                else
+                {
+                    count = null;
+                }
+
+                // default increment counter?
+                if( (show == null || STR_NONE.equals( show )) && count == null 
)
+                {
+                    increment = true;
+                }
+
+                // filter on referring pages?
+                Collection<String> referrers = null;
+
+                if( refer != null )
+                {
+                    ReferenceManager refManager = engine.getReferenceManager();
+
+                    Iterator iter = refManager.findCreated().iterator();
+
+                    while ( iter != null && iter.hasNext() )
+                    {
+
+                        String name = (String) iter.next();
+                        boolean use = false;
+
+                        for( int n = 0; !use && n < refer.length; n++ )
+                        {
+                            use = matcher.matches( name, refer[n] );
+                        }
+
+                        if( use )
+                        {
+                            Collection<String> refs = 
engine.getReferenceManager().findReferrers( name );
+
+                            if( refs != null && !refs.isEmpty() )
+                            {
+                                if( referrers == null )
+                                {
+                                    referrers = new HashSet<String>();
+                                }
+                                referrers.addAll( refs );
+                            }
+                        }
+                    }
+                }
+
+                synchronized( this )
+                {
+                    Counter counter = m_counters.get( pagename );
+
+                    // only count in view mode, keep storage values in sync
+                    if( increment && WikiContext.VIEW.equalsIgnoreCase( 
context.getRequestContext() ) )
+                    {
+                        if( counter == null )
+                        {
+                            counter = new Counter();
+                            m_counters.put( pagename, counter );
+                        }
+                        counter.increment();
+                        m_storage.setProperty( pagename, counter.toString() );
+                        m_dirty = true;
+                    }
+
+                    if( show == null || STR_NONE.equals( show ) )
+                    {
+                        // nothing to show
+
+                    }
+                    else if( PARAM_COUNT.equals( show ) )
+                    {
+                        // show page count
+                        result = counter.toString();
+
+                    }
+                    else if( body != null && 0 < body.length() && 
STR_LIST.equals( show ) )
+                    {
+                        // show list of counts
+                        String header = STR_EMPTY;
+                        String line = body;
+                        String footer = STR_EMPTY;
+                        int start = body.indexOf( STR_SEPARATOR );
+
+                        // split body into header, line, footer on ----
+                        // separator
+                        if( 0 < start )
+                        {
+                            header = body.substring( 0, start );
+
+                            start = skipWhitespace( start + 
STR_SEPARATOR.length(), body );
+
+                            int end = body.indexOf( STR_SEPARATOR, start );
+
+                            if( start >= end )
+                            {
+                                line = body.substring( start );
+
+                            }
+                            else
+                            {
+                                line = body.substring( start, end );
+
+                                end = skipWhitespace( end + 
STR_SEPARATOR.length(), body );
+
+                                footer = body.substring( end );
+                            }
+                        }
+
+                        // sort on name or count?
+                        Map<String, Counter> sorted = m_counters;
+
+                        if( sort != null && PARAM_COUNT.equals( sort ) )
+                        {
+                            sorted = new TreeMap<String, Counter>( 
m_compareCountDescending );
+
+                            sorted.putAll( m_counters );
+                        }
+
+                        // build a messagebuffer with the list in wiki markup
+                        StringBuffer buf = new StringBuffer( header );
+                        MessageFormat fmt = new MessageFormat( line );
+                        Object[] args = new Object[] { pagename, STR_EMPTY, 
STR_EMPTY };
+                        Iterator iter = sorted.entrySet().iterator();
+
+                        while ( iter != null && 0 < entries && iter.hasNext() )
+                        {
+
+                            Entry entry = (Entry) iter.next();
+                            String name = (String) entry.getKey();
+
+                            // check minimum count
+                            final int value = ((Counter) 
entry.getValue()).getValue();
+                            boolean use = min <= value && value <= max;
+
+                            // did we specify a refer-to page?
+                            if( use && referrers != null )
+                            {
+
+                                use = referrers.contains( name );
+                            }
+
+                            // did we specify what pages to include?
+                            if( use && include != null )
+                            {
+                                use = false;
+
+                                for( int n = 0; !use && n < include.length; 
n++ )
+                                {
+
+                                    use = matcher.matches( name, include[n] );
+                                }
+                            }
+
+                            // did we specify what pages to exclude?
+                            if( use && null != exclude )
+                            {
+                                for( int n = 0; use && n < exclude.length; n++ 
)
+                                {
+
+                                    use &= !matcher.matches( name, exclude[n] 
);
+                                }
+                            }
+
+                            if( use )
+                            {
+                                args[1] = engine.beautifyTitle( name );
+                                args[2] = entry.getValue();
+
+                                fmt.format( args, buf, null );
+
+                                entries--;
+                            }
+                        }
+                        buf.append( footer );
+
+                        // let the engine render the list
+                        result = engine.textToHTML( context, buf.toString() );
+                    }
+                }
+            }
+            return result;
+        }
+
+        /**
+         * Compile regexp parameter.
+         * 
+         * @param name The name of the parameter.
+         * @param value The parameter value.
+         * @return Pattern[] The compiled patterns, or <code>null</code>.
+         * @throws PluginException On malformed patterns.
+         */
+        private Pattern[] compileGlobs( String name, String value ) throws 
PluginException
+        {
+
+            Pattern[] result = null;
+
+            if( value != null && 0 < value.length() && !STR_GLOBSTAR.equals( 
value ) )
+            {
+                try
+                {
+                    PatternCompiler pc = new GlobCompiler();
+
+                    String[] ptrns = StringUtils.split( value, STR_COMMA );
+
+                    result = new Pattern[ptrns.length];
+
+                    for( int n = 0; n < ptrns.length; n++ )
+                    {
+                        result[n] = pc.compile( ptrns[n] );
+                    }
+                }
+                catch( MalformedPatternException e )
+                {
+                    throw new PluginException( "Parameter " + name + " has a 
malformed pattern: " + e.getMessage() );
+                }
+            }
+
+            return result;
+        }
+
+        /**
+         * Adjust ofsset skipping whitespace.
+         * 
+         * @param offset The offset in value to adjust.
+         * @param value String in which offset points.
+         * @return int Adjusted offset into value.
+         */
+        private int skipWhitespace( int offset, String value )
+        {
+            while ( Character.isWhitespace( value.charAt( offset ) ) )
+            {
+                offset++;
+            }
+            return offset;
+        }
+
+        /**
+         * Retrieve a page count.
+         * 
+         * @return int The page count for the given key.
+         * @param key the key for the Counter
+         */
+        protected int getCount( Object key )
+        {
+            return m_counters.get( key ).getValue();
+        }
+
+        /**
+         * Load the page view counters from file.
+         */
+        private void loadCounters()
+        {
+            if( m_counters != null && m_storage != null )
+            {
+
+                    log.error( "loadCounters" );
+                synchronized( this )
+                {
+
+                    InputStream fis = null;
+
+                    try
+                    {
+                        fis = new FileInputStream( new File( m_workDir, 
COUNTER_PAGE ) );
+
+                        m_storage.load( fis );
+
+                    }
+                    catch( IOException ioe )
+                    {
+                        log.error( "loadCounters: Can't load page counter 
store: " + ioe.getMessage() + " , will create a new one" );
+
+                    }
+                    finally
+                    {
+                        try
+                        {
+                            if( fis != null )
+                            {
+                                fis.close();
+                            }
+                        }
+                        catch( Exception ignore )
+                        {
+                            /** ignore */
+                        }
+                    }
+
+                    // Copy the collection into a sorted map
+                    Iterator iter = m_storage.entrySet().iterator();
+
+                    while ( iter != null && iter.hasNext() )
+                    {
+                        Entry entry = (Entry) iter.next();
+
+                        m_counters.put( (String) entry.getKey(), new Counter( 
(String) entry.getValue() ) );
+                    }
+
+                
+                        log.error( "loadCounters: counters.size=" + 
m_counters.size() );
+                }
+            }
+        }
+
+        /**
+         * Save the page view counters to file.
+         * 
+         */
+        protected void storeCounters()
+        {
+            if( m_counters != null && m_storage != null && m_dirty )
+            {
+
+       
+                    log.error( "storeCounters: counters.size=" + 
m_counters.size() );
+                synchronized( this )
+                {
+
+                    OutputStream fos = null;
+
+                    // Write out the collection of counters
+                    try
+                    {
+                        fos = new FileOutputStream( new File( m_workDir, 
COUNTER_PAGE ) );
+
+                        m_storage.store( fos, "\n# The number of times each 
page has been viewed.\n# Do not modify.\n" );
+                        fos.flush();
+
+                        m_dirty = false;
+
+                    }
+                    catch( IOException ioe )
+                    {
+                        log.error( "storeCounters: Can't store counters: " + 
ioe.getMessage() );
+
+                    }
+                    finally
+                    {
+                        try
+                        {
+                            if( fos != null )
+                            {
+                                fos.close();
+                            }
+                        }
+                        catch( Exception ignore )
+                        {
+                            /** ignore */
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Is the given thread still current?
+         * 
+         * @return boolean <code>true</code> iff the thread is still the 
current
+         *         background thread.
+         * @param thrd
+         */
+        private synchronized boolean isRunning( Thread thrd )
+        {
+            return m_initialized && thrd == m_pageCountSaveThread;
+        }
+
+    }
+
+    /**
+     * Counter for page hits collection.
+     */
+    private static final class Counter
+    {
+
+        /** The count value. */
+        private int m_count = 0;
+
+        /**
+         * Create a new counter.
+         */
+        public Counter()
+        {
+        }
+
+        /**
+         * Create and initialise a new counter.
+         * 
+         * @param value Count value.
+         */
+        public Counter( String value )
+        {
+
+            setValue( value );
+        }
+
+        /**
+         * Increment counter.
+         */
+        public void increment()
+        {
+            m_count++;
+        }
+
+        /**
+         * Get the count value.
+         * 
+         * @return int
+         */
+        public int getValue()
+        {
+
+            return m_count;
+        }
+
+        /**
+         * Set the count value.
+         * 
+         * @param value String representation of the count.
+         */
+        public void setValue( String value )
+        {
+            try
+            {
+                m_count = Integer.parseInt( value );
+
+            }
+            catch( Exception ignore )
+            {
+                m_count = 0;
+            }
+        }
+
+        /**
+         * @return String String representation of the count.
+         */
+        public String toString()
+        {
+            return String.valueOf( m_count );
+        }
+    }
+
+    /**
+     * Background thread storing the page counters.
+     */
+    static final class CounterSaveThread extends WikiBackgroundThread
+    {
+
+        /** The page view manager. */
+        private final PageViewManager m_manager;
+
+        /**
+         * Create a wiki background thread to store the page counters.
+         * 
+         * @param engine The wiki engine.
+         * @param interval Delay in seconds between saves.
+         * @param pageViewManager
+         */
+        public CounterSaveThread( WikiEngine engine, int interval, 
PageViewManager pageViewManager )
+        {
+
+            super( engine, interval );
+
+            if( pageViewManager == null )
+            {
+                throw new IllegalArgumentException( "Manager cannot be null" );
+            }
+
+            m_manager = pageViewManager;
+        }
+
+        /**
+         * Save the page counters to file.
+         */
+        public void backgroundTask()
+        {
+
+            if( m_manager.isRunning( this ) )
+            {
+                m_manager.storeCounters();
+            }
+        }
+    }
+}

Modified: 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/com/ecyrd/jspwiki/plugin/AllTests.java
URL: 
http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/com/ecyrd/jspwiki/plugin/AllTests.java?rev=809290&r1=809289&r2=809290&view=diff
==============================================================================
--- 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/com/ecyrd/jspwiki/plugin/AllTests.java
 (original)
+++ 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/com/ecyrd/jspwiki/plugin/AllTests.java
 Sun Aug 30 10:00:37 2009
@@ -26,6 +26,7 @@
         suite.addTest( TableOfContentsTest.suite() );
         suite.addTest( UndefinedPagesPluginTest.suite() );
         suite.addTest( RecentChangesPluginTest.suite() );
+        suite.addTest( PageViewPluginTest.suite() );
 
         return suite;
     }

Added: 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/com/ecyrd/jspwiki/plugin/PageViewPluginTest.java
URL: 
http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/com/ecyrd/jspwiki/plugin/PageViewPluginTest.java?rev=809290&view=auto
==============================================================================
--- 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/com/ecyrd/jspwiki/plugin/PageViewPluginTest.java
 (added)
+++ 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/com/ecyrd/jspwiki/plugin/PageViewPluginTest.java
 Sun Aug 30 10:00:37 2009
@@ -0,0 +1,175 @@
+package com.ecyrd.jspwiki.plugin;
+
+import java.util.Properties;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.framework.Test;
+
+import com.ecyrd.jspwiki.TestEngine;
+import com.ecyrd.jspwiki.WikiContext;
+import com.ecyrd.jspwiki.WikiPage;
+
+public class PageViewPluginTest extends TestCase
+
+{
+    Properties props = new Properties();
+
+    TestEngine testEngine;
+
+    WikiContext context;
+
+    PluginManager manager;
+
+    public void setUp() throws Exception
+    {
+        props.load( TestEngine.findTestProperties() );
+
+        testEngine = new TestEngine( props );
+
+        // create pages that should be counted
+        testEngine.saveText( "TestPage01", "this is test page 01 
[{PageViewPlugin}]" );
+        testEngine.saveText( "TestPage02", "this is test page 02 
[{PageViewPlugin}]" );
+
+        manager = new PluginManager( testEngine, props );
+    }
+
+    public void tearDown()
+    {
+        TestEngine.deleteTestPage( "TestPage01" );
+        TestEngine.deleteTestPage( "TestPage02" );
+        TestEngine.deleteTestPage( "PageViews" );
+        TestEngine.emptyWorkDir();
+    }
+
+    public void testShowCountsBasic() throws Exception
+    {
+        WikiPage page1 = testEngine.getPage( "TestPage01" );
+        WikiContext context1 = new WikiContext( testEngine, page1 );
+        WikiPage page2 = testEngine.getPage( "TestPage02" );
+        WikiContext context2 = new WikiContext( testEngine, page2 );
+
+        // generate counts:
+        testEngine.getHTML( context1, page1 );
+        testEngine.getHTML( context2, page2 );
+        testEngine.getHTML( context2, page2 );
+
+        // mind the double \n in the following string:
+        String pageViewPageContent = "[{PageViewPlugin show='list''\n\n* {1} 
({2} views)\n}]";
+        testEngine.saveText( "PageViews", pageViewPageContent );
+
+        WikiPage pageviews = testEngine.getPage( "PageViews" );
+        WikiContext contextPV = new WikiContext( testEngine, pageviews );
+
+        String result = testEngine.getHTML( contextPV, pageviews );
+//        System.out.println( result );
+
+        assertTrue( result.contains( "Test Page 01 (2 views)" ) );
+
+        assertTrue( result.contains( "Test Page 02 (3 views)" ) );
+    }
+
+    public void testShowCountsExclude() throws Exception
+    {
+        testEngine.saveText( "TestPageExcluded", "this is test page that 
should be excluded [{PageViewPlugin}]" );
+
+        WikiPage page1 = testEngine.getPage( "TestPage01" );
+        WikiContext context1 = new WikiContext( testEngine, page1 );
+        WikiPage page2 = testEngine.getPage( "TestPage02" );
+        WikiContext context2 = new WikiContext( testEngine, page2 );
+
+        // generate counts:
+        testEngine.getHTML( context1, page1 );
+        testEngine.getHTML( context2, page2 );
+        testEngine.getHTML( context2, page2 );
+
+        // mind the double \n in the following string:
+        String pageViewPageContent = "[{PageViewPlugin show='list' 
exclude='TestPageExcl*' '\n\n* {1} ({2} views)\n}]";
+        testEngine.saveText( "PageViews", pageViewPageContent );
+
+        WikiPage pageviews = testEngine.getPage( "PageViews" );
+        WikiContext contextPV = new WikiContext( testEngine, pageviews );
+
+        String result = testEngine.getHTML( contextPV, pageviews );
+//        System.out.println( result );
+
+        assertTrue( result.contains( "Test Page 01" ) );
+        
+        // this page should not have been shown:
+        assertFalse( result.contains( "Test Page Excluded" ) );
+
+        TestEngine.deleteTestPage( "TestPageExcluded" );
+    }
+
+    public void testShowCountsSorted() throws Exception
+    {
+        WikiPage page1 = testEngine.getPage( "TestPage01" );
+        WikiContext context1 = new WikiContext( testEngine, page1 );
+        WikiPage page2 = testEngine.getPage( "TestPage02" );
+        WikiContext context2 = new WikiContext( testEngine, page2 );
+
+        // generate counts:
+        testEngine.getHTML( context1, page1 );
+        testEngine.getHTML( context2, page2 );
+        testEngine.getHTML( context2, page2 );
+
+        // mind the double \n in the following string:
+        String pageViewPageContent = "[{PageViewPlugin show='list' sort=count 
'\n\n* {1} ({2} views)\n}]";
+        testEngine.saveText( "PageViews", pageViewPageContent );
+
+        WikiPage pageviews = testEngine.getPage( "PageViews" );
+        WikiContext contextPV = new WikiContext( testEngine, pageviews );
+
+        String result = testEngine.getHTML( contextPV, pageviews );
+//        System.out.println( result );
+
+        int start1 = result.indexOf( "Test Page 01" );
+        int start2 = result.indexOf( "Test Page 02" );
+        
+        // page2 should be showed before page1
+        assertTrue( start2 < start1 );
+    }
+
+    public void testShowCountEntries() throws Exception
+    {
+        // create pages that should be counted
+        testEngine.saveText( "TestPage03", "this is test page 03 
[{PageViewPlugin}]" );
+        testEngine.saveText( "TestPage04", "this is test page 04 
[{PageViewPlugin}]" );
+
+        WikiPage page1 = testEngine.getPage( "TestPage01" );
+        WikiContext context1 = new WikiContext( testEngine, page1 );
+        WikiPage page2 = testEngine.getPage( "TestPage02" );
+        WikiContext context2 = new WikiContext( testEngine, page2 );
+        WikiPage page3 = testEngine.getPage( "TestPage03" );
+        WikiContext context3 = new WikiContext( testEngine, page3 );
+        WikiPage page4 = testEngine.getPage( "TestPage04" );
+        WikiContext context4 = new WikiContext( testEngine, page4 );
+
+        // generate counts:
+        testEngine.getHTML( context1, page1 );
+        testEngine.getHTML( context2, page2 );
+        testEngine.getHTML( context2, page2 );
+        testEngine.getHTML( context3, page3 );
+        testEngine.getHTML( context4, page4 );
+
+        // mind the double \n in the following string:
+        String pageViewPageContent = "[{PageViewPlugin show='list' 
entries=3'\n\n* {1} ({2} views)\n}]";
+        testEngine.saveText( "PageViews", pageViewPageContent );
+
+        WikiPage pageviews = testEngine.getPage( "PageViews" );
+        WikiContext contextPV = new WikiContext( testEngine, pageviews );
+
+        String result = testEngine.getHTML( contextPV, pageviews );
+        System.out.println( result );
+
+        assertTrue( result.contains( "Test Page 03" ) );
+
+        assertFalse( result.contains( "Test Page 04" ) );
+    }
+
+
+    public static Test suite()
+    {
+        return new TestSuite( PageViewPluginTest.class );
+    }
+}

Modified: 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/etc/jspwiki.properties.tmpl
URL: 
http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/etc/jspwiki.properties.tmpl?rev=809290&r1=809289&r2=809290&view=diff
==============================================================================
--- 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/etc/jspwiki.properties.tmpl 
(original)
+++ 
incubator/jspwiki/branches/JSPWIKI_2_8_BRANCH/tests/etc/jspwiki.properties.tmpl 
Sun Aug 30 10:00:37 2009
@@ -120,7 +120,7 @@
 #
 #  Log everything into a file.
 log4j.rootCategory=INFO,FileLog
-log4j.logger.com.ecyrd.jspwiki=INFO, FileLog
+# log4j.logger.com.ecyrd.jspwiki=INFO, FileLog
 log4j.logger.org.mortbay=INFO, TestContainerLog
 log4j.logger.SecurityLog=INFO, SecurityAppender
 


Reply via email to