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

com.maxleap.code.test.framework.BootstrapCloudCode Maven / Gradle / Ivy

There is a newer version: 2.4.9
Show newest version
package com.maxleap.code.test.framework;

import com.maxleap.code.*;
import com.maxleap.code.impl.*;
import sun.net.www.protocol.file.FileURLConnection;

import java.io.*;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 *
 */
public class BootstrapCloudCode {

  private GlobalConfig globalConfig;
  private static final Logger logger = LoggerFactory.getLogger(BootstrapCloudCode.class);
  private LoaderBase loader;
  private ClassLoader classLoader;
  private Set hookClasses;
  private Map classesManagerHandlerMap = new ConcurrentHashMap();

  public BootstrapCloudCode() {
    CloudCodeContants.init();
    globalConfig = CloudCodeContants.GLOBAL_CONFIG;
    hookClasses = new HashSet();
    this.classLoader = Thread.currentThread().getContextClassLoader();
    adapterRegion();
  }

  protected void setRestAddr(String restAddr) {
    CloudCodeContants.DEFAULT_API_ADDRESS_PREFIX = restAddr;
  }

  public void start() {
    //load hook and manager
    loadHookAndManager();
    cacheClasses();
    loadMain(globalConfig.getCodeMain());
  }

  private enum Region {
    US("http://api.maxleap.com/2.0"), CN("http://api.maxleap.cn/2.0");

    private String checkAppIdAddress;

    Region(String checkAppIdAddress) {
      this.checkAppIdAddress = checkAppIdAddress;
    }

    public String getCheckAppIdAddress() {
      return this.checkAppIdAddress + "/apps/%s/info";
    }
  }

  private void adapterRegion() {
    if (checkAppId(Region.CN)) {
      CloudCodeContants.DEFAULT_API_ADDRESS_PREFIX = Region.CN.checkAppIdAddress;
    } else if (checkAppId(Region.US)) {
      CloudCodeContants.DEFAULT_API_ADDRESS_PREFIX = Region.US.checkAppIdAddress;
    } else {
      logger.warn("Does not exist app with id "+CloudCodeContants.GLOBAL_CONFIG.getApplicationID()+" from region[" + Region.CN.name() + "," + Region.US.name() + "]");
    }
  }

  private boolean checkAppId(Region region) {
    String result = null;
    try {
      result = WebUtils.doGet(String.format(region.getCheckAppIdAddress(), CloudCodeContants.GLOBAL_CONFIG.getApplicationID()), CloudCodeContants.getHeaders(null), null);
    } catch (IOException e) {
      if (!e.getMessage().contains("Does not exist app with id " + CloudCodeContants.GLOBAL_CONFIG.getApplicationID()))
        logger.warn("check appId from region[" + region.name() + "] fail:" + e.getMessage());
      return Boolean.FALSE;
    }
    Map map = MLJsonParser.asMap(result);
    if (map != null && map.containsKey("objectId") && map.get("objectId").equals(CloudCodeContants.GLOBAL_CONFIG.getApplicationID()))
      return Boolean.TRUE;
    else return false;
  }

  public MLClassManagerHandler getClassesManagerHandler(String managerName) {
    return classesManagerHandlerMap.get(managerName);
  }

  public Loader getLoader() {
    return this.loader;
  }

  private void loadMain(String userMainClassPath) {
    try {
      @SuppressWarnings("unchecked")
      Class clazz = (Class) Class.forName(userMainClassPath);
      loader = clazz.newInstance();
      loader.main(globalConfig);
    } catch (Exception e) {
      throw new MLException(e);
    }
  }

  private void cacheClasses() {
    //处理不存在hook的entity
    String classesPackage = globalConfig.getPackageClasses();
    if (isBlank(classesPackage)) {
      logger.warn("Your packageClasses is empty.You will can't operate any MLClassesManager interfaces.");
      return;
    }
    try {
      List> allClasses = getClassesForPackage(classLoader, classesPackage);
      if (allClasses.size() == 0) {
        logger.warn("Your packageClasses is empty.You will can't operate any MLClassesManager interfaces.Please check your global.json config");
        return;
      }
      allClasses.removeAll(hookClasses);
      //建立空的entityManager
      for (Class classes : allClasses) {
        MLClassManager classesManager = new MLClassManagerImpl(null, classes);
        MLClassManagerFactory.putManager(classes, classesManager);
        logger.info("cache entity to factory:" + classes.getSimpleName());
      }
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
      System.err.println(e.getMessage());
    }
  }

  private void loadHookAndManager() {
    String hookPackage = globalConfig.getPackageHook();
    if (isBlank(hookPackage)) return;

    URL packageRoot = classLoader.getResource(hookPackage.replace(".", "/"));
    if (packageRoot == null) throw new MLException("your packageHook is invalid.Please check your global.json config");
    File[] files = new File(packageRoot.getFile()).listFiles(new FilenameFilter() {
      public boolean accept(File dir, String name) {
        return name.endsWith(".class");
      }
    });
    for (File file : files) {
      String name = file.getName();
      if (name.endsWith(".class")) {
        parseClass(hookPackage, name.substring(0, name.length() - 6));
      }
    }
  }

  private void parseClass(String hookPackage, String clazzName) {
    try {
      Class hookClazz = classLoader.loadClass(hookPackage + "." + clazzName);
      ClassManager classManagerAnnotation = (ClassManager) hookClazz.getAnnotation(ClassManager.class);
      if (classManagerAnnotation == null) return;
      String managerName = classManagerAnnotation.value();
      if (managerName.equals("")) {
        String[] managerNames = managerName.split("ManagerHook");
        if (managerNames.length >= 2) {
          managerName = managerNames[0];
        } else {
          managerNames = managerName.split("Hook");
          if (managerNames.length >= 2) {
            managerName = managerNames[0];
          } else {
            throw new IllegalArgumentException(String.format("class %s should be annotate value.", hookClazz.getSimpleName()));
          }
        }
      }
      MLClassManagerHookBase hook = (MLClassManagerHookBase) hookClazz.newInstance();
      Type[] types = ((ParameterizedType) hookClazz.getGenericSuperclass()).getActualTypeArguments();
      Class classesClazz = (Class) types[0];
      MLClassManager classesManager = new MLClassManagerImpl(hook, classesClazz);
      classesManagerHandlerMap.put(managerName, new MLClassManagerHandler(classesManager, classesClazz));
      MLClassManagerFactory.putManager(classesClazz, classesManager);
      logger.info("cache hook classes to factory:" + classesClazz.getSimpleName());
      hookClasses.add(classesClazz);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  private boolean isBlank(String str) {
    return (str == null || str.trim().equals(""));
  }

  /**
   * Attempts to list all the classes in the specified package as determined
   * by the context class loader
   *
   * @param packageName the package name to search
   * @return a list of classes that exist within that package
   * @throws ClassNotFoundException if something went wrong
   */
  private List> getClassesForPackage(ClassLoader cld, String packageName) throws ClassNotFoundException {
    final ArrayList> classes = new ArrayList>();
    try {
      if (cld == null) throw new ClassNotFoundException("Can't get class loader.");
      final Enumeration resources = cld.getResources(packageName.replace('.', '/'));
      URLConnection connection;
      for (URL url; resources.hasMoreElements() && ((url = resources.nextElement()) != null); ) {
        try {
          connection = url.openConnection();
          if (connection instanceof JarURLConnection) {
            checkJarFile((JarURLConnection) connection, packageName, classes);
          } else if (connection instanceof FileURLConnection) {
            try {
              checkDirectory(new File(URLDecoder.decode(url.getPath(), "UTF-8")), packageName, classes);
            } catch (final UnsupportedEncodingException ex) {
              throw new ClassNotFoundException(packageName + " does not appear to be a valid package (Unsupported encoding)", ex);
            }
          } else
            throw new ClassNotFoundException(packageName + " (" + url.getPath() + ") does not appear to be a valid package");
        } catch (final IOException e) {
          throw new ClassNotFoundException("IOException was thrown when trying to get all resources for " + packageName, e);
        }
      }
    } catch (final NullPointerException ex) {
      throw new ClassNotFoundException(packageName + " does not appear to be a valid package (Null pointer exception)", ex);
    } catch (final IOException ioEx) {
      throw new ClassNotFoundException("IOException was thrown when trying to get all resources for " + packageName, ioEx);
    }
    return classes;
  }

  /**
   * Private helper method
   *
   * @param directory   The directory to start with
   * @param packageName The package name to search for. Will be needed for getting the
   *                    Class object.
   * @param classes     if a file isn't loaded but still is in the directory
   * @throws ClassNotFoundException
   */
  private void checkDirectory(File directory, String packageName, ArrayList> classes) throws ClassNotFoundException {
    File tmpDirectory;
    if (directory.exists() && directory.isDirectory()) {
      final String[] files = directory.list();

      for (final String file : files) {
        if (file.endsWith(".class")) {
          try {
            classes.add(Class.forName(packageName + '.' + file.substring(0, file.length() - 6)));
          } catch (final NoClassDefFoundError e) {
            // do nothing. this class hasn't been found by the
            // loader, and we don't care.
          }
        } else if ((tmpDirectory = new File(directory, file)).isDirectory()) {
          checkDirectory(tmpDirectory, packageName + "." + file, classes);
        }
      }
    }
  }

  /**
   * Private helper method.
   *
   * @param connection  the connection to the jar
   * @param packageName the package name to search for
   * @param classes     the current ArrayList of all classes. This method will simply
   *                    add new classes.
   * @throws ClassNotFoundException if a file isn't loaded but still is in the jar file
   * @throws IOException            if it can't correctly read from the jar file.
   */
  private void checkJarFile(JarURLConnection connection, String packageName, ArrayList> classes) throws ClassNotFoundException, IOException {
    final JarFile jarFile = connection.getJarFile();
    final Enumeration entries = jarFile.entries();
    String name;
    for (JarEntry jarEntry; entries.hasMoreElements() && ((jarEntry = entries.nextElement()) != null); ) {
      name = jarEntry.getName();
      if (name.contains(".class")) {
        name = name.substring(0, name.length() - 6).replace('/', '.');
        if (name.contains(packageName)) {
          classes.add(classLoader.loadClass(name));
        }
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy