001// Copyright 2004, 2005 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.hivemind.lib.factory;
016
017import java.lang.reflect.Constructor;
018import java.util.HashMap;
019import java.util.Iterator;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.hivemind.ApplicationRuntimeException;
024import org.apache.hivemind.ErrorLog;
025import org.apache.hivemind.HiveMind;
026import org.apache.hivemind.impl.BaseLocatable;
027import org.apache.hivemind.lib.BeanFactory;
028
029/**
030 * Implementation of {@link org.apache.hivemind.lib.BeanFactory}.
031 * 
032 * @author Howard Lewis Ship
033 */
034public class BeanFactoryImpl extends BaseLocatable implements BeanFactory
035{
036    private ErrorLog _errorLog;
037
038    private Class _vendType;
039
040    private Map _contributions = new HashMap();
041
042    private Map _cache = new HashMap();
043
044    private boolean _defaultCacheable;
045
046    public BeanFactoryImpl(ErrorLog errorLog, Class vendType, List contributions,
047            boolean defaultCacheable)
048    {
049        _errorLog = errorLog;
050        _vendType = vendType;
051        _defaultCacheable = defaultCacheable;
052
053        processContributions(contributions);
054    }
055
056    public boolean contains(String locator)
057    {
058        int commax = locator.indexOf(',');
059
060        String name = commax < 0 ? locator.trim() : locator.substring(0, commax);
061
062        return _contributions.containsKey(name);
063    }
064
065    private void processContributions(List list)
066    {
067        Iterator i = list.iterator();
068
069        while (i.hasNext())
070        {
071            BeanFactoryContribution c = (BeanFactoryContribution) i.next();
072
073            Class beanClass = c.getBeanClass();
074
075            if (beanClass.isInterface() || beanClass.isArray() || beanClass.isPrimitive())
076            {
077                _errorLog.error(FactoryMessages.invalidContributionClass(c), c.getLocation(), null);
078                continue;
079            }
080
081            if (!_vendType.isAssignableFrom(beanClass))
082            {
083                _errorLog.error(FactoryMessages.wrongContributionType(c, _vendType), c
084                        .getLocation(), null);
085                continue;
086            }
087
088            _contributions.put(c.getName(), c);
089        }
090    }
091
092    public synchronized Object get(String locator)
093    {
094        Object result = _cache.get(locator);
095
096        if (result == null)
097            result = create(locator);
098
099        return result;
100    }
101
102    // Implicitly synchronized by get()
103
104    private Object create(String locator)
105    {
106        int commax = locator.indexOf(',');
107
108        String name = commax < 0 ? locator.trim() : locator.substring(0, commax);
109        String initializer = commax < 0 ? null : locator.substring(commax + 1).trim();
110
111        BeanFactoryContribution c = (BeanFactoryContribution) _contributions.get(name);
112
113        if (c == null)
114            throw new ApplicationRuntimeException(FactoryMessages.unknownContribution(name));
115
116        Object result = construct(c, initializer);
117
118        if (c.getStoreResultInCache(_defaultCacheable))
119            _cache.put(locator, result);
120
121        return result;
122    }
123
124    private Object construct(BeanFactoryContribution contribution, String initializer)
125    {
126        Class beanClass = contribution.getBeanClass();
127
128        try
129        {
130            if (HiveMind.isBlank(initializer))
131                return beanClass.newInstance();
132
133            Constructor c = beanClass.getConstructor(new Class[]
134            { String.class });
135
136            return c.newInstance(new Object[]
137            { initializer });
138        }
139        catch (Exception ex)
140        {
141            throw new ApplicationRuntimeException(FactoryMessages
142                    .unableToInstantiate(beanClass, ex), contribution.getLocation(), ex);
143
144        }
145    }
146
147}