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     */
019    package org.apache.wiki.plugin;
020    
021    import java.io.PrintWriter;
022    import java.io.StringWriter;
023    import java.security.Principal;
024    import java.text.MessageFormat;
025    import java.text.SimpleDateFormat;
026    import java.util.*;
027    
028    import org.apache.log4j.Logger;
029    import org.apache.wiki.WikiContext;
030    import org.apache.wiki.WikiEngine;
031    import org.apache.wiki.WikiPage;
032    import org.apache.wiki.api.exceptions.PluginException;
033    import org.apache.wiki.api.exceptions.RedirectException;
034    import org.apache.wiki.api.exceptions.WikiException;
035    import org.apache.wiki.api.plugin.WikiPlugin;
036    import org.apache.wiki.parser.MarkupParser;
037    import org.apache.wiki.preferences.Preferences;
038    
039    /**
040     *  Provides a handler for bug reports.  Still under construction.
041     *
042     *  <p>Parameters : </p>
043     *  <ul>
044     *  <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>
045     *  <li><b>description</b> - description of the bug.</li>
046     *  <li><b>version</b> - version</li>
047     *  <li><b>map</b> - I have no idea </li>
048     *  <li><b>page</b> - The name of the page to be created for this bug report </li>
049     *  </ul>
050     *
051     */
052    public class BugReportHandler
053        implements WikiPlugin
054    {
055        private static Logger log = Logger.getLogger( BugReportHandler.class );
056    
057        /** Parameter name for setting the title.  Value is <tt>{@value}</tt>. */
058        public static final String PARAM_TITLE          = "title";
059        /** Parameter name for setting the description.  Value is <tt>{@value}</tt>. */
060        public static final String PARAM_DESCRIPTION    = "description";
061        /** Parameter name for setting the version.  Value is <tt>{@value}</tt>. */
062        public static final String PARAM_VERSION        = "version";
063        /** Parameter name for setting the map.  Value is <tt>{@value}</tt>. */
064        public static final String PARAM_MAPPINGS       = "map";
065        /** Parameter name for setting the page.  Value is <tt>{@value}</tt>. */
066        public static final String PARAM_PAGE           = "page";
067    
068        private static final String DEFAULT_DATEFORMAT = "dd-MMM-yyyy HH:mm:ss zzz";
069    
070        /**
071         *  {@inheritDoc}
072         */
073        public String execute( WikiContext context, Map<String, String> params )
074            throws PluginException
075        {
076            String    title;
077            String    description;
078            String    version;
079            String    submitter = null;
080            SimpleDateFormat format = new SimpleDateFormat( DEFAULT_DATEFORMAT );
081            ResourceBundle rb = Preferences.getBundle( context, WikiPlugin.CORE_PLUGINS_RESOURCEBUNDLE );
082    
083            title       = params.get( PARAM_TITLE );
084            description = params.get( PARAM_DESCRIPTION );
085            version     = params.get( PARAM_VERSION );
086    
087            Principal wup = context.getCurrentUser();
088    
089            if( wup != null )
090            {
091                submitter = wup.getName();
092            }
093    
094            if( title == null ) throw new PluginException(rb.getString("bugreporthandler.titlerequired"));
095            if( title.length() == 0 ) return "";
096    
097            if( description == null ) description = "";
098            if( version == null ) version = "unknown";
099    
100            Properties mappings = parseMappings( params.get( PARAM_MAPPINGS ) );
101    
102            //
103            //  Start things
104            //
105    
106            try
107            {
108                StringWriter str = new StringWriter();
109                PrintWriter out = new PrintWriter( str );
110    
111                Date d = new Date();
112    
113                //
114                //  Outputting of basic data
115                //
116                out.println("|"+mappings.getProperty(PARAM_TITLE,"Title")+"|"+title);
117                out.println("|"+mappings.getProperty("date","Date")+"|"+format.format(d));
118                out.println("|"+mappings.getProperty(PARAM_VERSION,"Version")+"|"+version);
119                if( submitter != null )
120                {
121                    out.println("|"+mappings.getProperty("submitter","Submitter")+
122                                "|"+submitter);
123                }
124    
125                //
126                //  Outputting the other parameters added to this.
127                //
128                for( Iterator<Map.Entry<String, String>>  i = params.entrySet().iterator(); i.hasNext(); )
129                {
130                    Map.Entry<String, String> entry = i.next();
131    
132                    if( entry.getKey().equals( PARAM_TITLE ) ||
133                        entry.getKey().equals( PARAM_DESCRIPTION ) ||
134                        entry.getKey().equals( PARAM_VERSION ) ||
135                        entry.getKey().equals( PARAM_MAPPINGS ) ||
136                        entry.getKey().equals( PARAM_PAGE ) ||
137                        entry.getKey().startsWith("_") )
138                    {
139                        // Ignore this
140                    }
141                    else
142                    {
143                        //
144                        //  If no mapping has been defined, just ignore
145                        //  it.
146                        //
147                        String head = mappings.getProperty( entry.getKey(), entry.getKey() );
148                        if( head.length() > 0 )
149                        {
150                            out.println("|"+head+
151                                        "|"+entry.getValue());
152                        }
153                    }
154                }
155    
156                out.println();
157                out.println( description );
158    
159                out.close();
160    
161                //
162                //  Now create a new page for this bug report
163                //
164                String pageName = findNextPage( context, title, params.get( PARAM_PAGE ) );
165    
166                WikiPage newPage = new WikiPage( context.getEngine(), pageName );
167                WikiContext newContext = (WikiContext)context.clone();
168                newContext.setPage( newPage );
169    
170                context.getEngine().saveText( newContext,
171                                              str.toString() );
172    
173                MessageFormat formatter = new MessageFormat("");
174                formatter.applyPattern( rb.getString("bugreporthandler.new") );
175                String[] args = { "<a href=\""+context.getViewURL(pageName)+"\">"+pageName+"</a>" };
176    
177                return formatter.format( args );
178            }
179            catch( RedirectException e )
180            {
181                log.info("Saving not allowed, reason: '"+e.getMessage()+"', can't redirect to "+e.getRedirect());
182    
183                throw new PluginException("Saving not allowed, reason: "+e.getMessage());
184            }
185            catch( WikiException e )
186            {
187                log.error("Unable to save page!",e);
188    
189                return rb.getString("bugreporthandler.unable");
190            }
191        }
192    
193        /**
194         *  Finds a free page name for adding the bug report.  Tries to construct a page,
195         *  and if it's found, adds a number to it and tries again.
196         */
197        private synchronized String findNextPage( WikiContext context,
198                                                  String title,
199                                                  String baseName )
200        {
201            String basicPageName = ((baseName != null)?baseName:"Bug")+MarkupParser.cleanLink(title);
202    
203            WikiEngine engine = context.getEngine();
204    
205            String pageName = basicPageName;
206            long   lastbug  = 2;
207    
208            while( engine.pageExists( pageName ) )
209            {
210                pageName = basicPageName + lastbug++;
211            }
212    
213            return pageName;
214        }
215    
216        /**
217         *  Just parses a mappings list in the form of "a=b;b=c;c=d".
218         *  <p>
219         *  FIXME: Should probably be in TextUtil or somewhere.
220         */
221        private Properties parseMappings( String mappings )
222        {
223            Properties props = new Properties();
224    
225            if( mappings == null ) return props;
226    
227            StringTokenizer tok = new StringTokenizer( mappings, ";" );
228    
229            while( tok.hasMoreTokens() )
230            {
231                String t = tok.nextToken();
232    
233                int colon = t.indexOf("=");
234    
235                String key;
236                String value;
237    
238                if( colon > 0 )
239                {
240                    key = t.substring(0,colon);
241                    value = t.substring(colon+1);
242                }
243                else
244                {
245                    key = t;
246                    value = "";
247                }
248    
249                props.setProperty( key, value );
250            }
251    
252            return props;
253        }
254    }