blob: cd415a8d70f19e6bd300de04affef953ac3c047a [file] [log] [blame]
/*
* 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;
}
});
}
}