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                      log.debug(e.getLocalizedMessage(), e);
    98                  }
    99
    100                 if (beanClass != null)
    101                 {
    102                     // XXX: Hack to deal with aop:scope-proxy (scopedTarget.) beans
    103                     if (!_SpringUtils.isAlternateBeanName(beanName))
    104                     {
    105                         // we are not on a scopedTarget ... check if there is one
    106                         String alternateBeanName = _SpringUtils.getAlternateBeanName(beanName);
    107                         if (beanFactory.containsBeanDefinition(alternateBeanName))
    108                         {
    109                             // ... yes, we are just interested in the alternate one.
    110                             continue;
    111                         }
    112                     }
    113                     String realBeanName = _SpringUtils.getRealBeanName(beanName);
    114
    115                     // check whether the bean is an orchestra-annotated bean,
    116                     // and if so cache its annotation info for later use.
    117                     annotationInfoManager.processBeanAnnotations(realBeanName, beanClass);
    118
    119                     // Now deal with any annotation data that must be processed at startup.
    120                     AnnotationInfo info = annotationInfoManager
    121                             .getAnnotationInfoByBeanName(realBeanName);
    122                     if (info != null)
    123                     {
    124                         processStartupAnnotations(beanDefinition, info);
    125                     }
    126                 }
    127             }
    128         }
    129     }
    130
    131     /**
    132      * Handle any annotations on a bean which should be processed on startup.
    133      * <p>
    134      * One such annotation is the
    135      *
    136      * @ConversationName annotation, which should modify the beanDefinition
    137      *                   object, as it is equivalent to putting an
    138      *                   orchestra:conversationName attribute in the spring bean
    139      *                   declaration.
    140      */
    141     private void processStartupAnnotations(BeanDefinition beanDefinition, AnnotationInfo info)
    142     {
    143         ConversationName conversationName = info.getConversationName();
    144         if (conversationName != null)
    145         {
    146             String convNameFromAnno = conversationName.value();
    147             if (convNameFromAnno != null && convNameFromAnno.length() > 0)
    148             {
    149                 String convNameFromDef = getConversationName(beanDefinition);
    150                 if (convNameFromDef == null)
    151                 {
    152                     setConversationName(beanDefinition, convNameFromAnno);
    153                 }
    154             }
    155         }
    156     }
    157
    158     /**
    159      * Get the orchestra conversationName attribute (if any) from the spring
    160      * bean definition.
    161      */
    162     // TODO: Move this method into orchestra-core, then call it from here, from
    163     // AbstractSpringOrchestraScope and BeanDefinition*Decorator. This of course
    164     // creates a dependency from this code onto that modified orchestra-core
    165     // version.
    166     private static String getConversationName(BeanDefinition def)
    167     {
    168         return (String) def
    169                 .getAttribute(BeanDefinitionConversationNameAttrDecorator.CONVERSATION_NAME_ATTRIBUTE);
    170     }
    171
    172     // See getConversationName
    173     private static void setConversationName(BeanDefinition def, String convName)
    174     {
    175         def.setAttribute(BeanDefinitionConversationNameAttrDecorator.CONVERSATION_NAME_ATTRIBUTE,
    176                 convName);
    177     }
    178 }