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.service.impl;
016
017import java.beans.BeanInfo;
018import java.beans.EventSetDescriptor;
019import java.beans.IntrospectionException;
020import java.beans.Introspector;
021import java.lang.reflect.Method;
022import java.util.HashMap;
023import java.util.Map;
024
025import org.apache.hivemind.ErrorLog;
026import org.apache.hivemind.HiveMind;
027import org.apache.hivemind.Location;
028import org.apache.hivemind.impl.BaseLocatable;
029import org.apache.hivemind.service.EventLinker;
030
031/**
032 * Implementation of {@link org.apache.hivemind.service.EventLinker}. Will output warnings whenever
033 * a consumer can't be registered for at least one event set (which can happen when the consumer
034 * does not implement the necessary interfaces).
035 * 
036 * @author Howard Lewis Ship
037 */
038public class EventLinkerImpl extends BaseLocatable implements EventLinker
039{
040    private ErrorLog _errorLog;
041
042    /**
043     * Map of {@link java.beans.EventSetDescriptor}[], keyed on producer class.
044     */
045    private Map _producerEventSets;
046
047    public EventLinkerImpl(ErrorLog errorLog)
048    {
049        _errorLog = errorLog;
050    }
051
052    public void addEventListener(Object producer, String eventSetName, Object consumer,
053            Location location)
054    {
055        EventSetDescriptor[] sets = getEventSets(producer);
056        boolean nameMatch = HiveMind.isNonBlank(eventSetName);
057        Class consumerClass = consumer.getClass();
058
059        int count = 0;
060        for (int i = 0; i < sets.length; i++)
061        {
062            EventSetDescriptor set = sets[i];
063            String name = set.getName();
064
065            if (nameMatch)
066            {
067                if (!eventSetName.equals(name))
068                    continue;
069
070                if (isAssignable(set, consumerClass))
071                    addEventListener(producer, set, consumer, location);
072                else
073                {
074                    _errorLog.error(
075                            ServiceMessages.notCompatibleWithEvent(consumer, set, producer),
076                            location,
077                            null);
078                }
079
080                return;
081            }
082
083            // Not matching on name, add anything that fits!
084
085            if (isAssignable(set, consumerClass))
086            {
087                addEventListener(producer, set, consumer, location);
088                count++;
089            }
090        }
091
092        if (count == 0)
093        {
094            if (nameMatch)
095                _errorLog.error(
096                        ServiceMessages.noSuchEventSet(producer, eventSetName),
097                        location,
098                        null);
099            else
100                _errorLog.error(ServiceMessages.noEventMatches(consumer, producer), location, null);
101        }
102    }
103
104    private boolean isAssignable(EventSetDescriptor set, Class consumerClass)
105    {
106        return set.getListenerType().isAssignableFrom(consumerClass);
107    }
108
109    private void addEventListener(Object producer, EventSetDescriptor set, Object consumer,
110            Location location)
111    {
112        Method m = set.getAddListenerMethod();
113
114        try
115        {
116            m.invoke(producer, new Object[]
117            { consumer });
118        }
119        catch (Exception ex)
120        {
121            _errorLog.error(ServiceMessages.unableToAddListener(
122                    producer,
123                    set,
124                    consumer,
125                    location,
126                    ex), location, ex);
127
128        }
129    }
130
131    private EventSetDescriptor[] getEventSets(Object producer)
132    {
133        return getEventSets(producer.getClass());
134    }
135
136    private synchronized EventSetDescriptor[] getEventSets(Class producerClass)
137    {
138        EventSetDescriptor[] result = null;
139
140        if (_producerEventSets == null)
141            _producerEventSets = new HashMap();
142        else
143            result = (EventSetDescriptor[]) _producerEventSets.get(producerClass);
144
145        if (result == null)
146        {
147            result = findEventSets(producerClass);
148
149            _producerEventSets.put(producerClass, result);
150        }
151
152        return result;
153    }
154
155    private EventSetDescriptor[] findEventSets(Class producerClass)
156    {
157        synchronized (HiveMind.INTROSPECTOR_MUTEX)
158        {
159            try
160            {
161                BeanInfo beanInfo = Introspector.getBeanInfo(producerClass);
162
163                // Will return an empty array (not null) when the class contains
164                // no event sets.
165
166                return beanInfo.getEventSetDescriptors();
167            }
168            catch (IntrospectionException ex)
169            {
170                _errorLog.error(
171                        ServiceMessages.unableToIntrospectClass(producerClass, ex),
172                        null,
173                        ex);
174
175                return new EventSetDescriptor[0];
176            }
177        }
178    }
179
180}