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

ratpack.guice.internal.DefaultGuiceBackedHandlerFactory Maven / Gradle / Ivy

Go to download

Integration with Google Guice for Ratpack applications - https://code.google.com/p/google-guice/

There is a newer version: 2.0.0-rc-1
Show newest version
/*
 * Copyright 2013 the original author or authors.
 *
 * 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 ratpack.guice.internal;

import com.google.common.collect.ImmutableList;
import com.google.inject.Binder;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.util.Modules;
import io.netty.buffer.ByteBuf;
import ratpack.func.Action;
import ratpack.func.Factory;
import ratpack.func.Function;
import ratpack.guice.BindingsSpec;
import ratpack.guice.GuiceBackedHandlerFactory;
import ratpack.guice.HandlerDecoratingModule;
import ratpack.handling.Handler;
import ratpack.handling.Handlers;
import ratpack.handling.internal.FactoryHandler;
import ratpack.launch.LaunchConfig;
import ratpack.reload.internal.ClassUtil;
import ratpack.reload.internal.ReloadableFileBackedFactory;

import javax.inject.Provider;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import static ratpack.util.ExceptionUtils.uncheck;

public class DefaultGuiceBackedHandlerFactory implements GuiceBackedHandlerFactory {

  private final LaunchConfig launchConfig;

  public DefaultGuiceBackedHandlerFactory(LaunchConfig launchConfig) {
    this.launchConfig = launchConfig;
  }

  public Handler create(final Action modulesAction, final Function moduleTransformer, final Function injectorTransformer) throws Exception {
    if (launchConfig.isReloadable()) {
      File classFile = ClassUtil.getClassFile(modulesAction);
      if (classFile != null) {
        Factory factory = new ReloadableFileBackedFactory<>(classFile.toPath(), true, new ReloadableFileBackedFactory.Producer() {
          @Override
          public InjectorBindingHandler produce(Path file, ByteBuf bytes) throws Exception {
            return doCreate(modulesAction, moduleTransformer, injectorTransformer);
          }
        });

        return new FactoryHandler(factory);
      }
    }

    return doCreate(modulesAction, moduleTransformer, injectorTransformer);
  }

  private InjectorBindingHandler doCreate(Action modulesAction, Function moduleTransformer, Function injectorTransformer) throws Exception {
    DefaultBindingsSpec moduleRegistry = new DefaultBindingsSpec(launchConfig);

    registerDefaultModules(moduleRegistry);
    try {
      modulesAction.execute(moduleRegistry);
    } catch (Exception e) {
      throw uncheck(e);
    }

    Module masterModule = null;
    List modules = moduleRegistry.getModules();
    for (Module module : modules) {
      if (masterModule == null) {
        masterModule = module;
      } else {
        masterModule = Modules.override(masterModule).with(module);
      }
    }

    Injector injector = moduleTransformer.apply(masterModule);

    List> init = moduleRegistry.init;
    for (Action initAction : init) {
      initAction.execute(injector);
    }

    Handler decorated = injectorTransformer.apply(injector);

    List modulesReversed = new ArrayList<>(modules);
    Collections.reverse(modulesReversed);

    for (Module module : modulesReversed) {
      if (module instanceof HandlerDecoratingModule) {
        decorated = ((HandlerDecoratingModule) module).decorate(injector, decorated);
      }
    }

    decorated = Handlers.chain(decorateHandler(decorated), Handlers.notFound());

    return new InjectorBindingHandler(injector, decorated);
  }

  protected Handler decorateHandler(Handler handler) {
    return handler;
  }

  protected void registerDefaultModules(BindingsSpec bindingsSpec) {
    bindingsSpec.add(new DefaultRatpackModule(launchConfig));
  }

  private static class DefaultBindingsSpec implements BindingsSpec {

    private final List modules = new LinkedList<>();
    private final LaunchConfig launchConfig;

    private final LinkedList> actions = new LinkedList<>();
    private final LinkedList> init = new LinkedList<>();

    public DefaultBindingsSpec(LaunchConfig launchConfig) {
      this.launchConfig = launchConfig;
    }

    public LaunchConfig getLaunchConfig() {
      return launchConfig;
    }

    @Override
    public void bind(final Class type) {
      actions.add(new Action() {
        public void execute(Binder binder) throws Exception {
          binder.bind(type);
        }
      });
    }

    @Override
    public  void bind(final Class publicType, final Class implType) {
      actions.add(new Action() {
        public void execute(Binder binder) throws Exception {
          binder.bind(publicType).to(implType);
        }
      });
    }

    @Override
    public  void bind(final Class publicType, final T instance) {
      actions.add(new Action() {
        public void execute(Binder binder) throws Exception {
          binder.bind(publicType).toInstance(instance);
        }
      });
    }

    @Override
    public  void bind(final T instance) {
      @SuppressWarnings("unchecked") final
      Class type = (Class) instance.getClass();
      actions.add(new Action() {
        public void execute(Binder binder) throws Exception {
          binder.bind(type).toInstance(instance);
        }
      });
    }

    @Override
    public  void provider(final Class publicType, final Class> providerType) {
      actions.add(new Action() {
        public void execute(Binder binder) throws Exception {
          binder.bind(publicType).toProvider(providerType);
        }
      });
    }

    @Override
    public void add(Module... modules) {
      Collections.addAll(this.modules, modules);
    }

    @Override
    public void add(Iterable modules) {
      for (Module module : modules) {
        this.modules.add(module);
      }
    }

    @Override
    public  T config(Class moduleClass) {
      for (Module module : modules) {
        if (moduleClass.isInstance(module)) {
          return moduleClass.cast(module);
        }
      }

      return null;
    }

    private List getModules() {
      return ImmutableList.builder()
        .addAll(modules)
        .add(createOverrideModule())
        .build();
    }

    private Module createOverrideModule() {
      return new Module() {
        public void configure(Binder binder) {
          for (Action binderAction : actions) {
            try {
              binderAction.execute(binder);
            } catch (Exception e) {
              throw uncheck(e);
            }
          }
        }
      };
    }

    @Override
    public void init(Action action) {
      init.add(action);
    }

    @Override
    public void init(final Class clazz) {
      init.add(new Action() {
        @Override
        public void execute(Injector injector) throws Exception {
          injector.getInstance(clazz).run();
        }
      });
    }

  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy