blob: fb3935db3292c4450c26f32e60d389cb951f1158 [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.
*/
package org.apache.reef.wake.impl;
import org.apache.reef.wake.MultiObserver;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* The MultiObserverImpl class uses reflection to discover which onNext()
* event processing methods are defined and then map events to them.
* @param <TSubCls> The subclass derived from MultiObserverImpl.
*/
public abstract class MultiObserverImpl<TSubCls> implements MultiObserver {
private static final Logger LOG = Logger.getLogger(MultiObserverImpl.class.getName());
private final Map<String, Method> methodMap = new HashMap<>();
/**
* Use reflection to discover all of the event processing methods in TSubCls
* and setup a means to direct calls from the generic event onNext method defined
* in the MultiObserver interface to specific concrete event onNext methods.
*/
public MultiObserverImpl() {
// Iterate across the methods and build a hash map of class names to reflection methods.
for (final Method method : this.getClass().getMethods()) {
if (method.getName().equals("onNext") && method.getDeclaringClass().equals(this.getClass())) {
// This is an onNext method defined in TSubCls
final Class<?>[] types = method.getParameterTypes();
if (types.length == 2 && types[0].equals(Long.TYPE)) {
methodMap.put(types[1].getName(), method);
}
}
}
}
/**
* Called when an event is received that does not have an onNext method definition
* in TSubCls. Override in TSubClas to handle the error.
* @param event A reference to an object which is an event not handled by TSubCls.
* @param <TEvent> The type of the event being processed.
*/
private <TEvent> void unimplemented(final long identifier, final TEvent event) {
LOG.log(Level.INFO, "Unimplemented event: [{0}]: {1}",
new String[]{String.valueOf(identifier), event.getClass().getName()});
}
/**
* Generic event onNext method in the base interface which maps the call to a concrete
* event onNext method in TSubCls if one exists otherwise unimplemented is invoked.
* @param event An event of type TEvent which will be sent to TSubCls as appropriate.
* @param <TEvent> The type of the event being processed.
*/
@Override
public <TEvent> void onNext(final long identifier, final TEvent event)
throws IllegalAccessException, InvocationTargetException {
// Get the reflection method for this call.
final Method onNext = methodMap.get(event.getClass().getName());
if (onNext != null) {
// Process the event.
onNext.invoke((TSubCls) this, identifier, event);
} else {
// Log the unprocessed event.
unimplemented(identifier, event);
}
}
}