MapToListDispatcher.java

/***************************************************************************
   Copyright 2012 Emily Estes

   Licensed 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 net.metanotion.util;


import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** This dispatcher assumes the data object is a pair({@link java.util.Map.Entry}, whose key is a method name, and
whose value is either a {@link java.util.Map}, {@link net.metanotion.util.Dictionary}, or {@link java.lang.Iterable}
which it converts to a list(instance of {@link java.lang.Iterable}). It does by using a map of method of names whose
values are a list of a parameter names in the order they belong.
		@param <O> The type of object that receives the messages generated by this dispatcher.
*/
public final class MapToListDispatcher<O> implements Dispatcher<O, Map.Entry<String,Object>> {
	private static final Logger logger = LoggerFactory.getLogger(MapToListDispatcher.class);

	private final Map<String,Iterable<String>> methodMap;
	private final Dispatcher<O, Map.Entry<String,Iterable>> listDisp;

	/** Create a "typical" dispatcher chain consisting of an instance of
		{@link net.metanotion.util.MapToListDispatcher} with a method map generated by
		{@link net.metanotion.util.NamedParameterMapper} delegating to a
		{@link net.metanotion.util.ReflectionListDispatcher} generated dispatcher.
		@param <I> The type of object that receives the messages generated by the returned dispatcher.
		@param klazz The class to create a dispatcher for.
		@return A dispatcher instance that dispatches method name/parameter map pairs on the class provided.
		@throws IOException if the byte code disassembly(via {@link net.metanotion.util.ObjectParameterMapper} throws
			one.
	*/
	public static <I> Dispatcher<I, Map.Entry<String,Object>> getDispatcher(final Class<I> klazz) throws IOException {
		final NamedParameterMapper namedMapper = new NamedParameterMapper();
		final Map<String,Iterable<String>> methodMap = namedMapper.read(klazz);
		if((!namedMapper.isNamed()) && (!(klazz.isInterface()))) {
			logger.debug("Parameters aren't @Named, using byte code disassembly");
			ObjectParameterMapper.INSTANCE.read(klazz, methodMap);
		}
		final Dispatcher<I, Map.Entry<String,Iterable>> listDispatcher = new ReflectionListDispatcher(klazz);
		return new MapToListDispatcher(methodMap, listDispatcher);
	}

	/** Create a new instance of a dispatcher that converts maps and dictionaries into lists based on a map of
		parameters names to position.
		@param methodMap The keys of this map are the names of the methods, and the values are t	he names of the
			parameters in parameter order.
		@param listDisp The dispatcer this dispatcher delgates to.
	*/
	public MapToListDispatcher(final Map<String,Iterable<String>> methodMap,
			final Dispatcher<O, Map.Entry<String,Iterable>> listDisp) {
		this.methodMap = methodMap;
		this.listDisp = listDisp;
	}

	@Override public Message<O> dispatch(final Map.Entry<String,Object> data) {
		final Iterable<String> paramMap = methodMap.get(data.getKey());
		final ArrayList<Object> list = new ArrayList<>();
		final Object v = data.getValue();
		if(v instanceof Iterable) {
			logger.debug("v is Iterable");
			return listDisp.dispatch(new Pair<>(data.getKey(), (Iterable) v));
		} else if(v instanceof Map) {
			logger.debug("v is Map");
			final Map<String,Object> params = (Map<String,Object>) v;
			if(paramMap != null) {
				for(final String p: paramMap) { list.add(params.get(p)); }
			}
		} else if(v instanceof Dictionary) {
			logger.debug("v is Dict");
			final Dictionary<String,Object> params = (Dictionary<String,Object>) v;
			if(paramMap != null) {
				for(final String p: paramMap) {
					logger.debug(" param {} '{}''", p, params.get(p));
					list.add(params.get(p));
				}
			}
		}
		logger.debug("Dispatching: " + list.size());
		return listDisp.dispatch(new Pair<>(data.getKey(), (Iterable) list));
	}
}