Package juzu.impl.plugin.application

Source Code of juzu.impl.plugin.application.Application

/*
* Copyright 2013 eXo Platform SAS
*
* 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 juzu.impl.plugin.application;

import juzu.Scope;
import juzu.Handler;
import juzu.impl.common.JSON;
import juzu.impl.common.Tools;
import juzu.impl.inject.BeanDescriptor;
import juzu.impl.inject.spi.Injector;
import juzu.impl.plugin.Service;
import juzu.impl.plugin.ServiceContext;
import juzu.impl.plugin.ServiceDescriptor;
import juzu.impl.plugin.application.descriptor.ApplicationDescriptor;
import juzu.impl.inject.spi.InjectionContext;
import juzu.impl.resource.ResourceResolver;

import javax.inject.Singleton;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.ServiceLoader;

/** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
@Singleton
public class Application implements ResourceResolver {

  /** . */
  private final ApplicationDescriptor descriptor;

  /** . */
  InjectionContext<?, ?> injectionContext;

  /** . */
  final ResourceResolver resourceResolver;

  /** . */
  final Injector injector;

  /** . */
  private Map<String, ApplicationService> plugins;

  /** . */
  private final ClassLoader classLoader;

  public Application(Injector injector, ApplicationDescriptor descriptor, ResourceResolver resourceResolver) {
    this.classLoader = descriptor.getApplicationLoader();
    this.injectionContext = null;
    this.descriptor = descriptor;
    this.injector = injector;
    this.resourceResolver = resourceResolver;
    this.plugins = Collections.emptyMap();
  }

  public void start() throws Exception {

    final ResourceResolver applicationResolver = new ResourceResolver() {
      public URL resolve(String uri) {
        if (uri == null) {
          throw new NullPointerException("No null URI accepted");
        }
        if (uri.startsWith("/")) {
          return classLoader.getResource(uri.substring(1));
        } else {
          return null;
        }
      }
    };

    // Take care of plugins
    HashMap<String, ApplicationService> plugins = new HashMap<String, ApplicationService>();
    for (ApplicationService plugin : ServiceLoader.load(ApplicationService.class)) {
      plugins.put(plugin.getName(), plugin);
    }
    HashSet<String> names = new HashSet<String>(descriptor.getConfig().names());
    HashMap<ApplicationService, JSON> configs = new HashMap<ApplicationService, JSON>();
    for (ApplicationService plugin : plugins.values()) {
      String name = plugin.getName();
      if (names.remove(name)) {
        configs.put(plugin, descriptor.getConfig().getJSON(plugin.getName()));
      } else {
        configs.put(plugin, null);
      }
    }
    if (names.size() > 0) {
      throw new UnsupportedOperationException("Handle me gracefully : missing plugins " + names);
    }

    //
    HashMap<String, ServiceDescriptor> pluginDescriptors = new HashMap<String, ServiceDescriptor>();
    for (final Map.Entry<ApplicationService, JSON> entry : configs.entrySet()) {
      ApplicationService plugin = entry.getKey();
      ServiceContext pluginContext = new ServiceContext() {
        public JSON getConfig() {
          return entry.getValue();
        }
        public ClassLoader getClassLoader() {
          return classLoader;
        }
        public ResourceResolver getServerResolver() {
          return resourceResolver;
        }
        public ResourceResolver getApplicationResolver() {
          return applicationResolver;
        }
      };
      plugin.setApplication(descriptor);
      ServiceDescriptor pluginDescriptor = plugin.init(pluginContext);
      if (pluginDescriptor != null) {
        pluginDescriptors.put(plugin.getName(), pluginDescriptor);
      }
    }

    //
    for (Iterator<String> i = plugins.keySet().iterator();i.hasNext();) {
      String name = i.next();
      if (!pluginDescriptors.containsKey(name)) {
        i.remove();
      }
    }

    // Bind the plugins
    for (Service service : plugins.values()) {

      // Bind the plugin as a bean
      Class aClass = service.getClass();
      Object o = service;
      injector.bindBean(aClass, null, o);
    }

    // Bind the beans
    for (ServiceDescriptor pluginDescriptor : pluginDescriptors.values()) {
      for (BeanDescriptor bean : pluginDescriptor.getBeans()) {
        bean.bind(injector);
      }
    }

    // Bind the application descriptor
    injector.bindBean(ApplicationDescriptor.class, null, descriptor);

    // Bind ourself
    injector.bindBean(Application.class, null, this);

    // Bind the scopes
    for (Scope scope : Scope.values()) {
      injector.addScope(scope);
    }

    // Filter the classes:
    // any class beginning with juzu. is refused
    // any class prefixed with the application package is accepted
    // any other application class is refused (i.e a class having an ancestor package annotated with @Application)
    Handler<Class<?>, Boolean> filter = new Handler<Class<?>, Boolean>() {
      HashSet<String> blackList = new HashSet<String>();
      public Boolean handle(Class<?> argument) {
        if (argument.getName().startsWith("juzu.")) {
          return false;
        } else if (argument.getPackage().getName().startsWith(descriptor.getPackageName())) {
          return true;
        } else {
          for (String currentPkg = argument.getPackage().getName();currentPkg != null;currentPkg = Tools.parentPackageOf(currentPkg)) {
            if (blackList.contains(currentPkg)) {
              return false;
            } else {
              try {
                Class<?> packageClass = classLoader.loadClass(currentPkg + ".package-info");
                juzu.Application ann = packageClass.getAnnotation(juzu.Application.class);
                if (ann != null) {
                  blackList.add(currentPkg);
                  return false;
                }
              }
              catch (ClassNotFoundException e) {
                // Skip it
              }
            }
          }
          return true;
        }
      }
    };

    //
    try {
      this.injectionContext = injector.create(filter);
      this.plugins = plugins;
    }
    catch (Exception e) {
      throw new UnsupportedOperationException("handle me gracefully", e);
    }
  }

  public String getName() {
    return descriptor.getName();
  }

  public ClassLoader getClassLoader() {
    return injectionContext.getClassLoader();
  }

  public InjectionContext<?, ?> getInjectionContext() {
    return injectionContext;
  }

  public <T> T resolveBean(Class<T> beanType) {
    return injectionContext.resolveInstance(beanType);
  }

  public <T> Iterable<T> resolveBeans(final Class<T> beanType) {
    return injectionContext.resolveInstances(beanType);
  }

  public ApplicationService getPlugin(String pluginName) {
    return plugins.get(pluginName);
  }

  public ApplicationDescriptor getDescriptor() {
    return descriptor;
  }

  public Object resolveBean(String name) throws InvocationTargetException {
    return resolveBean(injectionContext, name);
  }

  public URL resolve(String uri) {
    return classLoader.getResource(uri.substring(1));
  }

  private <B, I> Object resolveBean(InjectionContext<B, I> manager, String name) throws InvocationTargetException {
    B bean = manager.resolveBean(name);
    if (bean != null) {
      I cc = manager.createContext(bean);
      return manager.getInstance(bean, cc);
    }
    else {
      return null;
    }
  }
}
TOP

Related Classes of juzu.impl.plugin.application.Application

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.