Java tutorial
/* * RHQ Management Platform * Copyright (C) 2005-2009 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.server.core.plugin; import java.io.File; import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.rhq.core.clientapi.agent.metadata.PluginMetadataManager; import org.rhq.core.clientapi.descriptor.AgentPluginDescriptorUtil; import org.rhq.core.util.MessageDigestGenerator; import org.rhq.core.util.exception.ThrowableUtil; import org.rhq.core.util.file.FileUtil; import org.rhq.enterprise.server.util.LoggingThreadFactory; import org.rhq.enterprise.server.xmlschema.ServerPluginDescriptorUtil; /** * This looks at both the file system and the database for new agent and server plugins. * * @author John Mazzitelli */ public class PluginDeploymentScanner implements PluginDeploymentScannerMBean { private Log log = LogFactory.getLog(PluginDeploymentScanner.class); /** time, in millis, between each scans */ private long scanPeriod = 300000L; /** handles the scheduled scanning */ private ScheduledExecutorService poller; /** where the user can copy agent or server plugins */ private File userPluginDir = null; /** what looks for new or changed agent plugins */ private AgentPluginScanner agentPluginScanner = new AgentPluginScanner(); /** what looks for new or changed agent plugins */ private ServerPluginScanner serverPluginScanner = new ServerPluginScanner(); @NotNull public Long getScanPeriod() { return this.scanPeriod; } public void setScanPeriod(@Nullable Long ms) { if (ms != null) { this.scanPeriod = ms; } else { this.scanPeriod = 300000L; } } public File getUserPluginDir() { return this.userPluginDir; } public void setUserPluginDir(File dir) { this.userPluginDir = dir; } public File getServerPluginDir() { return this.serverPluginScanner.getServerPluginDir(); } public void setServerPluginDir(File dir) { this.serverPluginScanner.setServerPluginDir(dir); } public File getAgentPluginDir() { return this.agentPluginScanner.getAgentPluginDeployer().getPluginDir(); } public void setAgentPluginDir(File dir) { this.agentPluginScanner.getAgentPluginDeployer().setPluginDir(dir); } public PluginMetadataManager getPluginMetadataManager() { return this.agentPluginScanner.getAgentPluginDeployer().getPluginMetadataManager(); } public void start() throws Exception { // This will check to see if there are any agent plugin records in the database // that do not have content associated with them and if so, will stream // the content from the file system to the database. This is needed only // in the case when this server has recently been upgraded from an old // version of the software that did not originally have content stored in the DB. // Once we do that, we can start the agent plugin deployer. this.agentPluginScanner.fixMissingAgentPluginContent(); this.agentPluginScanner.getAgentPluginDeployer().start(); shutdownPoller(); // paranoia - just in case somehow one is still running this.poller = Executors.newSingleThreadScheduledExecutor(new LoggingThreadFactory("PluginScanner", true)); return; } public void stop() { this.agentPluginScanner.getAgentPluginDeployer().stop(); shutdownPoller(); return; } private void shutdownPoller() { if (this.poller != null) { this.poller.shutdownNow(); this.poller = null; } return; } public void startDeployment() { // We are being called by the server's startup servlet which essentially informs us that // the server's internal EJB/SLSBs are ready and can be called. This means we are allowed to start. // NOTE: Make sure we are called BEFORE the master plugin container is started! this.agentPluginScanner.getAgentPluginDeployer().startDeployment(); // this is the runnable task that executes each scan period - it runs in our thread pool Runnable runnable = new Runnable() { public void run() { try { scanAndRegister(); } catch (Throwable t) { log.error("Scan failed. Cause: " + ThrowableUtil.getAllMessages(t)); if (log.isDebugEnabled()) { log.debug("Scan failure stack trace follows:", t); } } } }; // do the initial scan now runnable.run(); // schedule it to run periodically from here on out this.poller.scheduleWithFixedDelay(runnable, this.scanPeriod, this.scanPeriod, TimeUnit.MILLISECONDS); return; } public synchronized void scan() throws Exception { // The user directory is a simple location for the user to put all plugins in. // It makes it easy for the user to know where to put the plugins without // having to know the internal location for the real plugins under the ear. // Now we move the user's plugins to their real location in the ear. scanUserDirectory(); // scan for agent plugins this.agentPluginScanner.agentPluginScan(); // scan for server plugins this.serverPluginScanner.serverPluginScan(); return; } public synchronized void scanAndRegister() throws Exception { // do the scan first to find any new/updated plugins scan(); // now tell the agent plugin scanner to register plugins that it determined needs to be registered this.agentPluginScanner.registerAgentPlugins(); // tell the server plugin scanner the same this.serverPluginScanner.registerServerPlugins(); } /** * Take the plugins placed in the user directory, and copy them to their apprpriate places * in the server. */ private void scanUserDirectory() { File userDir = getUserPluginDir(); if (userDir == null || !userDir.isDirectory()) { return; // not configured for a user directory, just return immediately and do nothing } File[] listFiles = userDir.listFiles(); if (listFiles == null || listFiles.length == 0) { return; // nothing to do } for (File file : listFiles) { File destinationDirectory; if (file.getName().endsWith(".jar")) { try { if (null == AgentPluginDescriptorUtil.loadPluginDescriptorFromUrl(file.toURI().toURL())) { throw new NullPointerException("no xml descriptor found in jar"); } destinationDirectory = getAgentPluginDir(); } catch (Exception e) { try { log.debug("[" + file.getAbsolutePath() + "] is not an agent plugin jar (Cause: " + ThrowableUtil.getAllMessages(e) + "). Will see if its a server plugin jar"); if (null == ServerPluginDescriptorUtil.loadPluginDescriptorFromUrl(file.toURI().toURL())) { throw new NullPointerException("no xml descriptor found in jar"); } destinationDirectory = getServerPluginDir(); } catch (Exception e1) { // skip it, doesn't look like a valid plugin jar File fixmeFile = new File(file.getAbsolutePath() + ".fixme"); boolean renamed = file.renameTo(fixmeFile); log.warn("Does not look like [" + (renamed ? fixmeFile : file).getAbsolutePath() + "] is a plugin jar -(Cause: " + ThrowableUtil.getAllMessages(e1) + "). It will be ignored. Please fix that file or remove it."); continue; } } try { String fileMd5 = MessageDigestGenerator.getDigestString(file); File realPluginFile = new File(destinationDirectory, file.getName()); String realPluginFileMd5 = null; if (realPluginFile.exists()) { realPluginFileMd5 = MessageDigestGenerator.getDigestString(realPluginFile); } if (!fileMd5.equals(realPluginFileMd5)) { if (file.lastModified() > realPluginFile.lastModified()) { FileUtil.copyFile(file, realPluginFile); boolean succeeded = realPluginFile.setLastModified(file.lastModified()); if (!succeeded) { log.error("Failed to set mtime to [" + new Date(file.lastModified()) + "] on file [" + realPluginFile + "]."); } log.info("Found plugin jar at [" + file.getAbsolutePath() + "] and placed it at [" + realPluginFile.getAbsolutePath() + "]"); } } boolean deleted = file.delete(); if (!deleted) { log.info("The plugin jar found at[" + file.getAbsolutePath() + "] has been processed and can be deleted. It failed to get deleted, " + "so it may get processed again. You should delete it manually now."); } } catch (Exception e) { log.error("Failed to process plugin [" + file.getAbsolutePath() + "], ignoring it", e); } } } return; } }