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.spring;
    21
    22  import org.aopalliance.intercept.MethodInterceptor;
    23  import org.aopalliance.intercept.MethodInvocation;
    24  import org.apache.myfaces.orchestra.conversation.Conversation;
    25
    26  /**
    27   * Maintain the appropriate persistence state for the current call-stack.
    28   * <p>
    29   * This class is a MethodInterceptor (an AOP Advice) which should be configured to intercept
    30   * calls to all conversation-scoped beans. It ensures that the appropriate PersistenceContext
    31   * object for this conversation is placed into the default location, by invoking the
    32   * <i>bind</i> method on the persistence context object. Typically the bind method stores
    33   * the persistence context into a thread-local variable, but that is implementation-specific.
    34   * <p>
    35   * When Spring code retrieves the persistence context in order to inject it into a bean,
    36   * it then finds the correct context for the conversation that is associated with the
    37   * nearest conversation-scoped bean in the callstack.
    38   * <p>
    39   * If no PersistenceContext yet exists for the conversation associated with the bean
    40   * that is being invoked then one is created using {@link PersistenceContextFactory}.
    41   * <p>
    42   * A reference to the {@link PersistenceContext} is put into the conversation attribute
    43   * map wrapped in an {@link PersistenceContextCloser} so that when the conversation
    44   * ends a callback occurs on it which closes the underlying object.
    45   */
    46  public class PersistenceContextConversationInterceptor implements MethodInterceptor
    47  {
    48      private final static String PERSISTENCE_CONTEXT_CONV_ATTRIBUTE =
    49          PersistenceContextConversationInterceptor.class.getName() + ".PERSISTENCE_CONTEXT";
    50      public final static String REQUEST_ATTRIBUTE =
    51          PersistenceContextConversationInterceptor.class.getName() + ".USED_PERSISTENCE_CONTEXTS";
    52
    53      private PersistenceContextFactory persistenceContextFactory;
    54
    55      public PersistenceContextConversationInterceptor()
    56      {
    57      }
    58
    59      public void setPersistenceContextFactory(PersistenceContextFactory persistenceContextFactory)
    60      {
    61          this.persistenceContextFactory = persistenceContextFactory;
    62      }
    63
    64      public Object invoke(MethodInvocation methodInvocation) throws Throwable
    65      {
    66          PersistenceContext persistenceContext = null;
    67
    68          // The CurrentConversationAdvice object is expected to have already been executed,
    69          // so the "current conversation" is now the one associated with the bean being
    70          // invoked. But the persistence context currently configured is still unchanged,
    71          // so here we set up the context associated with this conversation (creating
    72          // it if this is the first call to this conversation).
    73          Conversation conversation = Conversation.getCurrentInstance();
    74          if (conversation != null)
    75          {
    76              PersistenceContextCloser persistenceContextCloser = (PersistenceContextCloser)
    77                  conversation.getAttribute(PERSISTENCE_CONTEXT_CONV_ATTRIBUTE);
    78              if (persistenceContextCloser != null)
    79              {
    80                  // This is not the first call to this conversation (the closer exists). So
    81                  // retrieve the existing PersistenceContext for this conversation from the
    82                  // closer object.
    83                  persistenceContext = persistenceContextCloser.getPersistenceContext();
    84              }
    85
    86              if (persistenceContext == null)
    87              {
    88                  // This must be the first time any bean in this conversation has been
    89                  // invoked. Therefore create a PersistenceContext. Also create a
    90                  // PersistenceContextCloser and cache it in the conversation.
    91                  persistenceContext = persistenceContextFactory.create();
    92
    93                  conversation.setAttribute(
    94                      PERSISTENCE_CONTEXT_CONV_ATTRIBUTE,
    95                      new PersistenceContextCloser(persistenceContext));
    96              }
    97          }
    98
    99          if (persistenceContext != null)
    100         {
    101             // Make the persistenceContext object the "current" one. All PersistenceContext
    102             // instances that Spring injected are proxies that look up the actual target
    103             // PersistenceContext on each method call; after this bind call, the object
    104             // that they will retrieve is our new persistenceContext.
    105             persistenceContext.bind();
    106         }
    107
    108         try
    109         {
    110             return methodInvocation.proceed();
    111         }
    112         finally
    113         {
    114             if (persistenceContext != null)
    115             {
    116                 persistenceContext.unbind();
    117             }
    118         }
    119     }
    120
    121     /*
    122     protected void registerPersistenceContextUsage(PersistenceContext persistenceContext)
    123     {
    124         FrameworkAdapterInterface fai = FrameworkAdapter.getInstance();
    125         Set persistencesContexts = (Set) fai.getRequestAttribute(REQUEST_ATTRIBUTE);
    126         if (persistencesContexts == null)
    127         {
    128             persistencesContexts = new HashSet();
    129             fai.setRequestAttribute(REQUEST_ATTRIBUTE, persistencesContexts);
    130         }
    131         if (!persistencesContexts.contains(persistenceContext))
    132         {
    133             persistencesContexts.add(persistenceContext);
    134         }
    135     }
    136
    137     public static void cleanupPersistence()
    138     {
    139         FrameworkAdapterInterface fai = FrameworkAdapter.getInstance();
    140         Set persistencesContexts = (Set) fai.getRequestAttribute(REQUEST_ATTRIBUTE);
    141         if (persistencesContexts == null)
    142         {
    143             return;
    144         }
    145
    146         Iterator iterPersistencesContexts = persistencesContexts.iterator();
    147         while (iterPersistencesContexts.hasNext())
    148         {
    149             PersistenceContext persistenceContext = (PersistenceContext) iterPersistencesContexts.next();
    150             persistenceContext.unbind();
    151         }
    152     }
    153     */
    154 }