blob: 304ebe2f8697e775b138d93c12c0820478546a39 [file] [log] [blame]
/*
* 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());
}
}