001/* 002 * jPOS Project [http://jpos.org] 003 * Copyright (C) 2000-2026 jPOS Software SRL 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jpos.q2; 020 021import javax.management.*; 022import java.io.File; 023import java.io.FileFilter; 024import java.net.MalformedURLException; 025import java.net.URL; 026import java.net.URLClassLoader; 027import java.security.PrivilegedAction; 028 029/** 030 * Q2 Class Loader (scans deploy/lib directory for new jars) 031 * 032 * @author <a href="mailto:apr@cs.com.uy">Alejandro P. Revilla</a> 033 * @author <a href="mailto:taherkordy@dpi2.dpi.net.ir">Alireza Taherkordi</a> 034 * @version $Revision$ $Date$ 035 */ 036@SuppressWarnings("deprecation") 037public class QClassLoader 038 extends URLClassLoader 039 implements QClassLoaderMBean, FileFilter { 040 File libDir; 041 ObjectName loaderName; 042 MBeanServer server; 043 long lastModified; 044 045 /** 046 * Constructs a Q2 classloader and registers it with the given MBean server. 047 * 048 * @param server MBean server hosting this classloader 049 * @param libDir directory scanned for {@code .jar} files 050 * @param loaderName JMX name under which this loader is registered 051 * @param mainClassLoader parent class loader 052 */ 053 public QClassLoader 054 (MBeanServer server, File libDir, ObjectName loaderName, 055 ClassLoader mainClassLoader) 056 { 057 super(new URL[] { }, mainClassLoader); 058 this.loaderName = loaderName; 059 this.libDir = libDir; 060 this.server = server; 061 } 062 063 public void addURL (String url) throws MalformedURLException { 064 addURL (new URL (url)); 065 } 066 067 public boolean accept (File f) { 068 return f.getName().endsWith (".jar"); 069 } 070 071 /** 072 * Indicates whether the watched lib directory has changed since the last scan. 073 * 074 * @return {@code true} if {@link #libDir} is readable and its mtime has advanced 075 */ 076 public boolean isModified () { 077 return libDir.canRead () && lastModified != libDir.lastModified(); 078 } 079 /** 080 * Re-scans the lib directory, replacing the live class loader if needed, 081 * and returns the up-to-date loader. 082 * 083 * @param forceNewClassLoader force a fresh loader even when the directory is unchanged 084 * @return the (possibly new) classloader 085 * @throws InstanceAlreadyExistsException if the loader can't be re-registered 086 * @throws InstanceNotFoundException if the previous loader can't be unregistered 087 * @throws NotCompliantMBeanException if the loader fails MBean compliance checks 088 * @throws MBeanRegistrationException if MBean (un)registration fails 089 */ 090 public QClassLoader scan (boolean forceNewClassLoader) 091 throws InstanceAlreadyExistsException, 092 InstanceNotFoundException, 093 NotCompliantMBeanException, 094 MBeanRegistrationException 095 096 { 097 if (!isModified () && !forceNewClassLoader || !libDir.canRead()) 098 return this; 099 QClassLoader loader; 100 if (server.isRegistered (loaderName)) { 101 server.unregisterMBean (loaderName); 102 loader = new QClassLoader(server, libDir, loaderName, getParent()); 103 } else 104 loader = this; 105 106 File file[] = libDir.listFiles (this); 107 for (File aFile : file) { 108 try { 109 loader.addURL(aFile.toURL()); 110 } catch (MalformedURLException e) { 111 e.printStackTrace(); 112 } 113 } 114 loader.lastModified = libDir.lastModified (); 115 server.registerMBean (loader, loaderName); 116 return loader; 117 } 118 /** Forces {@link #scan(boolean)} to instantiate a fresh classloader on its next call. */ 119 public void forceNewClassLoaderOnNextScan() { 120 this.lastModified = 0L; 121 } 122} 123