Package org.vosao.business.impl.plugin

Source Code of org.vosao.business.impl.plugin.PluginLoader

/**
* Vosao CMS. Simple CMS for Google App Engine.
*
* Copyright (C) 2009-2010 Vosao development team.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*
* email: vosao.dev@gmail.com
*/

package org.vosao.business.impl.plugin;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.vosao.business.Business;
import org.vosao.common.PluginException;
import org.vosao.dao.Dao;
import org.vosao.entity.FileEntity;
import org.vosao.entity.FolderEntity;
import org.vosao.entity.PluginEntity;
import org.vosao.entity.PluginResourceEntity;
import org.vosao.utils.FolderUtil;
import org.vosao.utils.MimeType;
import org.vosao.utils.StrUtil;

public class PluginLoader {

  private static final Log logger = LogFactory.getLog(PluginLoader.class);

  private static final String VOSAO_PLUGIN = "WEB-INF/vosao-plugin.xml";
  private static final String RESOURCE_LIST = ".resourceList";
  private static final String FILE_LIST = ".fileList";
 
  private Dao dao;
  private Business business;
 
  public PluginLoader(Dao dao, Business business) {
    super();
    this.dao = dao;
    this.business = business;
  }

  private static class WarItem {
    public String path;
    public String filename;
    public ByteArrayOutputStream data;

    public WarItem(String path, ByteArrayOutputStream data) {
      super();
      this.path = path;
      this.filename = FolderUtil.getFileName(path);
      this.data = data;
    }
  }
 
  /**
   * Plugin installation:
   * - PluginEntity created
   * - All resources are placed to /plugins/PLUGIN_NAME/
   * - all classes are placed to PluginResourceEntity
   */
  public void install(String filename, byte[] data) throws IOException,
      PluginException, DocumentException {
    Map<String, WarItem> war = readWar(data);
    if (!war.containsKey(VOSAO_PLUGIN)) {
      throw new PluginException(VOSAO_PLUGIN + " not found");
    }
    PluginEntity plugin = readPluginConfig(war.get(VOSAO_PLUGIN));
    if (StringUtils.isEmpty(plugin.getEntryPointClass())) {
      throw new PluginException("Entry point class not defined.");
    }
    PluginEntity p = getDao().getPluginDao().getByName(plugin.getName());
    if (p != null) {
      plugin.setConfigData(p.getConfigData());
      uninstall(p);
    }
    getDao().getPluginDao().save(plugin);
    String pluginBase = "/plugins/" + plugin.getName();
    getBusiness().getFolderBusiness().createFolder(pluginBase);
    List<String> resourceList = new ArrayList<String>();
    List<String> fileCacheList = new ArrayList<String>();
    String filePrefix = pluginBase + "/";
    for (String url : war.keySet()) {
      if (!url.equals(VOSAO_PLUGIN)) {
        WarItem item = war.get(url);
        byte[] fileData = item.data.toByteArray();
        if (url.startsWith("WEB-INF/classes")) {
          resourceList.add(loadClasspathResource(item, plugin));
        }
        if (!url.startsWith("WEB-INF")) {
          String filePath = filePrefix + item.path;
          fileCacheList.add(filePath);
          String folderPath = pluginBase + "/" + FolderUtil.getFilePath(
              item.path);
          FolderEntity folder = getBusiness().getFolderBusiness()
              .createFolder(folderPath);
          FileEntity file = new FileEntity(item.filename,
              item.filename, folder.getId(),
              MimeType.getContentTypeByExt(
                  FolderUtil.getFileExt(item.path)),
              new Date(), fileData.length);
          getDao().getFileDao().save(file, fileData);
          getBusiness().getSystemService().getFileCache().remove(
              filePath);
        }
        if (url.startsWith("WEB-INF/lib") && url.endsWith(".jar")) {
          resourceList.addAll(loadJarFile(item, plugin));
        }
      }
    }
    saveResourceList(plugin, resourceList, fileCacheList);
  }
 
  private String loadClasspathResource(WarItem item, PluginEntity plugin) {
    String ext = FolderUtil.getFileExt(item.path);
    byte[] fileData = item.data.toByteArray();
    String resourceName = item.path.replace("WEB-INF/classes/", "");
    if (ext.equals("class")) {
      resourceName = resourceName.replace('/', '.')
        .replace(".class", "");
    }
    PluginResourceEntity res = getDao().getPluginResourceDao()
        .getByUrl(plugin.getName(), resourceName);
    if (res == null) {
      res = new PluginResourceEntity(plugin.getName(),
          resourceName, fileData);
    }
    else {
      res.setContent(fileData);
    }
    getDao().getPluginResourceDao().save(res);
    getBusiness().getPluginResourceBusiness()
      .updateResourceCache(res);
    return res.getId().toString();
  }

  private List<String> loadJarFile(WarItem file, PluginEntity plugin)
      throws IOException {
    List<String> result = new ArrayList<String>();
    Map<String, WarItem> war = readWar(file.data.toByteArray());
    for (String path : war.keySet()) {
      result.add(loadClasspathResource(war.get(path), plugin));
    }
    return result;
  }
 
  private void saveResourceList(PluginEntity plugin,
      List<String> resourceList, List<String> fileList) {
    String resourceListStr = StrUtil.toCSV(resourceList);
    String fileListStr = StrUtil.toCSV(fileList);
    try {
      getDao().getPluginResourceDao().save(
          new PluginResourceEntity(plugin.getName(),
              plugin.getName() + RESOURCE_LIST,
              resourceListStr.getBytes("UTF-8")));
      getDao().getPluginResourceDao().save(
          new PluginResourceEntity(plugin.getName(),
              plugin.getName() + FILE_LIST,
              fileListStr.getBytes("UTF-8")));
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
  }
 
  private Map<String, WarItem> readWar(byte[] data) throws IOException {
    ByteArrayInputStream inputData = new ByteArrayInputStream(data);
    ZipInputStream in = new ZipInputStream(inputData);
    Map<String, WarItem> map = new HashMap<String, WarItem>();
    ZipEntry entry;
    byte[] buffer = new byte[4096];
    while((entry = in.getNextEntry()) != null) {
      if (!entry.isDirectory()) {
        ByteArrayOutputStream itemData = new ByteArrayOutputStream();
        int len = 0;
        while ((len = in.read(buffer)) > 0) {
          itemData.write(buffer, 0, len);
        }
        WarItem item = new WarItem(entry.getName(), itemData);
        map.put(entry.getName(), item);
      }
    }
    in.close();
    return map;
  }

  private PluginEntity readPluginConfig(WarItem zipItem)
      throws UnsupportedEncodingException, DocumentException {
    PluginEntity result = new PluginEntity();
    Element root = DocumentHelper.parseText(zipItem.data.toString("UTF-8"))
        .getRootElement();
    result.setName(root.elementText("name"))
    result.setTitle(root.elementText("title"));
    result.setVersion(root.elementText("version"));
    result.setDescription(root.elementText("description"));
    result.setWebsite(root.elementText("website"));
    if (root.element("entry-point-class") != null) {
      result.setEntryPointClass(StringUtils.strip(
          root.elementText("entry-point-class")));
    }
    if (root.element("plugin-config-url") != null) {
      result.setConfigURL(StringUtils.strip(
          root.elementText("plugin-config-url")));
    }
    StringBuffer header = new StringBuffer();
    if (root.element("header-javascript") != null) {
      for (Element e : (List<Element>)root.elements("header-javascript")) {
        header.append("<script type=\"text/javascript\" src=\"/file/plugins/")
          .append(result.getName()).append("/").append(e.getText())
          .append("\"></script>\n");
      }
    }
    if (root.element("header-css") != null) {
      for (Element e : (List<Element>)root.elements("header-css")) {
        header.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"/file/plugins/")
          .append(result.getName()).append("/").append(e.getText())
          .append("\"/>\n");
      }
    }
    result.setPageHeader(header.toString());
    if (root.element("config") != null) {
      result.setConfigStructure(root.element("config").asXML());
    }
    return result;
  }

  public void uninstall(PluginEntity plugin) {
    removePluginResources(plugin);
    removePluginFileCache(plugin);
    getBusiness().getFolderBusiness().recursiveRemove(
        "/plugins/" + plugin.getName());
    getDao().getPluginDao().remove(plugin.getId());
  }
 
  private void removePluginResources(PluginEntity plugin) {
    PluginResourceEntity listResource = getDao().getPluginResourceDao()
        .getByUrl(plugin.getName(), plugin.getName() + RESOURCE_LIST);
    if (listResource == null) {
      return;
    }
    List<Long> ids = new ArrayList<Long>();
    ids.add(listResource.getId());
    if (listResource.getContent() != null && listResource.getContent().length > 0) {
      try {
        String list = new String(listResource.getContent(), "UTF-8");
        String[] resources = list.split(",");
        for (String id : resources) {
          ids.add(Long.valueOf(id));
        }
      } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
      }
    }
    getDao().getPluginResourceDao().remove(ids);
  }

  private void removePluginFileCache(PluginEntity plugin) {
    PluginResourceEntity listResource = getDao().getPluginResourceDao()
      .getByUrl(plugin.getName(), plugin.getName() + FILE_LIST);
    if (listResource == null) {
      return;
    }
    getDao().getPluginResourceDao().remove(listResource.getId());
    try {
      String list = new String(listResource.getContent(), "UTF-8");
      String[] resources = list.split(",");
      for (String path : resources) {
        getBusiness().getSystemService().getFileCache().remove(path);
      }
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
  } 
 
  public Dao getDao() {
    return dao;
  }

  public void setDao(Dao dao) {
    this.dao = dao;
  }

  public Business getBusiness() {
    return business;
  }

  public void setBusiness(Business business) {
    this.business = business;
  }
 
}
TOP

Related Classes of org.vosao.business.impl.plugin.PluginLoader

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.