/* * Copyright 2007 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.i18n.rebind; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.i18n.shared.GwtLocale; import com.google.gwt.user.rebind.AbstractSourceCreator; import java.util.HashMap; import java.util.Map; /** * Links classes with their localized counterparts. */ class LocalizableLinkageCreator extends AbstractSourceCreator { static Map<String, JClassType> findDerivedClasses(TreeLogger logger, JClassType baseClass) throws UnableToCompleteException { // Construct valid set of candidates for this type. Map<String, JClassType> matchingClasses = new HashMap<String, JClassType>(); // Add base class if possible. if (baseClass.isInterface() == null && baseClass.isAbstract() == false) { matchingClasses.put(GwtLocale.DEFAULT_LOCALE, baseClass); } String baseName = baseClass.getSimpleSourceName(); // Find matching sub types. JClassType[] x = baseClass.getSubtypes(); for (int i = 0; i < x.length; i++) { JClassType subType = x[i]; if ((subType.isInterface() == null) && (subType.isAbstract() == false)) { String name = subType.getSimpleSourceName(); // Strip locale from type, int localeIndex = name.indexOf(ResourceFactory.LOCALE_SEPARATOR); String subTypeBaseName = name; if (localeIndex != -1) { subTypeBaseName = name.substring(0, localeIndex); } boolean matches = subTypeBaseName.equals(baseName); if (matches) { boolean isDefault = localeIndex == -1 || localeIndex == name.length() - 1 || GwtLocale.DEFAULT_LOCALE.equals(name.substring(localeIndex + 1)); if (isDefault) { // Don't override base as default if present. JClassType defaultClass = matchingClasses.get(GwtLocale.DEFAULT_LOCALE); if (defaultClass != null) { throw error(logger, defaultClass + " and " + baseName + " are both potential default classes for " + baseClass); } else { matchingClasses.put(GwtLocale.DEFAULT_LOCALE, subType); } } else { // Don't allow a locale to be ambiguous. Very similar to default // case, different error message. String localeSubString = name.substring(localeIndex + 1); JClassType dopClass = matchingClasses.get(localeSubString); if (dopClass != null) { throw error(logger, dopClass.getQualifiedSourceName() + " and " + subType.getQualifiedSourceName() + " are both potential matches to " + baseClass + " in locale " + localeSubString); } matchingClasses.put(localeSubString, subType); } } } } return matchingClasses; } /** * Map to cache linkages of implementation classes and interfaces. */ // Change back to ReferenceMap once apache collections is in. private final Map<String, String> implCache = new HashMap<String, String>(); /** * * Finds associated implementation in the current locale. Here are the rules * <p> * </p> * <p> * If class name is X, and locale is z_y, look for X_z_y, then X_z, then X * </p> * * @param baseClass * @return class name to link with * @throws UnableToCompleteException */ String linkWithImplClass(TreeLogger logger, JClassType baseClass, GwtLocale locale) throws UnableToCompleteException { String baseName = baseClass.getQualifiedSourceName(); /** * Try to find implementation class, as the current class is not a Constant * or Message. */ String className = implCache.get(baseName + locale.toString()); if (className != null) { return className; } if (baseClass.getName().indexOf(ResourceFactory.LOCALE_SEPARATOR) != -1) { throw error(logger, "Cannot have a " + ResourceFactory.LOCALE_SEPARATOR + " in the base localizable class " + baseClass); } Map<String, JClassType> matchingClasses = findDerivedClasses(logger, baseClass); // Now that we have all matches, find best class JClassType result = null; for (GwtLocale search : locale.getCompleteSearchList()) { result = matchingClasses.get(search.toString()); if (result != null) { className = result.getQualifiedSourceName(); implCache.put(baseName + locale.toString(), className); return className; } } // No classes matched. throw error(logger, "Cannot find a class to bind to argument type " + baseClass.getQualifiedSourceName()); } }