/* * Copyright 2008 Google Inc. * * 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 com.google.gwt.core.ext.soyc.impl; import com.google.gwt.core.ext.soyc.Member; import com.google.gwt.dev.jjs.ast.JDeclaredType; import com.google.gwt.dev.jjs.ast.JField; import com.google.gwt.dev.jjs.ast.JMethod; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.IdentityHashMap; import java.util.Map; /** * A factory object for the standard implementations of Member subtypes. The * factory methods in this type provide canonicalized instances. The maps used * by MemberFactory use hard, identity-based references. */ public class MemberFactory { private final Map<Class<?>, Map<?, ?>> map = new IdentityHashMap<Class<?>, Map<?, ?>>(); public StandardClassMember get(JDeclaredType type) { return getOrCreate(type, StandardClassMember.class, JDeclaredType.class); } public StandardFieldMember get(JField field) { return getOrCreate(field, StandardFieldMember.class, JField.class); } public StandardMethodMember get(JMethod method) { return getOrCreate(method, StandardMethodMember.class, JMethod.class); } @SuppressWarnings("unchecked") private <K, V extends Member> Map<K, V> getElementMap(Class<V> clazz) { Map<K, V> elementMap = (Map<K, V>) map.get(clazz); if (elementMap == null) { elementMap = new IdentityHashMap<K, V>(); map.put(clazz, elementMap); } return elementMap; } /** * Assumes that the implementation of Member has a two-arg constructor that * accepts a MemberFactory and the key. * * @param <K> the type of key used to canonicalize the mapping * @param <V> the type of Member implementation to use * @param key the key by which the value should be canonicalized * @param implClazz the concrete type of Member to construct * @param constructorParam the declared type of the second parameter of the * concrete Member type * @return the canonicalized instance of Member for the given key */ private <K, V extends Member> V getOrCreate(K key, Class<V> implClazz, Class<? super K> constructorParam) { Map<K, V> elementMap = getElementMap(implClazz); V toReturn = elementMap.get(key); if (toReturn == null) { try { Constructor<V> ctor = implClazz.getConstructor(MemberFactory.class, constructorParam); toReturn = ctor.newInstance(this, key); } catch (NoSuchMethodException e) { throw new RuntimeException(implClazz.getName() + " must declare a two-arg (MemberFactory, " + constructorParam.getName() + ") constructor", e); } catch (IllegalArgumentException e) { // Error on the part of this type throw new RuntimeException(e); } catch (InstantiationException e) { // Error on the part of this type, asking for a non-instantiable type throw new RuntimeException(e); } catch (IllegalAccessException e) { // Error on the part of the coder of implClazz throw new RuntimeException(e); } catch (InvocationTargetException e) { // Probably a RuntimeException thrown from the constructor if (e.getCause() instanceof RuntimeException) { throw (RuntimeException) e.getCause(); } throw new RuntimeException(e); } elementMap.put(key, toReturn); } return toReturn; } }