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;
020
021import java.security.Permission;
022import java.security.Principal;
023import java.util.HashMap;
024
025import javax.servlet.http.HttpServletRequest;
026import javax.servlet.http.HttpSession;
027import javax.servlet.jsp.PageContext;
028
029import org.apache.log4j.Logger;
030import org.apache.wiki.auth.NoSuchPrincipalException;
031import org.apache.wiki.auth.UserManager;
032import org.apache.wiki.auth.WikiPrincipal;
033import org.apache.wiki.auth.permissions.AllPermission;
034import org.apache.wiki.auth.user.UserDatabase;
035import org.apache.wiki.tags.WikiTagBase;
036import org.apache.wiki.ui.Command;
037import org.apache.wiki.ui.CommandResolver;
038import org.apache.wiki.ui.GroupCommand;
039import org.apache.wiki.ui.Installer;
040import org.apache.wiki.ui.PageCommand;
041import org.apache.wiki.ui.WikiCommand;
042import org.apache.wiki.util.TextUtil;
043
044/**
045 *  <p>Provides state information throughout the processing of a page.  A
046 *  WikiContext is born when the JSP pages that are the main entry
047 *  points, are invoked.  The JSPWiki engine creates the new
048 *  WikiContext, which basically holds information about the page, the
049 *  handling engine, and in which context (view, edit, etc) the
050 *  call was done.</p>
051 *  <p>A WikiContext also provides request-specific variables, which can
052 *  be used to communicate between plugins on the same page, or
053 *  between different instances of the same plugin.  A WikiContext
054 *  variable is valid until the processing of the page has ended.  For
055 *  an example, please see the Counter plugin.</p>
056 *  <p>When a WikiContext is created, it automatically associates a
057 *  {@link WikiSession} object with the user's HttpSession. The
058 *  WikiSession contains information about the user's authentication
059 *  status, and is consulted by {@link #getCurrentUser()}.
060 *  object</p>
061 *  <p>Do not cache the page object that you get from the WikiContext; always
062 *  use getPage()!</p>
063 *
064 *  @see org.apache.wiki.plugin.Counter
065 *
066 */
067public class WikiContext
068    implements Cloneable, Command
069{
070    private    Command m_command = null;
071
072    private    WikiPage   m_page;
073    private    WikiPage   m_realPage;
074    private    WikiEngine m_engine;
075    private    String     m_template = "default";
076
077    private    HashMap<String,Object> m_variableMap = new HashMap<String,Object>();
078
079    /**
080     *  Stores the HttpServletRequest.  May be null, if the request did not
081     *  come from a servlet.
082     */
083    protected  HttpServletRequest m_request = null;
084
085    private    WikiSession m_session = null;
086
087    /** User is administering JSPWiki (Install, SecurityConfig). */
088    public static final String    INSTALL  = WikiCommand.INSTALL.getRequestContext();
089
090    /** The VIEW context - the user just wants to view the page
091        contents. */
092    public static final String    VIEW     = PageCommand.VIEW.getRequestContext();
093
094    /** User wants to view or administer workflows. */
095    public static final String    WORKFLOW = WikiCommand.WORKFLOW.getRequestContext();
096
097    /** The EDIT context - the user is editing the page. */
098    public static final String    EDIT     = PageCommand.EDIT.getRequestContext();
099
100    /** User is preparing for a login/authentication. */
101    public static final String    LOGIN    = WikiCommand.LOGIN.getRequestContext();
102
103    /** User is preparing to log out. */
104    public static final String    LOGOUT   = WikiCommand.LOGOUT.getRequestContext();
105
106    /** JSPWiki wants to display a message. */
107    public static final String    MESSAGE  = WikiCommand.MESSAGE.getRequestContext();
108
109    /** User is viewing a DIFF between the two versions of the page. */
110    public static final String    DIFF     = PageCommand.DIFF.getRequestContext();
111
112    /** User is viewing page history. */
113    public static final String    INFO     = PageCommand.INFO.getRequestContext();
114
115    /** User is previewing the changes he just made. */
116    public static final String    PREVIEW  = PageCommand.PREVIEW.getRequestContext();
117
118    /** User has an internal conflict, and does quite not know what to
119        do. Please provide some counseling. */
120    public static final String    CONFLICT = PageCommand.CONFLICT.getRequestContext();
121
122    /** An error has been encountered and the user needs to be informed. */
123    public static final String    ERROR    = WikiCommand.ERROR.getRequestContext();
124
125    /** User is uploading something. */
126    public static final String    UPLOAD   = PageCommand.UPLOAD.getRequestContext();
127
128    /** User is commenting something. */
129    public static final String    COMMENT  = PageCommand.COMMENT.getRequestContext();
130
131    /** User is searching for content. */
132    public static final String    FIND     = WikiCommand.FIND.getRequestContext();
133
134    /** User wishes to create a new group */
135    public static final String    CREATE_GROUP = WikiCommand.CREATE_GROUP.getRequestContext();
136
137    /** User is deleting an existing group. */
138    public static final String    DELETE_GROUP = GroupCommand.DELETE_GROUP.getRequestContext();
139
140    /** User is editing an existing group. */
141    public static final String    EDIT_GROUP = GroupCommand.EDIT_GROUP.getRequestContext();
142
143    /** User is viewing an existing group */
144    public static final String    VIEW_GROUP = GroupCommand.VIEW_GROUP.getRequestContext();
145
146    /** User is editing preferences */
147    public static final String    PREFS    = WikiCommand.PREFS.getRequestContext();
148
149    /** User is renaming a page. */
150    public static final String    RENAME   = PageCommand.RENAME.getRequestContext();
151
152    /** User is deleting a page or an attachment. */
153    public static final String    DELETE   = PageCommand.DELETE.getRequestContext();
154
155    /** User is downloading an attachment. */
156    public static final String    ATTACH   = PageCommand.ATTACH.getRequestContext();
157
158    /** RSS feed is being generated. */
159    public static final String    RSS      = PageCommand.RSS.getRequestContext();
160
161    /** This is not a JSPWiki context, use it to access static files. */
162    public static final String    NONE     = PageCommand.NONE.getRequestContext();
163
164    /** Same as NONE; this is just a clarification. */
165    public static final String    OTHER    = PageCommand.OTHER.getRequestContext();
166
167    /** User is doing administrative things. */
168    public static final String    ADMIN    = WikiCommand.ADMIN.getRequestContext();
169
170    private static final Logger   log      = Logger.getLogger( WikiContext.class );
171
172    private static final Permission DUMMY_PERMISSION  = new java.util.PropertyPermission( "os.name", "read" );
173
174    /**
175     *  Create a new WikiContext for the given WikiPage. Delegates to
176     * {@link #WikiContext(WikiEngine, HttpServletRequest, WikiPage)}.
177     *  @param engine The WikiEngine that is handling the request.
178     *  @param page   The WikiPage.  If you want to create a
179     *  WikiContext for an older version of a page, you must use this
180     *  constructor.
181     */
182    public WikiContext( WikiEngine engine, WikiPage page )
183    {
184        this( engine, null, findCommand( engine, null, page ) );
185    }
186
187    /**
188     * <p>
189     * Creates a new WikiContext for the given WikiEngine, Command and
190     * HttpServletRequest.
191     * </p>
192     * <p>
193     * This constructor will also look up the HttpSession associated with the
194     * request, and determine if a WikiSession object is present. If not, a new
195     * one is created.
196     * </p>
197     * @param engine The WikiEngine that is handling the request
198     * @param request The HttpServletRequest that should be associated with this
199     *            context. This parameter may be <code>null</code>.
200     * @param command the command
201     * @throws IllegalArgumentException if <code>engine</code> or
202     *             <code>command</code> are <code>null</code>
203     */
204    public WikiContext( WikiEngine engine, HttpServletRequest request, Command command )
205        throws IllegalArgumentException
206    {
207        super();
208        if ( engine == null || command == null )
209        {
210            throw new IllegalArgumentException( "Parameter engine and command must not be null." );
211        }
212
213        m_engine = engine;
214        m_request = request;
215        m_session = WikiSession.getWikiSession( engine, request );
216        m_command = command;
217
218        // If PageCommand, get the WikiPage
219        if( command instanceof PageCommand )
220        {
221            m_page = (WikiPage)((PageCommand)command).getTarget();
222        }
223
224        // If page not supplied, default to front page to avoid NPEs
225        if( m_page == null )
226        {
227            m_page = m_engine.getPage( m_engine.getFrontPage() );
228
229            // Front page does not exist?
230            if( m_page == null )
231            {
232                m_page = new WikiPage( m_engine, m_engine.getFrontPage() );
233            }
234        }
235
236        m_realPage = m_page;
237
238        // Special case: retarget any empty 'view' PageCommands to the front page
239        if ( PageCommand.VIEW.equals( command ) && command.getTarget() == null )
240        {
241            m_command = command.targetedCommand( m_page );
242        }
243
244        // Debugging...
245        if( log.isDebugEnabled() )
246        {
247            HttpSession session = ( request == null ) ? null : request.getSession( false );
248            String sid = ( session == null ) ? "(null)" : session.getId();
249            log.debug( "Creating WikiContext for session ID=" + sid + "; target=" + getName() );
250        }
251
252        // Figure out what template to use
253        setDefaultTemplate( request );
254    }
255
256    /**
257     * Creates a new WikiContext for the given WikiEngine, WikiPage and
258     * HttpServletRequest. This method simply looks up the appropriate Command
259     * using {@link #findCommand(WikiEngine, HttpServletRequest, WikiPage)} and
260     * delegates to
261     * {@link #WikiContext(WikiEngine, HttpServletRequest, Command)}.
262     * @param engine The WikiEngine that is handling the request
263     * @param request The HttpServletRequest that should be associated with this
264     *            context. This parameter may be <code>null</code>.
265     * @param page The WikiPage. If you want to create a WikiContext for an
266     *            older version of a page, you must supply this parameter
267     */
268    public WikiContext(WikiEngine engine, HttpServletRequest request, WikiPage page)
269    {
270        this( engine, request, findCommand( engine, request, page ) );
271    }
272
273    /**
274     * {@inheritDoc}
275     * @see org.apache.wiki.ui.Command#getContentTemplate()
276     */
277    public String getContentTemplate()
278    {
279        return m_command.getContentTemplate();
280    }
281
282    /**
283     * {@inheritDoc}
284     * @see org.apache.wiki.ui.Command#getJSP()
285     */
286    public String getJSP()
287    {
288        return m_command.getContentTemplate();
289    }
290
291    /**
292     *  Sets a reference to the real page whose content is currently being
293     *  rendered.
294     *  <p>
295     *  Sometimes you may want to render the page using some other page's context.
296     *  In those cases, it is highly recommended that you set the setRealPage()
297     *  to point at the real page you are rendering.  Please see InsertPageTag
298     *  for an example.
299     *  <p>
300     *  Also, if your plugin e.g. does some variable setting, be aware that if it
301     *  is embedded in the LeftMenu or some other page added with InsertPageTag,
302     *  you should consider what you want to do - do you wish to really reference
303     *  the "master" page or the included page.
304     *
305     *  @param page  The real page which is being rendered.
306     *  @return The previous real page
307     *  @since 2.3.14
308     *  @see org.apache.wiki.tags.InsertPageTag
309     */
310    public WikiPage setRealPage( WikiPage page )
311    {
312        WikiPage old = m_realPage;
313        m_realPage = page;
314        updateCommand( m_command.getRequestContext() );
315        return old;
316    }
317
318    /**
319     *  Gets a reference to the real page whose content is currently being rendered.
320     *  If your plugin e.g. does some variable setting, be aware that if it
321     *  is embedded in the LeftMenu or some other page added with InsertPageTag,
322     *  you should consider what you want to do - do you wish to really reference
323     *  the "master" page or the included page.
324     *  <p>
325     *  For example, in the default template, there is a page called "LeftMenu".
326     *  Whenever you access a page, e.g. "Main", the master page will be Main, and
327     *  that's what the getPage() will return - regardless of whether your plugin
328     *  resides on the LeftMenu or on the Main page.  However, getRealPage()
329     *  will return "LeftMenu".
330     *
331     *  @return A reference to the real page.
332     *  @see org.apache.wiki.tags.InsertPageTag
333     *  @see org.apache.wiki.parser.JSPWikiMarkupParser
334     */
335    public WikiPage getRealPage()
336    {
337        return m_realPage;
338    }
339
340    /**
341     *  Figure out to which page we are really going to.  Considers
342     *  special page names from the jspwiki.properties, and possible aliases.
343     *  This method forwards requests to
344     *  {@link org.apache.wiki.ui.CommandResolver#getSpecialPageReference(String)}.
345     *  @return A complete URL to the new page to redirect to
346     *  @since 2.2
347     */
348
349    public String getRedirectURL()
350    {
351        String pagename = m_page.getName();
352        String redirURL = null;
353
354        redirURL = m_engine.getCommandResolver().getSpecialPageReference( pagename );
355
356        if( redirURL == null )
357        {
358            String alias = (String)m_page.getAttribute( WikiPage.ALIAS );
359
360            if( alias != null )
361            {
362                redirURL = getViewURL( alias );
363            }
364            else
365            {
366                redirURL = (String)m_page.getAttribute( WikiPage.REDIRECT );
367            }
368        }
369
370        return redirURL;
371    }
372
373    /**
374     *  Returns the handling engine.
375     *
376     *  @return The wikiengine owning this context.
377     */
378    public WikiEngine getEngine()
379    {
380        return m_engine;
381    }
382
383    /**
384     *  Returns the page that is being handled.
385     *
386     *  @return the page which was fetched.
387     */
388    public WikiPage getPage()
389    {
390        return m_page;
391    }
392
393    /**
394     *  Sets the page that is being handled.
395     *
396     *  @param page The wikipage
397     *  @since 2.1.37.
398     */
399    public void setPage( WikiPage page )
400    {
401        m_page = page;
402        updateCommand( m_command.getRequestContext() );
403    }
404
405    /**
406     *  Returns the request context.
407     *  @return The name of the request context (e.g. VIEW).
408     */
409    public String getRequestContext()
410    {
411        return m_command.getRequestContext();
412    }
413
414    /**
415     *  Sets the request context.  See above for the different
416     *  request contexts (VIEW, EDIT, etc.)
417     *
418     *  @param arg The request context (one of the predefined contexts.)
419     */
420    public void setRequestContext( String arg )
421    {
422        updateCommand( arg );
423    }
424
425    /**
426     * {@inheritDoc}
427     * @see org.apache.wiki.ui.Command#getTarget()
428     */
429    public Object getTarget()
430    {
431        return m_command.getTarget();
432    }
433
434    /**
435     * {@inheritDoc}
436     * @see org.apache.wiki.ui.Command#getURLPattern()
437     */
438    public String getURLPattern()
439    {
440        return m_command.getURLPattern();
441    }
442
443    /**
444     *  Gets a previously set variable.
445     *
446     *  @param key The variable name.
447     *  @return The variable contents.
448     */
449    public Object getVariable( String key )
450    {
451        return m_variableMap.get( key );
452    }
453
454    /**
455     *  Sets a variable.  The variable is valid while the WikiContext is valid,
456     *  i.e. while page processing continues.  The variable data is discarded
457     *  once the page processing is finished.
458     *
459     *  @param key The variable name.
460     *  @param data The variable value.
461     */
462    public void setVariable( String key, Object data )
463    {
464        m_variableMap.put( key, data );
465        updateCommand( m_command.getRequestContext() );
466    }
467
468    /**
469     * This is just a simple helper method which will first check the context
470     * if there is already an override in place, and if there is not,
471     * it will then check the given properties.
472     *
473     * @param key      What key are we searching for?
474     * @param defValue Default value for the boolean
475     * @return  {@code true} or {@code false}.
476     */
477    public boolean getBooleanWikiProperty( final String key, final boolean defValue ) {
478        Object bool = getVariable( key );
479        if( bool != null ) {
480            return TextUtil.isPositive( (String) bool );
481        }
482
483        return TextUtil.getBooleanProperty( getEngine().getWikiProperties(), key, defValue );
484    }
485
486    /**
487     *  This method will safely return any HTTP parameters that
488     *  might have been defined.  You should use this method instead
489     *  of peeking directly into the result of getHttpRequest(), since
490     *  this method is smart enough to do all of the right things,
491     *  figure out UTF-8 encoded parameters, etc.
492     *
493     *  @since 2.0.13.
494     *  @param paramName Parameter name to look for.
495     *  @return HTTP parameter, or null, if no such parameter existed.
496     */
497    public String getHttpParameter( String paramName )
498    {
499        String result = null;
500
501        if( m_request != null )
502        {
503            result = m_request.getParameter( paramName );
504        }
505
506        return result;
507    }
508
509    /**
510     *  If the request did originate from a HTTP request,
511     *  then the HTTP request can be fetched here.  However, it the request
512     *  did NOT originate from a HTTP request, then this method will
513     *  return null, and YOU SHOULD CHECK FOR IT!
514     *
515     *  @return Null, if no HTTP request was done.
516     *  @since 2.0.13.
517     */
518    public HttpServletRequest getHttpRequest()
519    {
520        return m_request;
521    }
522
523    /**
524     *  Sets the template to be used for this request.
525     *
526     *  @param dir The template name
527     *  @since 2.1.15.
528     */
529    public void setTemplate( String dir )
530    {
531        m_template = dir;
532    }
533
534    /**
535     * Returns the target of this wiki context: a page, group name or JSP. If
536     * the associated Command is a PageCommand, this method returns the page's
537     * name. Otherwise, this method delegates to the associated Command's
538     * {@link org.apache.wiki.ui.Command#getName()} method. Calling classes
539     * can rely on the results of this method for looking up canonically-correct
540     * page or group names. Because it does not automatically assume that the
541     * wiki context is a PageCommand, calling this method is inherently safer
542     * than calling <code>getPage().getName()</code>.
543     * @return the name of the target of this wiki context
544     * @see org.apache.wiki.ui.PageCommand#getName()
545     * @see org.apache.wiki.ui.GroupCommand#getName()
546     */
547    public String getName()
548    {
549        if ( m_command instanceof PageCommand )
550        {
551            return m_page != null ? m_page.getName() : "<no page>";
552        }
553        return m_command.getName();
554    }
555
556    /**
557     *  Gets the template that is to be used throughout this request.
558     *  @since 2.1.15.
559     *  @return template name
560     */
561    public String getTemplate()
562    {
563        return m_template;
564    }
565
566    /**
567     *  Convenience method that gets the current user. Delegates the
568     *  lookup to the WikiSession associated with this WikiContect.
569     *  May return null, in case the current
570     *  user has not yet been determined; or this is an internal system.
571     *  If the WikiSession has not been set, <em>always</em> returns null.
572     *
573     *  @return The current user; or maybe null in case of internal calls.
574     */
575    public Principal getCurrentUser()
576    {
577        if (m_session == null)
578        {
579            // This shouldn't happen, really...
580            return WikiPrincipal.GUEST;
581        }
582        return m_session.getUserPrincipal();
583    }
584
585    /**
586     *  A shortcut to generate a VIEW url.
587     *
588     *  @param page The page to which to link.
589     *  @return An URL to the page.  This honours the current absolute/relative setting.
590     */
591    public String getViewURL( String page )
592    {
593        return getURL( VIEW, page, null );
594    }
595
596    /**
597     *  Creates an URL for the given request context.
598     *
599     *  @param context e.g. WikiContext.EDIT
600     *  @param page The page to which to link
601     *  @return An URL to the page, honours the absolute/relative setting in jspwiki.properties
602     */
603    public String getURL( String context,
604                          String page )
605    {
606        return getURL( context, page, null );
607    }
608
609    /**
610     *  Returns an URL from a page. It this WikiContext instance was constructed
611     *  with an actual HttpServletRequest, we will attempt to construct the
612     *  URL using HttpUtil, which preserves the HTTPS portion if it was used.
613     *
614     *  @param context The request context (e.g. WikiContext.UPLOAD)
615     *  @param page    The page to which to link
616     *  @param params  A list of parameters, separated with "&amp;"
617     *
618     *  @return An URL to the given context and page.
619     */
620    public String getURL( String context,
621                          String page,
622                          String params )
623    {
624        boolean absolute = "absolute".equals(m_engine.getVariable( this, WikiEngine.PROP_REFSTYLE ));
625
626        // FIXME: is rather slow
627        return m_engine.getURL( context,
628                                page,
629                                params,
630                                absolute );
631
632    }
633
634    /**
635     * Returns the Command associated with this WikiContext.
636     * @return the command
637     */
638    public Command getCommand()
639    {
640        return m_command;
641    }
642
643    /**
644     *  Returns a shallow clone of the WikiContext.
645     *
646     *  @since 2.1.37.
647     *  @return A shallow clone of the WikiContext
648     */
649    public Object clone()
650    {
651        try
652        {
653            // super.clone() must always be called to make sure that inherited objects
654            // get the right type
655            WikiContext copy = (WikiContext)super.clone();
656
657            copy.m_engine = m_engine;
658            copy.m_command = m_command;
659
660            copy.m_template       = m_template;
661            copy.m_variableMap    = m_variableMap;
662            copy.m_request        = m_request;
663            copy.m_session        = m_session;
664            copy.m_page           = m_page;
665            copy.m_realPage       = m_realPage;
666            return copy;
667        }
668        catch( CloneNotSupportedException e ){} // Never happens
669
670        return null;
671    }
672
673    /**
674     *  Creates a deep clone of the WikiContext.  This is useful when you want
675     *  to be sure that you don't accidentally mess with page attributes, etc.
676     *
677     *  @since  2.8.0
678     *  @return A deep clone of the WikiContext.
679     */
680    public WikiContext deepClone()
681    {
682        try
683        {
684            // super.clone() must always be called to make sure that inherited objects
685            // get the right type
686            WikiContext copy = (WikiContext)super.clone();
687
688            //  No need to deep clone these
689            copy.m_engine  = m_engine;
690            copy.m_command = m_command; // Static structure
691
692            copy.m_template       = m_template;
693            copy.m_variableMap    = (HashMap<String,Object>)m_variableMap.clone();
694            copy.m_request        = m_request;
695            copy.m_session        = m_session;
696            copy.m_page           = (WikiPage)m_page.clone();
697            copy.m_realPage       = (WikiPage)m_realPage.clone();
698            return copy;
699        }
700        catch( CloneNotSupportedException e ){} // Never happens
701
702        return null;
703    }
704
705    /**
706     *  Returns the WikiSession associated with the context.
707     *  This method is guaranteed to always return a valid WikiSession.
708     *  If this context was constructed without an associated
709     *  HttpServletRequest, it will return {@link WikiSession#guestSession(WikiEngine)}.
710     *
711     *  @return The WikiSession associate with this context.
712     */
713    public WikiSession getWikiSession()
714    {
715        return m_session;
716    }
717
718    /**
719     *  This method can be used to find the WikiContext programmatically
720     *  from a JSP PageContext. We check the request context.
721     *  The wiki context, if it exists,
722     *  is looked up using the key
723     *  {@link org.apache.wiki.tags.WikiTagBase#ATTR_CONTEXT}.
724     *
725     *  @since 2.4
726     *  @param pageContext the JSP page context
727     *  @return Current WikiContext, or null, of no context exists.
728     */
729    public static WikiContext findContext( PageContext pageContext )
730    {
731        HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
732        WikiContext context = (WikiContext)request.getAttribute( WikiTagBase.ATTR_CONTEXT );
733        return context;
734    }
735
736    /**
737     * Returns the permission required to successfully execute this context.
738     * For example, the a wiki context of VIEW for a certain page means that
739     * the PagePermission "view" is required for the page. In some cases, no
740     * particular permission is required, in which case a dummy permission will
741     * be returned ({@link java.util.PropertyPermission}<code> "os.name",
742     * "read"</code>). This method is guaranteed to always return a valid,
743     * non-null permission.
744     * @return the permission
745     * @since 2.4
746     */
747    public Permission requiredPermission()
748    {
749        // This is a filthy rotten hack -- absolutely putrid
750        if ( WikiCommand.INSTALL.equals( m_command ) )
751        {
752            // See if admin users exists
753            boolean adminExists = false;
754            try
755            {
756                UserManager userMgr = m_engine.getUserManager();
757                UserDatabase userDb = userMgr.getUserDatabase();
758                userDb.findByLoginName( Installer.ADMIN_ID );
759                adminExists = true;
760            }
761            catch ( NoSuchPrincipalException e )
762            {
763                return DUMMY_PERMISSION;
764            }
765            if ( adminExists )
766            {
767                return new AllPermission( m_engine.getApplicationName() );
768            }
769        }
770
771        // TODO: we should really break the contract so that this
772        // method returns null, but until then we will use this hack
773        if ( m_command.requiredPermission() == null )
774        {
775            return DUMMY_PERMISSION;
776        }
777
778        return m_command.requiredPermission();
779    }
780
781    /**
782     * Associates a target with the current Command and returns
783     * the new targeted Command. If the Command associated with this
784     * WikiContext is already "targeted", it is returned instead.
785     * @see org.apache.wiki.ui.Command#targetedCommand(java.lang.Object)
786     *
787     * {@inheritDoc}
788     */
789    public Command targetedCommand( Object target )
790    {
791        if ( m_command.getTarget() == null )
792        {
793            return m_command.targetedCommand( target );
794        }
795        return m_command;
796    }
797
798    /**
799     *  Returns true, if the current user has administrative permissions (i.e. the omnipotent
800     *  AllPermission).
801     *
802     *  @since 2.4.46
803     *  @return true, if the user has all permissions.
804     */
805    public boolean hasAdminPermissions()
806    {
807        boolean admin = false;
808
809        admin = m_engine.getAuthorizationManager().checkPermission( getWikiSession(),
810                                                                    new AllPermission(m_engine.getApplicationName()) );
811
812        return admin;
813    }
814
815    /**
816     * Figures out which template a new WikiContext should be using.
817     * @param request the HTTP request
818     */
819    protected void setDefaultTemplate( HttpServletRequest request )
820    {
821        // FIXME: Most definitely this should be checked for
822        //        existence, or else it is possible to create pages that
823        //        cannot be shown.
824        String defaultTemplate = m_engine.getTemplateDir();
825
826        //  Figure out which template we should be using for this page.
827        String template = null;
828        if ( request != null )
829        {
830            template = request.getParameter( "skin" );
831        }
832
833        // If request doesn't supply the value, extract from wiki page
834        if( template == null )
835        {
836            WikiPage page = getPage();
837            if ( page != null )
838            {
839                template = (String)page.getAttribute( WikiEngine.PROP_TEMPLATEDIR );
840            }
841
842        }
843
844        // If something over-wrote the default, set the new value.
845        if ( template != null )
846        {
847            setTemplate( template );
848        }
849        else
850        {
851            setTemplate( defaultTemplate );
852        }
853    }
854
855    /**
856     * Looks up and returns a PageCommand based on a supplied WikiPage and HTTP
857     * request. First, the appropriate Command is obtained by examining the HTTP
858     * request; the default is {@link PageCommand#VIEW}. If the Command is a
859     * PageCommand (and it should be, in most cases), a targeted Command is
860     * created using the (non-<code>null</code>) WikiPage as target.
861     * @param engine the wiki engine
862     * @param request the HTTP request
863     * @param page the wiki page
864     * @return the correct command
865     */
866    protected static Command findCommand( WikiEngine engine, HttpServletRequest request, WikiPage page )
867    {
868        String defaultContext = PageCommand.VIEW.getRequestContext();
869        Command command = engine.getCommandResolver().findCommand( request, defaultContext );
870        if ( command instanceof PageCommand && page != null )
871        {
872            command = command.targetedCommand( page );
873        }
874        return command;
875    }
876
877    /**
878     * Protected method that updates the internally cached Command.
879     * Will always be called when the page name, request context, or variable
880     * changes.
881     * @param requestContext the desired request context
882     * @since 2.4
883     */
884    protected void updateCommand( String requestContext )
885    {
886        if ( requestContext == null )
887        {
888            m_command = PageCommand.NONE;
889        }
890        else
891        {
892            CommandResolver resolver = m_engine.getCommandResolver();
893            m_command = resolver.findCommand( m_request, requestContext );
894        }
895
896        if ( m_command instanceof PageCommand && m_page != null )
897        {
898            m_command = m_command.targetedCommand( m_page );
899        }
900    }
901
902}