/* * * Copyright 2005 AgileTec s.r.l. (http://www.agiletec.it) All rights reserved. * * This file is part of JAPS software. * JAPS and its source-code is licensed under the terms of the * GNU General Public License as published by the Free Software * Foundation (http://www.fsf.org/licensing/licenses/gpl.txt). * * You may copy, adapt, and redistribute this file for commercial * or non-commercial use. * When copying, adapting, or redistributing this document you * are required to provide proper attribution to AgileTec, using * the following attribution line: * Copyright 2005 AgileTec s.r.l. (http://www.agiletec.it) All rights reserved. * */ package com.agiletec.apsadmin.system.resource; import java.io.InputStream; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import com.agiletec.aps.system.ApsSystemUtils; import com.opensymphony.xwork2.util.LocalizedTextUtil; /** * This listener is used to add the properties of the plugins menu to the default resource bundles. * Note: this listener distinguishes between plugins under development and standard ones, that is, * those plugins found in the WEB-INF/classes/ directory and those normally installed in the * WEB-INF/lib/ in the form of JAR files. * Apart the 'plugins' contained in the package, we rely on the 'apsadmin' being present soon * after the plugin name in the URL to distinguish between jAPS plugins and the others eventually * contained in the system libraries. * * @author M. Minnai */ public class JapsPluginLabelListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent event) { Set<String> jaredPlugins = new HashSet<String>(); Set<String> classPlugins = new HashSet<String>(); classPlugins = discoverClasses(TOMCAT_CLASSES, event); jaredPlugins = discoverJars(TOMCAT_LIB, event); Iterator<String> itr = classPlugins.iterator(); while (itr.hasNext()) { String cur = itr.next(); ApsSystemUtils.getLogger().info("Trying to load resources under development @ "+cur); LocalizedTextUtil.addDefaultResourceBundle(cur+this.PLUGIN_RESOURCE_NAME); } itr = jaredPlugins.iterator(); while (itr.hasNext()) { String cur = itr.next(); ApsSystemUtils.getLogger().info("Trying to load resources @ "+cur); LocalizedTextUtil.addDefaultResourceBundle(cur+this.PLUGIN_RESOURCE_NAME); } ApsSystemUtils.getLogger().info("JapsPluginLabelListener summary: "+(classPlugins.size()+jaredPlugins.size())+" plugin detected ("+classPlugins.size()+" under development)"); } /** * Discover the directories holding plugins within the classpath * @param path the path where to start the search from * @param event the servlet context event */ private Set<String> discoverClasses(String path, ServletContextEvent event) { Set<String> plugins = new HashSet<String>(); if (null==path || event==null) return plugins; Set<String> directory = event.getServletContext().getResourcePaths(path); if (null != directory && !directory.isEmpty()) { Iterator<String> itr = directory.iterator(); while (itr.hasNext()) { String currentDirectory=itr.next(); boolean skip = false; // AVOID USELESS LOOPS IF POSSIBLE Iterator<String> exclude = _plugin_exclusion_directories.iterator(); while (exclude.hasNext()) { String currentDirectoryExcluded = exclude.next(); if (currentDirectory.contains(currentDirectoryExcluded) && !currentDirectory.contains(PLUGIN_DIRECTORY)) { skip = true; break; } } if (skip) continue; if (currentDirectory.contains(PLUGIN_DIRECTORY) && currentDirectory.endsWith(PLUGIN_APSADMIN_PATH)) { currentDirectory = currentDirectory.replaceFirst(TOMCAT_CLASSES, ""); plugins.add(currentDirectory); } else { plugins.addAll(discoverClasses(currentDirectory, event)); } } } return plugins; } private Set<String> discoverJars(String path, ServletContextEvent event) { Set<String> plugins = new HashSet<String>(); Set<String> directory = event.getServletContext().getResourcePaths(path); Iterator<String> itr = directory.iterator(); // ITERATE OVER PATHS while (null != itr && itr.hasNext()) { String currentJar = itr.next(); InputStream is=event.getServletContext().getResourceAsStream(currentJar); plugins.addAll(discoverJarPlugin(is)); } return plugins; } /** * Fetch all the entries in the given (jar) input stream and look for the * plugin directory. * @param is the input stream to analyse */ private Set<String> discoverJarPlugin(InputStream is) { Set<String> plugins = new HashSet<String>(); if (null==is) return plugins; JarEntry je = null; try { JarInputStream jis = new JarInputStream(is); do { je = jis.getNextJarEntry(); if (null != je) { String URL=je.toString(); if (URL.contains(PLUGIN_DIRECTORY) && URL.endsWith(PLUGIN_APSADMIN_PATH)) { plugins.add(URL); } } } while (je != null); } catch (Throwable t) { ApsSystemUtils.logThrowable(t, this, "discoverJarPlugin"); } return plugins; } @Override public void contextDestroyed(ServletContextEvent arg0) { // nothing to do } /** * This contains all the directories to exclude from the recursive search when * PLUGIN_DIRECTORY does NOT exist in the URL or path */ private List<String> _plugin_exclusion_directories = Arrays.asList("/test/", "/aps/", "/apsadmin/"); /** * Path within the plugin where the global properties are stored. */ private final String PLUGIN_APSADMIN_PATH = "/apsadmin/"; /** * Path to the global properties file within the plugin package */ private final String PLUGIN_RESOURCE_NAME = "global-messages"; /** * This is the directory where plugins are searched */ private final String PLUGIN_DIRECTORY = "plugins"; /** * The URL of Tomcat classes */ private String TOMCAT_CLASSES = "/WEB-INF/classes/"; /** * The URL of the Tomcat shared lib directory */ private String TOMCAT_LIB = "/WEB-INF/lib/"; }