Package com.google.gwt.inject.rebind

Source Code of com.google.gwt.inject.rebind.GuiceElementVisitor$GuiceElementVisitorFactory

/*
* Copyright 2011 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.inject.rebind;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.inject.rebind.binding.BindingFactory;
import com.google.gwt.inject.rebind.binding.Context;
import com.google.gwt.inject.rebind.binding.ExposedChildBinding;
import com.google.gwt.inject.rebind.util.PrettyPrinter;
import com.google.inject.Inject;
import com.google.inject.Key;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.spi.DefaultElementVisitor;
import com.google.inject.spi.Element;
import com.google.inject.spi.Message;
import com.google.inject.spi.PrivateElements;
import com.google.inject.spi.ProviderLookup;
import com.google.inject.spi.StaticInjectionRequest;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
* Gathers elements and adds them to a {@link GinjectorBindings}.
*/
public class GuiceElementVisitor extends DefaultElementVisitor<Void> {
 
  /**
   * Interface for use with Assisted Injection for creating {@link GuiceElementVisitor}
   */
  public interface GuiceElementVisitorFactory {
    GuiceElementVisitor create(GinjectorBindings bindingsCollection);
  }

  private final List<Message> messages = new ArrayList<Message>();
  private final TreeLogger logger;
  private final GuiceElementVisitor.GuiceElementVisitorFactory guiceElementVisitorFactory;
  private final GinjectorBindings bindings;
  private final ErrorManager errorManager;
  private final BindingFactory bindingFactory;
  private Iterator<GinjectorBindings> children;
  private GuiceBindingVisitorFactory bindingVisitorFactory;

  @Inject
  public GuiceElementVisitor(TreeLogger logger,
      GuiceElementVisitorFactory guiceElementVisitorFactory,
      GuiceBindingVisitorFactory bindingVisitorFactory,
      ErrorManager errorManager,
      @Assisted GinjectorBindings bindings, BindingFactory bindingFactory) {
    this.logger = logger;
    this.guiceElementVisitorFactory = guiceElementVisitorFactory;
    this.bindingVisitorFactory = bindingVisitorFactory;
    this.errorManager = errorManager;
    this.bindings = bindings;
    this.bindingFactory = bindingFactory;
  }
 
  public void visitElementsAndReportErrors(List<Element> elements) {
    visitElements(elements);
   
    // Capture any binding errors, any of which we treat as fatal.
    if (!messages.isEmpty()) {
      for (Message message : messages) {
        // tostring has both source and message so use that
        errorManager.logError(message.toString(), message.getCause());
      }
    }
  }
 
  private void visitElements(List<Element> elements) {
    // We take advantage of the fact that iterating over the PrivateElements should
    // happen in the same order that the modules were installed.  We match each PrivateElements
    // up with the {@link GinjectorBindings} that were created in the adapter.
    children = bindings.getChildren().iterator();
    for (Element element : elements) {
      element.acceptVisitor(this);
    }
  }

  public <T> Void visit(com.google.inject.Binding<T> command) {
    GuiceBindingVisitor<T> bindingVisitor = bindingVisitorFactory.create(
        command.getKey(), messages, bindings);
    PrettyPrinter.log(logger, TreeLogger.DEBUG, "Adding pin for %s in %s because %s",
        command.getKey(), bindings, command);

    // If we visit a binding for a key, we pin it to the current ginjector,
    // since it indicates that the user explicitly asked for it to be placed
    // there.
    bindings.addPin(command.getKey());
    command.acceptTargetVisitor(bindingVisitor);
    command.acceptScopingVisitor(bindingVisitor);
    return null;
  }

  public Void visit(Message message) {
    messages.add(message);
    return null;
  }

  public <T> Void visit(ProviderLookup<T> providerLookup) {
    // Ignore provider lookups for now
    // TODO(bstoler): I guess we should error if you try to lookup a provider
    // that is not bound?
    return null;
  }

  protected Void visitOther(Element element) {
    visit(new Message(element.getSource(), "Ignoring unsupported Module element: " + element));
    return null;
  }

  public Void visit(StaticInjectionRequest staticInjectionRequest) {
    bindings.addStaticInjectionRequest(
        staticInjectionRequest.getType(),
        staticInjectionRequest.getSource());
    return null;
  }
 
  public Void visit(PrivateElements privateElements) {
    GinjectorBindings childCollection = children.next();
   
    // Add information about the elements in the child ginjector to the child bindings
    // TODO(bchambers): Use the tree loggers more intelligently -- when visiting
    // a child bindings collection, we should create a new branch.  This is slightly
    // complicated because we process  in two stages -- once here where we
    // add explicit bindings (and record implicit dependencies), and again later
    // to resolve the implicit dependencies.
    GuiceElementVisitor childVisitor = guiceElementVisitorFactory.create(childCollection);
    childVisitor.visitElements(privateElements.getElements());
    messages.addAll(childVisitor.getMessages());
   
    // Add information about the exposed elements in child to the current binding collection
    for (Key<?> key : privateElements.getExposedKeys()) {
      ExposedChildBinding childBinding =
          bindingFactory.getExposedChildBinding(key, childCollection,
              Context.forElement(privateElements));

      // The child must have an explicit binding or pin for anything it exposes.
      //
      // Note that this is correct only because the
      // GuiceElementVisitor runs before any synthetic bindings are
      // inserted into the GinjectorBindings (more specifically,
      // before implicit bindings are generated).  Otherwise,
      // isBound() might return true for keys that weren't explicitly bound.
      //
      // If the above invariant is violated, the effect will be to
      // bypass this error in some cases.  The offending key should
      // still generate an error, but it will not be as clearly
      // described.
      if (!(childCollection.isBound(key) || childCollection.isPinned(key))) {
        errorManager.logError(
            "Key %s was exposed from but not bound in %s.  Did you forget to call bind()?",
            key, childCollection);
      }

      PrettyPrinter.log(logger, TreeLogger.TRACE, "Child binding for %s in %s: %s", key, bindings, childBinding);

      bindings.addBinding(key, childBinding);
    }
    return null;
  }

  public List<Message> getMessages() {
    return messages;
  }
}
TOP

Related Classes of com.google.gwt.inject.rebind.GuiceElementVisitor$GuiceElementVisitorFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.