alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Struts example source code file (ContainerBuilder.java)

This example Struts source code file (ContainerBuilder.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Struts tags/keywords

class, container, containerbuilder, containerbuilder, factory, internalfactory, internalfactory, linkedhashmap, log, logging, override, reflection, scope, string, string, t, t, util

The Struts ContainerBuilder.java source code

/**
 * Copyright (C) 2006 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.opensymphony.xwork2.inject;

import java.lang.reflect.Member;
import java.util.*;
import java.util.logging.Logger;

/**
 * Builds a dependency injection {@link Container}. The combination of
 * dependency type and name uniquely identifies a dependency mapping; you can
 * use the same name for two different types. Not safe for concurrent use.
 *
 * <p>Adds the following factories by default:
 *
 * <ul>
 *   <li>Injects the current {@link Container}.
 *   <li>Injects the {@link Logger} for the injected member's declaring class.
 * </ul>
 *
 * @author crazybob@google.com (Bob Lee)
 */
public final class ContainerBuilder {

  final Map<Key> factories =
      new HashMap<Key>();
  final List<InternalFactory singletonFactories =
      new ArrayList<InternalFactory();
  final List<Class staticInjections = new ArrayList>();
  boolean created;
  boolean allowDuplicates = false;

  private static final InternalFactory<Container> CONTAINER_FACTORY =
      new InternalFactory<Container>() {
        public Container create(InternalContext context) {
          return context.getContainer();
        }
      };

  private static final InternalFactory<Logger> LOGGER_FACTORY =
      new InternalFactory<Logger>() {
        public Logger create(InternalContext context) {
          Member member = context.getExternalContext().getMember();
          return member == null ? Logger.getAnonymousLogger()
              : Logger.getLogger(member.getDeclaringClass().getName());
        }
      };

  /**
   * Constructs a new builder.
   */
  public ContainerBuilder() {
    // In the current container as the default Container implementation.
    factories.put(Key.newInstance(Container.class, Container.DEFAULT_NAME),
        CONTAINER_FACTORY);

    // Inject the logger for the injected member's declaring class.
    factories.put(Key.newInstance(Logger.class, Container.DEFAULT_NAME),
        LOGGER_FACTORY);
  }

  /**
   * Maps a dependency. All methods in this class ultimately funnel through
   * here.
   */
  private <T> ContainerBuilder factory(final Key key,
      InternalFactory<? extends T> factory, Scope scope) {
    ensureNotCreated();
    checkKey(key);
    final InternalFactory<? extends T> scopedFactory =
        scope.scopeFactory(key.getType(), key.getName(), factory);
    factories.put(key, scopedFactory);
    if (scope == Scope.SINGLETON) {
      singletonFactories.add(new InternalFactory<T>() {
        public T create(InternalContext context) {
          try {
            context.setExternalContext(ExternalContext.newInstance(
                null, key, context.getContainerImpl()));
            return scopedFactory.create(context);
          } finally {
            context.setExternalContext(null);
          }
        }
      });
    }
    return this;
  }
  
  /**
   * Ensures a key isn't already mapped.
   */
  private void checkKey(Key<?> key) {
    if (factories.containsKey(key) && !allowDuplicates) {
      throw new DependencyException(
          "Dependency mapping for " + key + " already exists.");
    }
  }

  /**
   * Maps a factory to a given dependency type and name.
   *
   * @param type of dependency
   * @param name of dependency
   * @param factory creates objects to inject
   * @param scope scope of injected instances
   * @return this builder
   */
  public <T> ContainerBuilder factory(final Class type, final String name,
      final Factory<? extends T> factory, Scope scope) {
    InternalFactory<T> internalFactory =
        new InternalFactory<T>() {

      public T create(InternalContext context) {
        try {
          Context externalContext = context.getExternalContext();
          return factory.create(externalContext);
        } catch (Exception e) {
          throw new RuntimeException(e);
        }
      }

      @Override
      public String toString() {
        return new LinkedHashMap<String, Object>() {{
          put("type", type);
          put("name", name);
          put("factory", factory);
        }}.toString();
      }
    };

    return factory(Key.newInstance(type, name), internalFactory, scope);
  }

  /**
   * Convenience method. Equivalent to {@code factory(type,
   * Container.DEFAULT_NAME, factory, scope)}.
   *
   * @see #factory(Class, String, Factory, Scope)
   */
  public <T> ContainerBuilder factory(Class type,
      Factory<? extends T> factory, Scope scope) {
    return factory(type, Container.DEFAULT_NAME, factory, scope);
  }

  /**
   * Convenience method. Equivalent to {@code factory(type, name, factory,
   * Scope.DEFAULT)}.
   *
   * @see #factory(Class, String, Factory, Scope)
   */
  public <T> ContainerBuilder factory(Class type, String name,
      Factory<? extends T> factory) {
    return factory(type, name, factory, Scope.DEFAULT);
  }

  /**
   * Convenience method. Equivalent to {@code factory(type,
   * Container.DEFAULT_NAME, factory, Scope.DEFAULT)}.
   *
   * @see #factory(Class, String, Factory, Scope)
   */
  public <T> ContainerBuilder factory(Class type,
      Factory<? extends T> factory) {
    return factory(type, Container.DEFAULT_NAME, factory, Scope.DEFAULT);
  }

  /**
   * Maps an implementation class to a given dependency type and name. Creates
   * instances using the container, recursively injecting dependencies.
   *
   * @param type of dependency
   * @param name of dependency
   * @param implementation class
   * @param scope scope of injected instances
   * @return this builder
   */
  public <T> ContainerBuilder factory(final Class type, final String name,
      final Class<? extends T> implementation, final Scope scope) {
    // This factory creates new instances of the given implementation.
    // We have to lazy load the constructor because the Container
    // hasn't been created yet.
    InternalFactory<? extends T> factory = new InternalFactory() {

      volatile ContainerImpl.ConstructorInjector<? extends T> constructor;

      @SuppressWarnings("unchecked")
      public T create(InternalContext context) {
        if (constructor == null) {
          this.constructor =
              context.getContainerImpl().getConstructor(implementation);
        }
        return (T) constructor.construct(context, type);
      }

      @Override
      public String toString() {
        return new LinkedHashMap<String, Object>() {{
          put("type", type);
          put("name", name);
          put("implementation", implementation);
          put("scope", scope);
        }}.toString();
      }
    };

    return factory(Key.newInstance(type, name), factory, scope);
  }

  /**
   * Maps an implementation class to a given dependency type and name. Creates
   * instances using the container, recursively injecting dependencies.
   *
   * <p>Sets scope to value from {@link Scoped} annotation on the
   * implementation class. Defaults to {@link Scope#DEFAULT} if no annotation
   * is found.
   *
   * @param type of dependency
   * @param name of dependency
   * @param implementation class
   * @return this builder
   */
  public <T> ContainerBuilder factory(final Class type, String name,
      final Class<? extends T> implementation) {
    Scoped scoped = implementation.getAnnotation(Scoped.class);
    Scope scope = scoped == null ? Scope.DEFAULT : scoped.value();
    return factory(type, name, implementation, scope);
  }

  /**
   * Convenience method. Equivalent to {@code factory(type,
   * Container.DEFAULT_NAME, implementation)}.
   *
   * @see #factory(Class, String, Class)
   */
  public <T> ContainerBuilder factory(Class type,
      Class<? extends T> implementation) {
    return factory(type, Container.DEFAULT_NAME, implementation);
  }

  /**
   * Convenience method. Equivalent to {@code factory(type,
   * Container.DEFAULT_NAME, type)}.
   *
   * @see #factory(Class, String, Class)
   */
  public <T> ContainerBuilder factory(Class type) {
    return factory(type, Container.DEFAULT_NAME, type);
  }

  /**
   * Convenience method. Equivalent to {@code factory(type, name, type)}.
   *
   * @see #factory(Class, String, Class)
   */
  public <T> ContainerBuilder factory(Class type, String name) {
    return factory(type, name, type);
  }

  /**
   * Convenience method. Equivalent to {@code factory(type,
   * Container.DEFAULT_NAME, implementation, scope)}.
   *
   * @see #factory(Class, String, Class, Scope)
   */
  public <T> ContainerBuilder factory(Class type,
      Class<? extends T> implementation, Scope scope) {
    return factory(type, Container.DEFAULT_NAME, implementation, scope);
  }

  /**
   * Convenience method. Equivalent to {@code factory(type,
   * Container.DEFAULT_NAME, type, scope)}.
   *
   * @see #factory(Class, String, Class, Scope)
   */
  public <T> ContainerBuilder factory(Class type, Scope scope) {
    return factory(type, Container.DEFAULT_NAME, type, scope);
  }

  /**
   * Convenience method. Equivalent to {@code factory(type, name, type,
   * scope)}.
   *
   * @see #factory(Class, String, Class, Scope)
   */
  public <T> ContainerBuilder factory(Class type, String name, Scope scope) {
    return factory(type, name, type, scope);
  }
  
  /**
   * Convenience method. Equivalent to {@code alias(type, Container.DEFAULT_NAME,
   * type)}.
   *
   * @see #alias(Class, String, String)
   */
  public <T> ContainerBuilder alias(Class type, String alias) {
    return alias(type, Container.DEFAULT_NAME, alias);
  }
  
  /**
   * Maps an existing factory to a new name. 
   * 
   * @param type of dependency
   * @param name of dependency
   * @param alias of to the dependency
   * @return this builder
   */
  public <T> ContainerBuilder alias(Class type, String name, String alias) {
    return alias(Key.newInstance(type, name), Key.newInstance(type, alias));
  }
  
  /**
   * Maps an existing dependency. All methods in this class ultimately funnel through
   * here.
   */
  private <T> ContainerBuilder alias(final Key key,
      final Key<T> aliasKey) {
    ensureNotCreated();
    checkKey(aliasKey);
    
    final InternalFactory<? extends T> scopedFactory = 
      (InternalFactory<? extends T>)factories.get(key);
    if (scopedFactory == null) {
        throw new DependencyException(
                "Dependency mapping for " + key + " doesn't exists.");
    }
    factories.put(aliasKey, scopedFactory);
    return this;
  }

  /**
   * Maps a constant value to the given name.
   */
  public ContainerBuilder constant(String name, String value) {
    return constant(String.class, name, value);
  }

  /**
   * Maps a constant value to the given name.
   */
  public ContainerBuilder constant(String name, int value) {
    return constant(int.class, name, value);
  }

  /**
   * Maps a constant value to the given name.
   */
  public ContainerBuilder constant(String name, long value) {
    return constant(long.class, name, value);
  }

  /**
   * Maps a constant value to the given name.
   */
  public ContainerBuilder constant(String name, boolean value) {
    return constant(boolean.class, name, value);
  }

  /**
   * Maps a constant value to the given name.
   */
  public ContainerBuilder constant(String name, double value) {
    return constant(double.class, name, value);
  }

  /**
   * Maps a constant value to the given name.
   */
  public ContainerBuilder constant(String name, float value) {
    return constant(float.class, name, value);
  }

  /**
   * Maps a constant value to the given name.
   */
  public ContainerBuilder constant(String name, short value) {
    return constant(short.class, name, value);
  }

  /**
   * Maps a constant value to the given name.
   */
  public ContainerBuilder constant(String name, char value) {
    return constant(char.class, name, value);
  }

  /**
   * Maps a class to the given name.
   */
  public ContainerBuilder constant(String name, Class value) {
    return constant(Class.class, name, value);
  }

  /**
   * Maps an enum to the given name.
   */
  public <E extends Enum ContainerBuilder constant(String name, E value) {
    return constant(value.getDeclaringClass(), name, value);
  }

  /**
   * Maps a constant value to the given type and name.
   */
  private <T> ContainerBuilder constant(final Class type, final String name,
      final T value) {
    InternalFactory<T> factory = new InternalFactory() {
      public T create(InternalContext ignored) {
        return value;
      }

      @Override
      public String toString() {
        return new LinkedHashMap<String, Object>() {
          {
            put("type", type);
            put("name", name);
            put("value", value);
          }
        }.toString();
      }
    };

    return factory(Key.newInstance(type, name), factory, Scope.DEFAULT);
  }

  /**
   * Upon creation, the {@link Container} will inject static fields and methods
   * into the given classes.
   *
   * @param types for which static members will be injected
   */
  public ContainerBuilder injectStatics(Class<?>... types) {
    staticInjections.addAll(Arrays.asList(types));
    return this;
  }

  /**
   * Returns true if this builder contains a mapping for the given type and
   * name.
   */
  public boolean contains(Class<?> type, String name) {
    return factories.containsKey(Key.newInstance(type, name));
  }

  /**
   * Convenience method. Equivalent to {@code contains(type,
   * Container.DEFAULT_NAME)}.
   */
  public boolean contains(Class<?> type) {
    return contains(type, Container.DEFAULT_NAME);
  }

  /**
   * Creates a {@link Container} instance. Injects static members for classes
   * which were registered using {@link #injectStatics(Class...)}.
   *
   * @param loadSingletons If true, the container will load all singletons
   *  now. If false, the container will lazily load singletons. Eager loading
   *  is appropriate for production use while lazy loading can speed
   *  development.
   * @throws IllegalStateException if called more than once
   */
  public Container create(boolean loadSingletons) {
    ensureNotCreated();
    created = true;
    final ContainerImpl container = new ContainerImpl(
        new HashMap<Key>(factories));
    if (loadSingletons) {
      container.callInContext(new ContainerImpl.ContextualCallable<Void>() {
        public Void call(InternalContext context) {
          for (InternalFactory<?> factory : singletonFactories) {
            factory.create(context);
          }
          return null;
        }
      });
    }
    container.injectStatics(staticInjections);
    return container;
  }

  /**
   * Currently we only support creating one Container instance per builder.
   * If we want to support creating more than one container per builder,
   * we should move to a "factory factory" model where we create a factory
   * instance per Container. Right now, one factory instance would be
   * shared across all the containers, singletons synchronize on the
   * container when lazy loading, etc.
   */
  private void ensureNotCreated() {
    if (created) {
      throw new IllegalStateException("Container already created.");
    }
  }
  
  public void setAllowDuplicates(boolean val) {
      allowDuplicates = val;
  }

  /**
   * Implemented by classes which participate in building a container.
   */
  public interface Command {

    /**
     * Contributes factories to the given builder.
     *
     * @param builder
     */
    void build(ContainerBuilder builder);
  }
}

Other Struts examples (source code examples)

Here is a short list of links related to this Struts ContainerBuilder.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.