Package com.quickwebframework.web.util

Source Code of com.quickwebframework.web.util.BundleUtils

package com.quickwebframework.web.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
import java.util.zip.ZipFile;

import org.apache.commons.io.IOExceptionWithCause;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.Version;
import org.osgi.framework.wiring.FrameworkWiring;

import com.quickwebframework.web.listener.QuickWebFrameworkFactory;

/**
* 插件辅助类
*
* @author aaa
*
*/
public class BundleUtils {
  static Logger logger = QuickWebFrameworkFactory.getLogger(BundleUtils.class
      .getName());

  // 插件方法URL模板
  public static String bundleMethodUrlTemplate;

  /**
   * 得到Bundle中的路径列表
   *
   * @param bundle
   *            Bundle对象
   * @param startPath
   *            起始路径,一般为"/"
   * @return
   */
  public static List<String> getPathListInBundle(Bundle bundle,
      String startPath) {
    List<String> rtnList = new ArrayList<String>();
    Enumeration<?> urlEnum = bundle.getEntryPaths(startPath);
    while (urlEnum.hasMoreElements()) {
      String url = (String) urlEnum.nextElement();
      rtnList.add(url);
      // 如果是目录
      if (url.endsWith("/")) {
        rtnList.addAll(getPathListInBundle(bundle, url));
      }
    }
    return rtnList;
  }

  /**
   * 得到Bundle的header映射
   *
   * @param bundle
   * @return
   */
  public static Map<String, String> getBundleHeadersMap(Bundle bundle) {
    Dictionary<String, String> headersDict = bundle.getHeaders();
    Map<String, String> headersMap = new HashMap<String, String>();
    Enumeration<String> keyEnumeration = headersDict.keys();
    while (keyEnumeration.hasMoreElements()) {
      String key = keyEnumeration.nextElement();
      headersMap.put(key, headersDict.get(key));
    }
    return headersMap;
  }

  /**
   * 解压Bundle的文件
   *
   * @param bundle
   *            Bundle对象
   * @param dirPath
   *            解压到的目录
   */
  public static void extractBundleFiles(Bundle bundle, String dirPath) {
    try {
      List<String> urlList = getPathListInBundle(bundle, "/");
      for (String url : urlList) {
        // 如果是目录
        if (url.endsWith("/")) {
          File folder = new File(dirPath + "/" + url);
          if (!folder.exists()) {
            folder.mkdirs();
          }
        } else {
          InputStream inputStream = bundle.getResource(url)
              .openStream();
          File file = new File(dirPath + "/" + url);
          file.createNewFile();
          FileOutputStream outputStream = new FileOutputStream(file);

          IOUtils.copy(inputStream, outputStream);
          outputStream.close();
          inputStream.close();
        }
      }
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }

  /**
   * 安装或更新插件
   *
   * @param bundleContext
   *            BundleContext
   * @param bundleURLs
   *            插件的URL数组
   * @return
   */
  public static Bundle[] installOrUpdateBundle(BundleContext bundleContext,
      URL[] bundleURLs) {
    try {
      InputStream[] bundleInputStreams = new InputStream[bundleURLs.length];
      for (int i = 0; i < bundleURLs.length; i++) {
        URL bundleURL = bundleURLs[i];
        bundleInputStreams[i] = bundleURL.openStream();
      }
      Bundle[] bundles = installOrUpdateBundle(bundleContext,
          bundleInputStreams);
      for (InputStream bundleInputStream : bundleInputStreams) {
        bundleInputStream.close();
      }
      return bundles;
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }

  /**
   * 安装或更新插件
   *
   * @param bundleContext
   *            BundleContext
   * @param bundleFiles
   *            插件的文件数组
   * @return
   * @throws IOException
   */
  public static Bundle[] installOrUpdateBundle(BundleContext bundleContext,
      File[] bundleFiles) throws IOException {
    InputStream[] bundleInputStreams = null;
    try {
      bundleInputStreams = new InputStream[bundleFiles.length];
      for (int i = 0; i < bundleFiles.length; i++) {
        File bundleFile = bundleFiles[i];
        try {
          // 尝试加载为ZIP文件
          ZipFile zipFile = new ZipFile(bundleFile);
          zipFile.close();
        } catch (IOException ex) {
          throw new IOExceptionWithCause(String.format(
              "将文件[%s]作为ZIP文件打开时出错!", bundleFile.getName()), ex);
        }
        bundleInputStreams[i] = new FileInputStream(bundleFile);
      }
      Bundle[] bundles = installOrUpdateBundle(bundleContext,
          bundleInputStreams);

      return bundles;
    } catch (IOException ex) {
      throw ex;
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    } finally {
      if (bundleInputStreams != null && bundleInputStreams.length > 0) {
        for (InputStream bundleInputStream : bundleInputStreams) {
          if (bundleInputStream == null)
            continue;
          try {
            bundleInputStream.close();
          } catch (IOException e) {
            e.printStackTrace();
          }
        }
      }
    }
  }

  /**
   * 安装或更新插件
   *
   * @param bundleContext
   *            BundleContext
   * @param bundleInputStreams
   *            插件的输入流数组
   * @return
   * @throws IOException
   * @throws BundleException
   */
  public static Bundle[] installOrUpdateBundle(BundleContext bundleContext,
      InputStream[] bundleInputStreams) throws BundleException,
      IOException {
    List<BundleInfo> bundleInfoList = new ArrayList<BundleInfo>();
    for (InputStream bundleInputStream : bundleInputStreams) {
      // 得到插件的信息
      try {
        BundleInfo bundleInfo = new BundleInfo(bundleInputStream);
        bundleInfoList.add(bundleInfo);
      } catch (Exception ex) {
        logger.warning("警告:加载Bundle清单文件信息时失败。原因:" + ex.getMessage());
      }
    }

    // 排出安装顺序
    orderBundleInstallList(bundleInfoList);
    // 排出停止顺序(倒序)
    List<BundleInfo> shouldStopBundleInfoList = getShouldRefreshBundleInfoList(
        bundleInfoList, BundleUtils.getAllBundleInfoList(bundleContext));
    // 按照逆序停止Bundle
    for (int i = 0; i < shouldStopBundleInfoList.size(); i++) {
      BundleInfo bundleInfo = shouldStopBundleInfoList
          .get(shouldStopBundleInfoList.size() - i - 1);
      String bundleName = bundleInfo.getBundleName();
      Bundle bundle = getBundleByName(bundleContext, bundleName);
      if (bundle != null && bundle.getState() == Bundle.ACTIVE) {
        logger.config(String.format("插件智能安装函数:根据依赖关系准备停止[%s]插件!",
            bundleName));
        bundle.stop();
      }
    }
    // 休息0.001秒钟
    try {
      Thread.sleep(1);
    } catch (InterruptedException e) {
    }
    Bundle[] installedBundles = new Bundle[bundleInfoList.size()];

    // 按照顺序安装,注意:此处只是安装并不启动插件
    for (int i = 0; i < bundleInfoList.size(); i++) {
      BundleInfo bundleInfo = bundleInfoList.get(i);
      installedBundles[i] = installOrUpdateBundle(bundleContext,
          bundleInfo);
    }

    try {
      // 刷新Bundle
      Bundle systemBundle = bundleContext.getBundle(0);
      FrameworkWiring frameworkWiring = systemBundle
          .adapt(FrameworkWiring.class);

      for (Bundle bundle : frameworkWiring.getRemovalPendingBundles()) {
        logger.config("RemovalPendingBundle:"
            + bundle.getSymbolicName());
      }
      frameworkWiring.refreshBundles(null);

    } catch (Error error) {
      logger.warning("RemovalPendingBundle error." + error.getMessage());
    }

    // 休息0.001秒钟
    try {
      Thread.sleep(1);
    } catch (InterruptedException e) {
    }

    // 重新排出启动或刷新顺序
    List<BundleInfo> shouldStartBundleInfoList = getShouldRefreshBundleInfoList(
        bundleInfoList, BundleUtils.getAllBundleInfoList(bundleContext));
    orderBundleInstallList(shouldStartBundleInfoList);

    // 按照顺序启动Bundle
    for (int i = 0; i < shouldStartBundleInfoList.size(); i++) {
      BundleInfo bundleInfo = shouldStartBundleInfoList.get(i);
      String bundleName = bundleInfo.getBundleName();
      Bundle bundle = getBundleByName(bundleContext, bundleName);
      if (bundle == null) {
        logger.warning(String.format(
            "插件智能安装函数警告:在OSGi容器中未发现名称为[%s]的插件!", bundleName));
        continue;
      } else {
        if (bundle.getState() == Bundle.ACTIVE) {
          logger.warning(String.format(
              "插件智能安装函数警告:[%s]插件在启动之前,已经是启动状态!", bundleName));
        }
        logger.config(String.format("插件智能安装函数:准备启动[%s]插件...",
            bundleName));
        bundle.start();
        logger.config(String.format("插件智能安装函数:启动[%s]插件完成!", bundleName));
      }
    }
    return installedBundles;
  }

  private static Bundle installOrUpdateBundle(BundleContext bundleContext,
      BundleInfo bundleInfo) throws BundleException, IOException {
    String bundleName = bundleInfo.getBundleName();
    Version bundleVersion = bundleInfo.getBundleVersion();

    Bundle preBundle = null;
    Bundle[] bundles = bundleContext.getBundles();
    for (Bundle bundle : bundles) {
      if (bundleName.equals(bundle.getSymbolicName())) {
        preBundle = bundle;
        break;
      }
    }

    Bundle newBundle = null; // 如果之前没有此插件,则安装
    if (preBundle == null) {
      logger.info("自动安装新插件:" + bundleName + "  " + bundleVersion);
      newBundle = bundleContext.installBundle(bundleInfo.getBundleName(),
          bundleInfo.getBundleInputStream());
    }// 否则更新
    else {
      if (bundleVersion.compareTo(preBundle.getVersion()) >= 0) {
        preBundle.stop();
        logger.info("自动将插件:" + bundleName + " 由 "
            + preBundle.getVersion() + "更新到" + bundleVersion);
        preBundle.update(bundleInfo.getBundleInputStream());
        newBundle = preBundle;
      } else {
        logger.warning("插件:" + bundleName + "的版本" + bundleVersion
            + "小于已安装的版本" + preBundle.getVersion() + ",没有应用更新!");
      }
    }
    return newBundle;
  }

  /**
   * 得到插件方法的URL
   *
   * @param bundleName
   * @param methodName
   * @return
   */
  public static String getBundleMethodUrl(String bundleName, String methodName) {
    if (StringUtils.isEmpty(bundleMethodUrlTemplate))
      return "Missing bundleMethodUrlTemplate";
    return String.format(bundleMethodUrlTemplate, bundleName, methodName);
  }

  /**
   * 根据名称得到Bundle
   *
   * @param bundleContext
   * @param bundleName
   * @return
   */
  public static Bundle getBundleByName(BundleContext bundleContext,
      String bundleName) {
    if (bundleContext == null) {
      return null;
    }
    Bundle[] bundles = bundleContext.getBundles();
    for (Bundle bundle : bundles) {
      if (bundleName.equals(bundle.getSymbolicName()))
        return bundle;
    }
    return null;
  }

  /**
   * 得到指定Bundle的信息
   *
   * @param bundle
   * @return
   */
  public static BundleInfo getBundleInfo(Bundle bundle) {
    try {
      BundleInfo newBundleInfo = new BundleInfo();
      Properties prop = new Properties();
      Dictionary<String, String> dict = bundle.getHeaders();
      Enumeration<String> keyEnumeration = dict.keys();
      while (keyEnumeration.hasMoreElements()) {
        String key = keyEnumeration.nextElement();
        prop.put(key, dict.get(key));
      }
      newBundleInfo.loadProperties(prop);
      return newBundleInfo;
    } catch (Exception ex) {
      logger.warning(String
          .format("[com.quickwebframework.util.BundleUtil.getBundleInfo]警告:读取插件[%s]的资源文件[%s]时出错,原因:[%s]",
              bundle.getSymbolicName(),
              BundleInfo.METAINF_FILE_PATH, ex));
      return null;
    }
  }

  /**
   * 得到OSGi容器中已安装的全部插件的信息列表
   *
   * @param bundleContext
   * @return
   */
  public static List<BundleInfo> getAllBundleInfoList(
      BundleContext bundleContext) {
    if (bundleContext == null) {
      return null;
    }

    List<BundleInfo> list = new ArrayList<BundleInfo>();

    Bundle[] bundles = bundleContext.getBundles();
    for (Bundle bundle : bundles) {
      BundleInfo bundleInfo = getBundleInfo(bundle);
      list.add(bundleInfo);
    }
    return list;
  }

  // 得到Bundle名称列表(主要是为了得到最新的list中的顺序)
  private static List<String> getBundleNameList(List<BundleInfo> list) {
    List<String> bundleNameList = new ArrayList<String>();
    for (BundleInfo bundleInfo : list) {
      bundleNameList.add(bundleInfo.getBundleName());
    }
    return bundleNameList;
  }

  // 根据Bundle的依赖关系,排列出安装顺序
  private static void orderBundleInstallList(List<BundleInfo> list) {
    // 用于查询
    List<String> bundleNameList = getBundleNameList(list);
    // 导出包名与Bundle名对应Map
    Map<String, String> exportPackageBundleNameMap = new HashMap<String, String>();
    for (BundleInfo bundleInfo : list) {
      for (String exportPackage : bundleInfo.getExportPackageList()) {
        exportPackageBundleNameMap.put(exportPackage,
            bundleInfo.getBundleName());
      }
    }

    // 开始排序
    for (int i = 0; i < list.size();) {
      // 是否有对象移动
      boolean isItemMoved = false;

      BundleInfo bundleInfo = list.get(i);

      // 根据Require-Bundle排序
      for (String requireBundleName : bundleInfo
          .getRequireBundleNameList()) {
        // 如果依赖的Bundle不在要安装的插件列表中,则忽略
        if (!bundleNameList.contains(requireBundleName))
          continue;

        int requireBundleIndex = bundleNameList
            .indexOf(requireBundleName);

        // 如果需要的包在此包后面,则移动到前面
        if (requireBundleIndex > i) {
          BundleInfo requireBundleInfo = list.get(requireBundleIndex);
          list.remove(requireBundleIndex);
          list.add(i, requireBundleInfo);

          bundleNameList = getBundleNameList(list);
          isItemMoved = true;
          i++;
          logger.config(String
              .format("安装/更新顺序自动计算算法:因为插件[%s]需要插件[%s],所以将插件[%s]移动到[%s]前面。",
                  bundleInfo.getBundleName(),
                  requireBundleName, requireBundleName,
                  bundleInfo.getBundleName()));
        }
      }

      // 根据Import-Package排序
      for (String importPackage : bundleInfo.getImportPackageList()) {
        // 如果导入的包不在要安装的插件的导出包列表中,则忽略
        if (!exportPackageBundleNameMap.containsKey(importPackage))
          continue;
        String importPackageBelongBundleName = exportPackageBundleNameMap
            .get(importPackage);
        int importPackageBelongBundleIndex = bundleNameList
            .indexOf(importPackageBelongBundleName);

        // 如果需要的包在此包后面,则移动到前面
        if (importPackageBelongBundleIndex > i) {
          BundleInfo importPackageBelongBundle = list
              .get(importPackageBelongBundleIndex);
          list.remove(importPackageBelongBundleIndex);
          list.add(i, importPackageBelongBundle);

          bundleNameList = getBundleNameList(list);
          isItemMoved = true;
          i++;
          logger.warning(String
              .format("安装/更新顺序自动计算算法:因为插件[%s]导入了插件[%s]的包[%s],所以将插件[%s]移动到[%s]前面。",
                  bundleInfo.getBundleName(),
                  importPackageBelongBundleName,
                  importPackage,
                  importPackageBelongBundleName,
                  bundleInfo.getBundleName()));
        }

      }
      if (isItemMoved) {
        i = 0;
      } else {
        i++;
      }
    }
  }

  // 得到应该刷新的Bundle
  private static List<BundleInfo> getShouldRefreshBundleInfoList(
      List<BundleInfo> installedBundleInfoList,
      List<BundleInfo> allBundleInfoList) {
    // 已安装全部插件信息Map
    Map<String, BundleInfo> allBundleInfoMap = new HashMap<String, BundleInfo>();
    for (BundleInfo bundleInfo : allBundleInfoList) {
      allBundleInfoMap.put(bundleInfo.getBundleName(), bundleInfo);
    }

    // 应该刷新的插件名称列表
    List<String> shouldRefreshBundleNameList = new ArrayList<String>();
    // 应该刷新的插件信息列表
    List<BundleInfo> shouldRefreshBundleInfoList = new ArrayList<BundleInfo>();

    for (BundleInfo bundleInfo : installedBundleInfoList) {
      shouldRefreshBundleNameList.add(bundleInfo.getBundleName());
      shouldRefreshBundleInfoList.add(bundleInfo);
    }

    for (int i = 0; i < shouldRefreshBundleInfoList.size(); i++) {
      BundleInfo bundleInfo = shouldRefreshBundleInfoList.get(i);
      String bundleName = bundleInfo.getBundleName();
      List<String> bundleExportPackageList = bundleInfo
          .getExportPackageList();

      // 搜索全部的Bundle
      for (BundleInfo tmpBundleInfo : allBundleInfoList) {
        boolean isTrue = false;

        String tmpBundleName = tmpBundleInfo.getBundleName();

        // 如果满足Require-Bundle依赖关系
        if (tmpBundleInfo.getRequireBundleNameList().contains(
            bundleName)) {
          isTrue = true;
        }
        // 否则如果满足Import-Package依赖关系
        else {
          List<String> tmpBundleInfoImportPackageList = tmpBundleInfo
              .getImportPackageList();
          for (String tmpBundleInfoImportPackage : tmpBundleInfoImportPackageList) {
            if (bundleExportPackageList
                .contains(tmpBundleInfoImportPackage)) {
              isTrue = true;
              break;
            }
          }
        }
        // 如果满足依赖关系,并且未加入应该刷新的列表中
        if (isTrue
            && !shouldRefreshBundleNameList.contains(tmpBundleName)) {
          shouldRefreshBundleNameList.add(tmpBundleName);
          shouldRefreshBundleInfoList.add(tmpBundleInfo);
        }
      }
    }
    return shouldRefreshBundleInfoList;
  }
}
TOP

Related Classes of com.quickwebframework.web.util.BundleUtils

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.