View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one
    3    * or more contributor license agreements.  See the NOTICE file
    4    * distributed with this work for additional information
    5    * regarding copyright ownership.  The ASF licenses this file
    6    * to you under the Apache License, Version 2.0 (the
    7    * "License"); you may not use this file except in compliance
    8    * with the License.  You may obtain a copy of the License at
    9    *
    10   *   http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing,
    13   * software distributed under the License is distributed on an
    14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   * KIND, either express or implied.  See the License for the
    16   * specific language governing permissions and limitations
    17   * under the License.
    18   */
    19
    20  package org.apache.myfaces.orchestra.conversation;
    21
    22  import org.apache.myfaces.orchestra.requestParameterProvider.RequestParameterProvider;
    23
    24  /**
    25   * Adds the required fields (conversationContext) to the request parameters.
    26   * <p>
    27   * This ensures that every URL in the generated page contains the current
    28   * conversation context id as a query parameter. When the request is submitted to the
    29   * server this query parameter is then used to select the correct ConversationContext
    30   * instance from the user session (ie the set of Conversation objects that are associated
    31   * with this particular window).
    32   */
    33  public class ConversationRequestParameterProvider implements RequestParameterProvider
    34  {
    35      private final static String[] NO_PARAMETERS = new String[0];
    36
    37      private final static String[] REQUEST_PARAMETERS = new String[]
    38          {
    39              ConversationManager.CONVERSATION_CONTEXT_PARAM
    40          };
    41
    42      private final static ThreadLocal inSeparationModeThreadLocal = new ThreadLocal();
    43
    44      /**
    45       * Update a threadlocal flag indicating whether URLs written to the
    46       * response page should have the special ConversationContext query
    47       * parameter added to them or not.
    48       * <p>
    49       * Defaults to false (no separation), which means that urls ARE modified.
    50       * <p>
    51       * This can be called by a component before rendering its children in order to
    52       * skip this url mangling. Any code that calls this method is responsible for
    53       * restoring the original value at the appropriate time. This is very important,
    54       * because this is a thread-local value that will be inherited by whatever
    55       * request this pooled thread is reused for!
    56       */
    57      public static void setInSeparationMode(boolean separationMode)
    58      {
    59          // TODO: consider using a request-scope variable rather than a
    60          // ThreadLocal; less damage if the flag is not reset..
    61          inSeparationModeThreadLocal.set(separationMode ? Boolean.TRUE : Boolean.FALSE);
    62      }
    63
    64      /**
    65       * Returns true if URLs should be written out unmodified, false if they should
    66       * have the conversation context id appended as a query parameter.
    67       */
    68      public static boolean isInSeparationMode()
    69      {
    70          return Boolean.TRUE.equals(inSeparationModeThreadLocal.get());
    71      }
    72
    73      public String getFieldValue(String field)
    74      {
    75          if (isInSeparationMode())
    76          {
    77              return null;
    78          }
    79
    80          ConversationManager conversationManager = ConversationManager.getInstance();
    81          if (conversationManager == null)
    82          {
    83              throw new IllegalStateException("can find the conversationManager");
    84          }
    85
    86          // fetch the conversation context, creating one if it does not yet exist.
    87          ConversationContext ctx = conversationManager.getOrCreateCurrentConversationContext();
    88          return Long.toString(ctx.getId(), Character.MAX_RADIX);
    89      }
    90
    91      //TODO: theoretical security problem here as something can call this method then
    92      // modify the 0th element of the returned array. If this library is deployed at the
    93      // "shared" level, that means that one webapp can cause a "denial of service" or
    94      // similar against other webapps in the container by changing this critical field.
    95      // Not a very important flaw, but nevertheless...
    96      public String[] getFields()
    97      {
    98          if (isInSeparationMode())
    99          {
    100             return NO_PARAMETERS;
    101         }
    102
    103         return REQUEST_PARAMETERS;
    104     }
    105 }