All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gxp.compiler.servicedir..svn.text-base.ScopedServiceDirectory.svn-base Maven / Gradle / Ivy

Go to download

Google XML Pages (GXP) is a templating system used to generate XML/SGML markup (most often HTML).

The newest version!
/*
 * Copyright (C) 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.gxp.compiler.servicedir;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gxp.compiler.alerts.AlertSink;
import com.google.gxp.compiler.base.Callable;
import com.google.gxp.compiler.base.ClassImport;
import com.google.gxp.compiler.base.DefaultingImportVisitor;
import com.google.gxp.compiler.base.Implementable;
import com.google.gxp.compiler.base.Import;
import com.google.gxp.compiler.base.InstanceCallable;
import com.google.gxp.compiler.base.PackageImport;
import com.google.gxp.compiler.base.TemplateName;

import java.util.*;

/**
 * A {@code ServiceDirectory} that looks up resources with a specific "scope".
 * This scope includes a current package, and a set of class and/or package
 * imports. A {@code ScopedServiceDirectory} acts as a decorator for another
 * {@code ServiceDirectory}, intercepting requests for unqualified resources
 * and qualifying them with respect to its scope. Requests for fully qualified
 * resources are passed through to the underlying {@code ServiceDirectory}
 * without modification.
 *
 * 

When attempting to resolve an unqualified reference the rules are as * close to the rules of the Java proramming language as possible: *

    *
  1. class imports have highest precedence. Class imports are not allowed to * be ambiguous. *
  2. the current package has the next highest precedence. *
  3. package imports have the lowest precedence. Ambigous references via * package imports are ignored. That is, if something cannot be found via a * class import or in the current package, but can be found via two or more * distinct package imports, then it is considered to not have been found at * all. *
*/ public class ScopedServiceDirectory implements ServiceDirectory { private final String packageName; private final Set packageImports; private final Map classImports; private final ServiceDirectory baseServiceDirectory; private final Function callableGetter = new Function() { public Callable apply(TemplateName from) { return baseServiceDirectory.getCallable(from); } }; private final Function instanceCallableGetter = new Function() { public InstanceCallable apply(TemplateName from) { return baseServiceDirectory.getInstanceCallable(from); } }; private final Function implementableGetter = new Function() { public Implementable apply(TemplateName from) { return baseServiceDirectory.getImplementable(from); } }; public ScopedServiceDirectory(AlertSink alertSink, final ServiceDirectory baseServiceDirectory, String packageName, List imports) { this.baseServiceDirectory = Preconditions.checkNotNull(baseServiceDirectory); this.packageName = Preconditions.checkNotNull(packageName); ImportProcessor visitor = new ImportProcessor(alertSink, packageName); for (Import imp : imports) { imp.acceptVisitor(visitor); } this.packageImports = ImmutableSet.copyOf(visitor.getPackageImports()); this.classImports = ImmutableMap.copyOf(visitor.getClassImports()); } /** * @return an ImportVisitor that, upon visiting an import, validates it and * populates either classImports or packageImports as appropriate. */ private static class ImportProcessor extends DefaultingImportVisitor { private final AlertSink alertSink; private final Set packageImports = Sets.newHashSet(); private final Map classImports = Maps.newHashMap(); public ImportProcessor(AlertSink alertSink, String packageName) { this.alertSink = Preconditions.checkNotNull(alertSink); packageImports.add(packageName); } public Set getPackageImports() { return packageImports; } public Map getClassImports() { return classImports; } @Override public Void defaultVisitImport(Import imp) { // do nothing return null; } @Override public Void visitClassImport(ClassImport imp) { TemplateName className = imp.getClassName(); String baseName = className.getBaseName(); TemplateName redundantImport = classImports.get(baseName); if ((redundantImport != null) && !className.equals(redundantImport)) { alertSink.add(new AmbiguousImportError(imp, baseName, redundantImport, className)); } else { classImports.put(baseName, className); } return null; } @Override public Void visitPackageImport(PackageImport imp) { packageImports.add(imp.getPackageName()); return null; } } private T baseGet(TemplateName templateName, Function underlyingGetter) { if (templateName.getPackageName() == null) { String baseName = templateName.getBaseName(); if (classImports.containsKey(baseName)) { return underlyingGetter.apply(classImports.get(baseName)); } else { templateName = baseFindUniquePackageMatch(baseName, underlyingGetter); if (templateName == null) { templateName = TemplateName.create(packageName, baseName); } } } return underlyingGetter.apply(templateName); } /** * @return the name of the unique callable that can be found by combining the * specified baseName with our package imports. If there is not a unique * callable, returns null. */ private TemplateName baseFindUniquePackageMatch(String baseName, Function underlyingGetter) { TemplateName result = null; for (String packageImport : packageImports) { TemplateName fqName = new TemplateName.FullyQualified(packageImport, baseName); if (underlyingGetter.apply(fqName) != null) { if (result != null) { // Ambiguous match. return null; } else { result = fqName; } } } return result; } public Callable getCallable(TemplateName templateName) { return baseGet(templateName, callableGetter); } public InstanceCallable getInstanceCallable(TemplateName templateName) { return baseGet(templateName, instanceCallableGetter); } public Implementable getImplementable(TemplateName templateName) { return baseGet(templateName, implementableGetter); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy