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