blob: c4f0b6b4cf6e1d79fb4aca67ecf2e756eff6e48d [file] [log] [blame]
package org.codehaus.redback.components.springutils;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* utility class to mimic some behaviour of the plexus container with role#hint
* @author Olivier Lamy
*/
@Service( "componentContainer" )
public class ComponentContainer
{
private Logger log = LoggerFactory.getLogger( getClass() );
private static final String DEFAULT_ROLE_HINT = "default";
public static final String BEAN_NAME_ROLEHINTSEPARATOR = "#";
/**
* To prevent to much use of #buildMapWithRole we store already used values here
*
* @see #buildMapWithRole(Class)
*/
private Map<String, Map<String, ?>> classBeansOfType = new ConcurrentHashMap<String, Map<String, ?>>();
public String getDefaultRoleHint()
{
return DEFAULT_ROLE_HINT;
}
@Inject
protected ApplicationContext applicationContext;
/**
* <b>must be used only at startup of container (ie in initialize method as it
* can cause performance issue http://jira.springframework.org/browse/SPR-5360</b><br/>
* Returns bean of type T. <br/>
* <b>It must be unique of not {@link RuntimeException}</b>
*
* @param <T>
* @param clazz
* @return
*/
public <T> T getComponent( Class<T> clazz )
{
Map<String, T> beansOfType = applicationContext.getBeansOfType( clazz );
if ( beansOfType == null || beansOfType.isEmpty() )
{
throw new RuntimeException( "no beans of Type " + clazz.getName() );
}
if ( beansOfType.size() > 1 )
{
throw new RuntimeException( "not only one beans of Type " + clazz.getName() );
}
return beansOfType.values().iterator().next();
}
/**
* <b>must be used only at startup of container (ie in initialize method as it
* can cause performance issue http://jira.springframework.org/browse/SPR-5360</b><br/>
* Returns bean of type T and hint . <br/>
*
* @param <T>
* @param clazz
* @param hint
* @return
*/
public <T> T getComponent( Class<T> clazz, String hint )
{
Map<String, T> beansOfType = buildMapWithRole( clazz );
if ( beansOfType == null || beansOfType.isEmpty() )
{
throw new RuntimeException( "no beans of Type " + clazz.getName() );
}
T bean = beansOfType.get( hint );
if ( bean == null )
{
throw new RuntimeException( "no beans of Type " + clazz.getName() + " with hint " + hint );
}
return bean;
}
/**
* Return true if one and only bean of type T exists.
*
* @param <T>
* @param clazz
* @return
*/
public <T> boolean hasComponent( Class<T> clazz )
{
Map<String, T> beansOfType = applicationContext.getBeansOfType( clazz );
if ( beansOfType == null || beansOfType.isEmpty() )
{
return false;
}
return beansOfType.size() == 1;
}
/**
* Return true if one and only bean of type T and hint exists.
*
* @param <T>
* @param clazz
* @param hint
* @return
*/
public <T> boolean hasComponent( Class<T> clazz, String hint )
{
Map<String, T> beansOfType = buildMapWithRole( clazz );
if ( beansOfType == null || beansOfType.isEmpty() )
{
return false;
}
return beansOfType.containsKey( hint );
}
/**
* <b>must be used only at startup of container (ie in initialize method as it
* can cause performance issue http://jira.springframework.org/browse/SPR-5360</b><br/>
* Produce a map with hint as key and bean as value.<br/>
* An internal map is used to cache call to #buildMapWithRole
*
* @param <T>
* @param clazz
* @return
*/
@SuppressWarnings( "unchecked" )
public <T> Map<String, T> buildMapWithRole( Class<T> clazz )
{
try
{
Map<String, T> beansOfType = (Map<String, T>) classBeansOfType.get( clazz.getName() );
if ( beansOfType == null )
{
Map<String, T> map = this.applicationContext.getBeansOfType( clazz );
beansOfType = buildMapWithRole( map );
classBeansOfType.put( clazz.getName(), beansOfType );
}
return beansOfType;
}
catch ( Throwable e )
{
log.error( e.getMessage(), e );
throw new RuntimeException( e.getMessage(), e );
}
}
/**
* Mimic of lookupMap from plexus. <br/>
* Ex: if the bean is called "foo#mine" "AvlRqBuilder#1"A
* then the map will contains mine as key with the bean foo#mine as value </b>
* <b>if no # in the bean name then the bean name will be as it's returned</b>.
*
* @param beansOfType
* @return
*/
public static <T> Map<String, T> buildMapWithRole( Map<String, T> beansOfType )
{
if ( beansOfType == null || beansOfType.isEmpty() )
{
return Collections.emptyMap();
}
Map<String, T> beansOfHint = new HashMap<String, T>();
for ( Map.Entry<String, T> entry : beansOfType.entrySet() )
{
int separatorIndex = StringUtils.indexOf( entry.getKey(), '#' );
if ( separatorIndex >= 0 )
{
String hint = entry.getKey().substring( separatorIndex + 1, entry.getKey().length() );
beansOfHint.put( hint, beansOfType.get( entry.getKey() ) );
}
else
{
beansOfHint.put( entry.getKey(), beansOfType.get( entry.getKey() ) );
}
}
return beansOfHint;
}
}