001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.plugin; 020 021import org.apache.log4j.Logger; 022import org.apache.wiki.api.core.Context; 023import org.apache.wiki.api.core.Engine; 024import org.apache.wiki.api.core.Page; 025import org.apache.wiki.api.exceptions.PluginException; 026import org.apache.wiki.api.exceptions.RedirectException; 027import org.apache.wiki.api.exceptions.WikiException; 028import org.apache.wiki.api.plugin.Plugin; 029import org.apache.wiki.api.spi.Wiki; 030import org.apache.wiki.pages.PageManager; 031import org.apache.wiki.parser.MarkupParser; 032import org.apache.wiki.preferences.Preferences; 033 034import java.io.PrintWriter; 035import java.io.StringWriter; 036import java.security.Principal; 037import java.text.MessageFormat; 038import java.text.SimpleDateFormat; 039import java.util.Date; 040import java.util.Map; 041import java.util.Properties; 042import java.util.ResourceBundle; 043import java.util.StringTokenizer; 044 045/** 046 * Provides a handler for bug reports. Still under construction. 047 * 048 * <p>Parameters : </p> 049 * <ul> 050 * <li><b>title</b> - title of the bug, this is required. If it is empty (as in "") it is a signal to the handler to return quietly.</li> 051 * <li><b>description</b> - description of the bug.</li> 052 * <li><b>version</b> - version</li> 053 * <li><b>map</b> - I have no idea </li> 054 * <li><b>page</b> - The name of the page to be created for this bug report </li> 055 * </ul> 056 * 057 */ 058public class BugReportHandler implements Plugin { 059 060 private static final Logger log = Logger.getLogger( BugReportHandler.class ); 061 private static final String DEFAULT_DATEFORMAT = "dd-MMM-yyyy HH:mm:ss zzz"; 062 063 /** Parameter name for setting the title. Value is <tt>{@value}</tt>. */ 064 public static final String PARAM_TITLE = "title"; 065 /** Parameter name for setting the description. Value is <tt>{@value}</tt>. */ 066 public static final String PARAM_DESCRIPTION = "description"; 067 /** Parameter name for setting the version. Value is <tt>{@value}</tt>. */ 068 public static final String PARAM_VERSION = "version"; 069 /** Parameter name for setting the map. Value is <tt>{@value}</tt>. */ 070 public static final String PARAM_MAPPINGS = "map"; 071 /** Parameter name for setting the page. Value is <tt>{@value}</tt>. */ 072 public static final String PARAM_PAGE = "page"; 073 074 /** 075 * {@inheritDoc} 076 */ 077 @Override 078 public String execute( final Context context, final Map< String, String > params ) throws PluginException { 079 final String title = params.get( PARAM_TITLE ); 080 String description = params.get( PARAM_DESCRIPTION ); 081 String version = params.get( PARAM_VERSION ); 082 String submitter = null; 083 final SimpleDateFormat format = new SimpleDateFormat( DEFAULT_DATEFORMAT ); 084 final ResourceBundle rb = Preferences.getBundle( context, Plugin.CORE_PLUGINS_RESOURCEBUNDLE ); 085 final Principal wup = context.getCurrentUser(); 086 087 if( wup != null ) { 088 submitter = wup.getName(); 089 } 090 091 if( title == null ) { 092 throw new PluginException(rb.getString("bugreporthandler.titlerequired")); 093 } 094 if( title.length() == 0 ) { 095 return ""; 096 } 097 098 if( description == null ) { 099 description = ""; 100 } 101 if( version == null ) { 102 version = "unknown"; 103 } 104 105 final Properties mappings = parseMappings( params.get( PARAM_MAPPINGS ) ); 106 107 // Start things 108 try { 109 final StringWriter str = new StringWriter(); 110 final PrintWriter out = new PrintWriter( str ); 111 final Date d = new Date(); 112 113 // Outputting of basic data 114 out.println( "|" + mappings.getProperty(PARAM_TITLE,"Title" ) + "|" + title ); 115 out.println( "|" + mappings.getProperty("date","Date" ) + "|" + format.format( d ) ); 116 out.println( "|" + mappings.getProperty(PARAM_VERSION,"Version" ) + "|" + version ); 117 if( submitter != null ) { 118 out.println("|"+mappings.getProperty("submitter","Submitter") + "|" + submitter ); 119 } 120 121 // Outputting the other parameters added to this. 122 for( final Map.Entry< String, String > entry : params.entrySet() ) { 123 if( !( entry.getKey().equals( PARAM_TITLE ) || 124 entry.getKey().equals( PARAM_DESCRIPTION ) || 125 entry.getKey().equals( PARAM_VERSION ) || 126 entry.getKey().equals( PARAM_MAPPINGS ) || 127 entry.getKey().equals( PARAM_PAGE ) || 128 entry.getKey().startsWith( "_" ) 129 ) ) { 130 // If no mapping has been defined, just ignore it. 131 final String head = mappings.getProperty( entry.getKey(), entry.getKey() ); 132 if( head.length() > 0 ) { 133 out.println( "|" + head + "|" + entry.getValue() ); 134 } 135 } 136 } 137 138 out.println(); 139 out.println( description ); 140 out.close(); 141 142 // Now create a new page for this bug report 143 final String pageName = findNextPage( context, title, params.get( PARAM_PAGE ) ); 144 final Page newPage = Wiki.contents().page( context.getEngine(), pageName ); 145 final Context newContext = context.clone(); 146 newContext.setPage( newPage ); 147 context.getEngine().getManager( PageManager.class ).saveText( newContext, str.toString() ); 148 149 final MessageFormat formatter = new MessageFormat(""); 150 formatter.applyPattern( rb.getString("bugreporthandler.new") ); 151 final String[] args = { "<a href=\""+context.getViewURL(pageName)+"\">"+pageName+"</a>" }; 152 153 return formatter.format( args ); 154 } catch( final RedirectException e ) { 155 log.info("Saving not allowed, reason: '"+e.getMessage()+"', can't redirect to "+e.getRedirect()); 156 throw new PluginException("Saving not allowed, reason: "+e.getMessage()); 157 } catch( final WikiException e ) { 158 log.error( "Unable to save page!", e ); 159 return rb.getString("bugreporthandler.unable" ); 160 } 161 } 162 163 /** 164 * Finds a free page name for adding the bug report. Tries to construct a page, and if it's found, adds a number to it 165 * and tries again. 166 */ 167 private synchronized String findNextPage( final Context context, final String title, final String baseName ) { 168 final String basicPageName = ( ( baseName != null ) ? baseName : "Bug" ) + MarkupParser.cleanLink( title ); 169 final Engine engine = context.getEngine(); 170 171 String pageName = basicPageName; 172 long lastbug = 2; 173 while( engine.getManager( PageManager.class ).wikiPageExists( pageName ) ) { 174 pageName = basicPageName + lastbug++; 175 } 176 177 return pageName; 178 } 179 180 /** 181 * Just parses a mappings list in the form of "a=b;b=c;c=d". 182 * <p> 183 * FIXME: Should probably be in TextUtil or somewhere. 184 */ 185 private Properties parseMappings( final String mappings ) { 186 final Properties props = new Properties(); 187 if( mappings == null ) { 188 return props; 189 } 190 191 final StringTokenizer tok = new StringTokenizer( mappings, ";" ); 192 while( tok.hasMoreTokens() ) { 193 final String t = tok.nextToken(); 194 final int colon = t.indexOf("="); 195 final String key; 196 final String value; 197 198 if( colon > 0 ) { 199 key = t.substring(0,colon); 200 value = t.substring(colon+1); 201 } else { 202 key = t; 203 value = ""; 204 } 205 206 props.setProperty( key, value ); 207 } 208 return props; 209 } 210 211}