| /* |
| * 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. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.events; |
| |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Proxy; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.xmlgraphics.util.Service; |
| |
| import org.apache.fop.events.model.EventMethodModel; |
| import org.apache.fop.events.model.EventModel; |
| import org.apache.fop.events.model.EventModelFactory; |
| import org.apache.fop.events.model.EventProducerModel; |
| import org.apache.fop.events.model.EventSeverity; |
| |
| /** |
| * Default implementation of the EventBroadcaster interface. It holds a list of event listeners |
| * and can provide {@link EventProducer} instances for type-safe event production. |
| */ |
| public class DefaultEventBroadcaster implements EventBroadcaster { |
| |
| /** Holds all registered event listeners */ |
| protected CompositeEventListener listeners = new CompositeEventListener(); |
| |
| /** {@inheritDoc} */ |
| public void addEventListener(EventListener listener) { |
| this.listeners.addEventListener(listener); |
| } |
| |
| /** {@inheritDoc} */ |
| public void removeEventListener(EventListener listener) { |
| this.listeners.removeEventListener(listener); |
| } |
| |
| /** {@inheritDoc} */ |
| public boolean hasEventListeners() { |
| return this.listeners.hasEventListeners(); |
| } |
| |
| /** {@inheritDoc} */ |
| public void broadcastEvent(Event event) { |
| this.listeners.processEvent(event); |
| } |
| |
| private static List/*<EventModel>*/ eventModels = new java.util.ArrayList(); |
| private Map proxies = new java.util.HashMap(); |
| |
| static { |
| Iterator iter = Service.providers(EventModelFactory.class, true); |
| while (iter.hasNext()) { |
| EventModelFactory factory = (EventModelFactory)iter.next(); |
| addEventModel(factory.createEventModel()); |
| } |
| } |
| |
| /** |
| * Adds a new {@link EventModel} to the list of registered event models. |
| * @param eventModel the event model instance |
| */ |
| public static void addEventModel(EventModel eventModel) { |
| eventModels.add(eventModel); |
| } |
| |
| /** {@inheritDoc} */ |
| public EventProducer getEventProducerFor(Class clazz) { |
| if (!EventProducer.class.isAssignableFrom(clazz)) { |
| throw new IllegalArgumentException( |
| "Class must be an implementation of the EventProducer interface: " |
| + clazz.getName()); |
| } |
| EventProducer producer; |
| producer = (EventProducer)this.proxies.get(clazz); |
| if (producer == null) { |
| producer = createProxyFor(clazz); |
| this.proxies.put(clazz, producer); |
| } |
| return producer; |
| } |
| |
| private EventProducerModel getEventProducerModel(Class clazz) { |
| for (int i = 0, c = eventModels.size(); i < c; i++) { |
| EventModel eventModel = (EventModel)eventModels.get(i); |
| EventProducerModel producerModel = eventModel.getProducer(clazz); |
| if (producerModel != null) { |
| return producerModel; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Creates a dynamic proxy for the given EventProducer interface that will handle the |
| * conversion of the method call into the broadcasting of an event instance. |
| * @param clazz a descendant interface of EventProducer |
| * @return the EventProducer instance |
| */ |
| protected EventProducer createProxyFor(Class clazz) { |
| final EventProducerModel producerModel = getEventProducerModel(clazz); |
| if (producerModel == null) { |
| throw new IllegalStateException("Event model doesn't contain the definition for " |
| + clazz.getName()); |
| } |
| return (EventProducer)Proxy.newProxyInstance(clazz.getClassLoader(), |
| new Class[] {clazz}, |
| new InvocationHandler() { |
| public Object invoke(Object proxy, Method method, Object[] args) |
| throws Throwable { |
| String methodName = method.getName(); |
| EventMethodModel methodModel = producerModel.getMethod(methodName); |
| String eventID = producerModel.getInterfaceName() + "." + methodName; |
| if (methodModel == null) { |
| throw new IllegalStateException( |
| "Event model isn't consistent" |
| + " with the EventProducer interface. Please rebuild FOP!" |
| + " Affected method: " |
| + eventID); |
| } |
| Map params = new java.util.HashMap(); |
| int i = 1; |
| Iterator iter = methodModel.getParameters().iterator(); |
| while (iter.hasNext()) { |
| EventMethodModel.Parameter param |
| = (EventMethodModel.Parameter)iter.next(); |
| params.put(param.getName(), args[i]); |
| i++; |
| } |
| Event ev = new Event(args[0], eventID, methodModel.getSeverity(), params); |
| broadcastEvent(ev); |
| |
| if (ev.getSeverity() == EventSeverity.FATAL) { |
| EventExceptionManager.throwException(ev, |
| methodModel.getExceptionClass()); |
| } |
| return null; |
| } |
| }); |
| } |
| |
| } |