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  package org.apache.myfaces.orchestra.annotation.spring;
    20
    21  import org.apache.commons.logging.Log;
    22  import org.apache.commons.logging.LogFactory;
    23  import org.apache.myfaces.orchestra.annotation.AnnotationInfo;
    24  import org.apache.myfaces.orchestra.annotation.AnnotationInfoManager;
    25  import org.apache.myfaces.orchestra.conversation.annotations.ConversationName;
    26  import org.apache.myfaces.orchestra.conversation.spring.BeanDefinitionConversationNameAttrDecorator;
    27  import org.apache.myfaces.orchestra.conversation.spring._SpringUtils;
    28  import org.apache.myfaces.shared_orchestra.util.ClassUtils;
    29  import org.springframework.beans.BeansException;
    30  import org.springframework.beans.factory.config.BeanDefinition;
    31  import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
    32  import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    33  import org.springframework.core.Ordered;
    34
    35  /**
    36   * Parse all configured spring beans and extract Orchestra annotations out of
    37   * them.
    38   * <p>
    39   * Just declaring an instance of this type as a Spring Singleton will cause the
    40   * postProcessBeanFactory to be called passing in info about all the bean
    41   * declarations in the spring context, allowing Orchestra annotations on any
    42   * directly declared class to be discovered and processed.
    43   * <p>
    44   * Every class referenced from a bean declaration is then passed to the
    45   * AnnotationInfoManager instance that has been injected into this object.
    46   */
    47  public class AnnotationsInfoInitializer implements BeanFactoryPostProcessor, Ordered
    48  {
    49      private Log log = LogFactory.getLog(AnnotationsInfoInitializer.class);
    50
    51      private int order = Ordered.LOWEST_PRECEDENCE;  // default: same as non-Ordered
    52
    53      private AnnotationInfoManager annotationInfoManager;
    54
    55      /**
    56       * Implement the Spring Ordered interface.
    57       */
    58      public int getOrder()
    59      {
    60          return order;
    61      }
    62
    63      public void setOrder(int order)
    64      {
    65          this.order = order;
    66      }
    67
    68      /**
    69       * Inject the object that actually inspects each Class for Orchestra annotations.
    70       */
    71      public void setAnnotationInfoManager(AnnotationInfoManager annotationInfoManager)
    72      {
    73          this.annotationInfoManager = annotationInfoManager;
    74      }
    75
    76      /**
    77       * For each bean in the beanFactory, load the appropriate Class object and
    78       * pass it to the annotationInfoManager object for inspection.
    79       */
    80      public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
    81              throws BeansException
    82      {
    83          String[] beanNames = beanFactory.getBeanDefinitionNames();
    84          for (String beanName : beanNames)
    85          {
    86              BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
    87              String className = beanDefinition.getBeanClassName();
    88              if (className != null)
    89              {
    90                  Class<?> beanClass = null;
    91                  try
    92                  {
    93                      beanClass = ClassUtils.classForName(className);
    94                  }
    95                  catch (ClassNotFoundException e)
    96                  {
    97
    98                      if (log.isDebugEnabled())
    99                      {
    100                         log.debug(e.getLocalizedMessage(), e);
    101                     }
    102                 }
    103
    104                 if (beanClass != null)
    105                 {
    106                     // XXX: Hack to deal with aop:scope-proxy (scopedTarget.) beans
    107                     if (!_SpringUtils.isAlternateBeanName(beanName))
    108                     {
    109                         // we are not on a scopedTarget ... check if there is one
    110                         String alternateBeanName = _SpringUtils.getAlternateBeanName(beanName);
    111                         if (beanFactory.containsBeanDefinition(alternateBeanName))
    112                         {
    113                             // ... yes, we are just interested in the alternate one.
    114                             continue;
    115                         }
    116                     }
    117                     String realBeanName = _SpringUtils.getRealBeanName(beanName);
    118
    119                     // check whether the bean is an orchestra-annotated bean,
    120                     // and if so cache its annotation info for later use.
    121                     annotationInfoManager.processBeanAnnotations(realBeanName, beanClass);
    122
    123                     // Now deal with any annotation data that must be processed at startup.
    124                     AnnotationInfo info = annotationInfoManager
    125                             .getAnnotationInfoByBeanName(realBeanName);
    126                     if (info != null)
    127                     {
    128                         processStartupAnnotations(beanDefinition, info);
    129                     }
    130                 }
    131             }
    132         }
    133     }
    134
    135     /**
    136      * Handle any annotations on a bean which should be processed on startup.
    137      * <p>
    138      * One such annotation is the
    139      *
    140      * @ConversationName annotation, which should modify the beanDefinition
    141      *                   object, as it is equivalent to putting an
    142      *                   orchestra:conversationName attribute in the spring bean
    143      *                   declaration.
    144      */
    145     private void processStartupAnnotations(BeanDefinition beanDefinition, AnnotationInfo info)
    146     {
    147         ConversationName conversationName = info.getConversationName();
    148         if (conversationName != null)
    149         {
    150             String convNameFromAnno = conversationName.value();
    151             if (convNameFromAnno != null && convNameFromAnno.length() > 0)
    152             {
    153                 String convNameFromDef = getConversationName(beanDefinition);
    154                 if (convNameFromDef == null)
    155                 {
    156                     setConversationName(beanDefinition, convNameFromAnno);
    157                 }
    158             }
    159         }
    160     }
    161
    162     /**
    163      * Get the orchestra conversationName attribute (if any) from the spring
    164      * bean definition.
    165      */
    166     // TODO: Move this method into orchestra-core, then call it from here, from
    167     // AbstractSpringOrchestraScope and BeanDefinition*Decorator. This of course
    168     // creates a dependency from this code onto that modified orchestra-core
    169     // version.
    170     private static String getConversationName(BeanDefinition def)
    171     {
    172         return (String) def
    173                 .getAttribute(BeanDefinitionConversationNameAttrDecorator.CONVERSATION_NAME_ATTRIBUTE);
    174     }
    175
    176     // See getConversationName
    177     private static void setConversationName(BeanDefinition def, String convName)
    178     {
    179         def.setAttribute(BeanDefinitionConversationNameAttrDecorator.CONVERSATION_NAME_ATTRIBUTE,
    180                 convName);
    181     }
    182 }