View Javadoc

1   package org.apache.archiva.redback.components.springutils;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  import org.springframework.context.ApplicationContext;
26  import org.springframework.stereotype.Service;
27  
28  import javax.inject.Inject;
29  import java.util.Collections;
30  import java.util.HashMap;
31  import java.util.Map;
32  import java.util.concurrent.ConcurrentHashMap;
33  
34  /**
35   * utility class to mimic some behaviour of the plexus container with role#hint
36   * @author Olivier Lamy
37   */
38  @Service( "componentContainer" )
39  public class ComponentContainer
40  {
41  
42      private Logger log = LoggerFactory.getLogger( getClass() );
43  
44      private static final String DEFAULT_ROLE_HINT = "default";
45  
46      public static final String BEAN_NAME_ROLEHINTSEPARATOR = "#";
47  
48      /**
49       * To prevent to much use of #buildMapWithRole we store already used values here
50       *
51       * @see #buildMapWithRole(Class)
52       */
53      private Map<String, Map<String, ?>> classBeansOfType = new ConcurrentHashMap<String, Map<String, ?>>();
54  
55      public String getDefaultRoleHint()
56      {
57          return DEFAULT_ROLE_HINT;
58      }
59  
60      @Inject
61      protected ApplicationContext applicationContext;
62  
63      /**
64       * <b>must be used only at startup of container (ie in initialize method as it
65       * can cause performance issue http://jira.springframework.org/browse/SPR-5360</b><br/>
66       * Returns bean of type T. <br/>
67       * <b>It must be unique of not {@link RuntimeException}</b>
68       *
69       * @param <T>
70       * @param clazz
71       * @return
72       */
73      public <T> T getComponent( Class<T> clazz )
74      {
75          Map<String, T> beansOfType = applicationContext.getBeansOfType( clazz );
76          if ( beansOfType == null || beansOfType.isEmpty() )
77          {
78              throw new RuntimeException( "no beans of Type " + clazz.getName() );
79          }
80          if ( beansOfType.size() > 1 )
81          {
82              throw new RuntimeException( "not only one beans of Type " + clazz.getName() );
83          }
84          return beansOfType.values().iterator().next();
85      }
86  
87      /**
88       * <b>must be used only at startup of container (ie in initialize method as it
89       * can cause performance issue http://jira.springframework.org/browse/SPR-5360</b><br/>
90       * Returns bean of type T and hint . <br/>
91       *
92       * @param <T>
93       * @param clazz
94       * @param hint
95       * @return
96       */
97      public <T> T getComponent( Class<T> clazz, String hint )
98      {
99          Map<String, T> beansOfType = buildMapWithRole( clazz );
100         if ( beansOfType == null || beansOfType.isEmpty() )
101         {
102             throw new RuntimeException( "no beans of Type " + clazz.getName() );
103         }
104         T bean = beansOfType.get( hint );
105         if ( bean == null )
106         {
107             throw new RuntimeException( "no beans of Type " + clazz.getName() + " with hint " + hint );
108         }
109         return bean;
110     }
111 
112     /**
113      * Return true if one and only bean of type T exists.
114      *
115      * @param <T>
116      * @param clazz
117      * @return
118      */
119     public <T> boolean hasComponent( Class<T> clazz )
120     {
121         Map<String, T> beansOfType = applicationContext.getBeansOfType( clazz );
122         if ( beansOfType == null || beansOfType.isEmpty() )
123         {
124             return false;
125         }
126         return beansOfType.size() == 1;
127     }
128 
129     /**
130      * Return true if one and only bean of type T and hint exists.
131      *
132      * @param <T>
133      * @param clazz
134      * @param hint
135      * @return
136      */
137     public <T> boolean hasComponent( Class<T> clazz, String hint )
138     {
139         Map<String, T> beansOfType = buildMapWithRole( clazz );
140         if ( beansOfType == null || beansOfType.isEmpty() )
141         {
142             return false;
143         }
144         return beansOfType.containsKey( hint );
145     }
146 
147     /**
148      * <b>must be used only at startup of container (ie in initialize method as it
149      * can cause performance issue http://jira.springframework.org/browse/SPR-5360</b><br/>
150      * Produce a map with hint as key and bean as value.<br/>
151      * An internal map is used to cache call to #buildMapWithRole
152      *
153      * @param <T>
154      * @param clazz
155      * @return
156      */
157     @SuppressWarnings( "unchecked" )
158     public <T> Map<String, T> buildMapWithRole( Class<T> clazz )
159     {
160         try
161         {
162             Map<String, T> beansOfType = (Map<String, T>) classBeansOfType.get( clazz.getName() );
163             if ( beansOfType == null )
164             {
165                 Map<String, T> map = this.applicationContext.getBeansOfType( clazz );
166                 beansOfType = buildMapWithRole( map );
167                 classBeansOfType.put( clazz.getName(), beansOfType );
168             }
169             return beansOfType;
170         }
171         catch ( Throwable e )
172         {
173             log.error( e.getMessage(), e );
174             throw new RuntimeException( e.getMessage(), e );
175         }
176     }
177 
178 
179     /**
180      * Mimic of lookupMap from plexus. <br/>
181      * Ex: if the bean is called "foo#mine" "AvlRqBuilder#1"A
182      * then the map will contains mine as key with the bean foo#mine as value </b>
183      * <b>if no # in the bean name then the bean name will be as it's returned</b>.
184      *
185      * @param beansOfType
186      * @return
187      */
188     public static <T> Map<String, T> buildMapWithRole( Map<String, T> beansOfType )
189     {
190         if ( beansOfType == null || beansOfType.isEmpty() )
191         {
192             return Collections.emptyMap();
193         }
194         Map<String, T> beansOfHint = new HashMap<String, T>();
195         for ( Map.Entry<String, T> entry : beansOfType.entrySet() )
196         {
197             int separatorIndex = StringUtils.indexOf( entry.getKey(), '#' );
198             if ( separatorIndex >= 0 )
199             {
200                 String hint = entry.getKey().substring( separatorIndex + 1, entry.getKey().length() );
201                 beansOfHint.put( hint, beansOfType.get( entry.getKey() ) );
202             }
203             else
204             {
205                 beansOfHint.put( entry.getKey(), beansOfType.get( entry.getKey() ) );
206             }
207         }
208         return beansOfHint;
209     }
210 }