From 469ac7891d3649a2d8fad69a35925d7434e68e58 Mon Sep 17 00:00:00 2001
From: FURUHASHI Sadayuki <frsyuki@users.sourceforge.jp>
Date: Wed, 1 Dec 2010 20:25:06 +0900
Subject: [PATCH] java adds TemplateRegistry that replaces CustomMessage

---
 .../msgpack/template/TemplateRegistry.java    | 212 ++++++++++++++++++
 1 file changed, 212 insertions(+)
 create mode 100644 java/src/main/java/org/msgpack/template/TemplateRegistry.java

diff --git a/java/src/main/java/org/msgpack/template/TemplateRegistry.java b/java/src/main/java/org/msgpack/template/TemplateRegistry.java
new file mode 100644
index 00000000..cee8de05
--- /dev/null
+++ b/java/src/main/java/org/msgpack/template/TemplateRegistry.java
@@ -0,0 +1,212 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+//
+//    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 org.msgpack.template;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.lang.reflect.Type;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.annotation.Annotation;
+import org.msgpack.annotation.MessagePackMessage;
+import org.msgpack.annotation.MessagePackDelegate;
+import org.msgpack.annotation.MessagePackOrdinalEnum;
+import org.msgpack.Template;
+import org.msgpack.Templates;
+
+public class TemplateRegistry {
+	private static Map<Type, Template> map;
+	private static Map<Type, GenericTemplate> genericMap;
+
+	static {
+		map = new HashMap<Type, Template>();
+		genericMap = new HashMap<Type, GenericTemplate>();
+		BuiltInTemplateLoader.load();
+	}
+
+	public static void register(Class<?> target) { // auto-detect
+		if(target.isEnum()) {
+			register(target, TemplateBuilder.buildOrdinalEnum(target));
+		} else {
+			register(target, TemplateBuilder.build(target));
+		}
+	}
+
+	public static void register(Class<?> target, FieldOption implicitOption) {
+		register(target, TemplateBuilder.build(target, implicitOption));
+	}
+
+	public static void register(Class<?> target, FieldList flist) throws NoSuchFieldException {
+		register(target, TemplateBuilder.build(target, flist));
+	}
+
+	public static synchronized void register(Type rawType, Template tmpl) {
+		if(rawType instanceof ParameterizedType) {
+			rawType = ((ParameterizedType)rawType).getRawType();
+		}
+		map.put(rawType, tmpl);
+	}
+
+	public static synchronized void registerGeneric(Type rawType, GenericTemplate gtmpl) {
+		if(rawType instanceof ParameterizedType) {
+			rawType = ((ParameterizedType)rawType).getRawType();
+		}
+		genericMap.put(rawType, gtmpl);
+	}
+
+	public static synchronized Template lookup(Type targetType) {
+		return lookupImpl(targetType, false, true);
+	}
+
+	public static synchronized Template lookup(Type targetType, boolean forceBuild) {
+		return lookupImpl(targetType, forceBuild, true);
+	}
+
+	public static synchronized Template tryLookup(Type targetType) {
+		return lookupImpl(targetType, false, false);
+	}
+
+	public static synchronized Template tryLookup(Type targetType, boolean forceBuild) {
+		return lookupImpl(targetType, forceBuild, false);
+	}
+
+	private static synchronized Template lookupImpl(Type targetType, boolean forceBuild, boolean fallbackDefault) {
+		Template tmpl;
+		Class<?> target;
+
+		// TODO
+		//if((Type)target instanceof GenericArrayType) {
+		//	return lookupArrayImpl((GenericArrayType)(Type)target);
+		//}
+
+		if(targetType instanceof ParameterizedType) {
+			tmpl = lookupGenericImpl((ParameterizedType)targetType);
+			if(tmpl != null) {
+				return tmpl;
+			}
+			target = (Class<?>)((ParameterizedType)targetType).getRawType();
+		} else {
+			target = (Class<?>)targetType;
+		}
+
+		tmpl = map.get(target);
+		if(tmpl != null) {
+			return tmpl;
+		}
+
+		if(isAnnotated(target, MessagePackMessage.class)) {
+			tmpl = TemplateBuilder.build(target);
+			register(target, tmpl);
+			return tmpl;
+		} else if(isAnnotated(target, MessagePackDelegate.class)) {
+			// TODO DelegateTemplate
+			throw new UnsupportedOperationException("not supported yet. : " + target.getName());
+		} else if(isAnnotated(target, MessagePackOrdinalEnum.class)) {
+			tmpl = TemplateBuilder.buildOrdinalEnum(target);
+			register(target, tmpl);
+			return tmpl;
+		}
+
+		for(Class<?> i : target.getInterfaces()) {
+			tmpl = map.get(i);
+			if(tmpl != null) {
+				map.put(target, tmpl);
+				return tmpl;
+			}
+		}
+
+		Class<?> c = target.getSuperclass();
+		if(c != null) {
+			for(; c != Object.class; c = c.getSuperclass()) {
+				tmpl = map.get(c);
+				if(tmpl != null) {
+					map.put(target, tmpl);
+					return tmpl;
+				}
+			}
+
+			if(forceBuild) {
+				tmpl = TemplateBuilder.build(target);
+				register(target, tmpl);
+				return tmpl;
+			}
+		}
+
+		if(fallbackDefault) {
+			tmpl = new DefaultTemplate((Class<?>)target);
+			register(target, tmpl);
+			return tmpl;
+		} else {
+			return null;
+		}
+	}
+
+	public static synchronized Template lookupGeneric(Type targetType) {
+		if(targetType instanceof ParameterizedType) {
+			ParameterizedType parameterizedType = (ParameterizedType)targetType;
+			Template tmpl = lookupGenericImpl(parameterizedType);
+			if(tmpl != null) {
+				return tmpl;
+			}
+			return new DefaultTemplate((Class<?>)parameterizedType.getRawType(), parameterizedType);
+		} else {
+			throw new IllegalArgumentException("actual types of the generic type are erased: "+targetType);
+		}
+	}
+
+	private static synchronized Template lookupGenericImpl(ParameterizedType type) {
+		Type rawType = type.getRawType();
+		GenericTemplate gtmpl = genericMap.get(rawType);
+		if(gtmpl == null) {
+			return null;
+		}
+
+		Type[] types = type.getActualTypeArguments();
+		Template[] tmpls = new Template[types.length];
+		for(int i=0; i < types.length; i++) {
+			tmpls[i] = lookup(types[i]);
+		}
+
+		return gtmpl.build(tmpls);
+	}
+
+	public static synchronized Template lookupArray(Type targetType) {
+		if(targetType instanceof GenericArrayType) {
+			GenericArrayType arrayType = (GenericArrayType)targetType;
+			return lookupArrayImpl(arrayType);
+		} else {
+			throw new IllegalArgumentException("actual type of the array type is erased: "+targetType);
+		}
+	}
+
+	private static synchronized Template lookupArrayImpl(GenericArrayType arrayType) {
+		Template tmpl = map.get(arrayType);
+		if(tmpl != null) {
+			// TODO primitive types are included?
+			return tmpl;
+		}
+		Type component = arrayType.getGenericComponentType();
+		Template componentTemplate = lookup(component);
+		return new ObjectArrayTemplate(componentTemplate);
+	}
+
+	private static boolean isAnnotated(Class<?> ao, Class<? extends Annotation> with) {
+		return ao.getAnnotation(with) != null;
+	}
+}
+