001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.jci; 019 020 import java.io.InputStream; 021 import java.net.URL; 022 023 import org.apache.commons.jci.listeners.ReloadNotificationListener; 024 import org.apache.commons.jci.stores.ResourceStore; 025 import org.apache.commons.jci.stores.ResourceStoreClassLoader; 026 import org.apache.commons.logging.Log; 027 import org.apache.commons.logging.LogFactory; 028 029 /** 030 * The ReloadingClassLoader uses a delegation mechansim to allow 031 * classes to be reloaded. That means that loadClass calls may 032 * return different results if the class was changed in the underlying 033 * ResourceStore. 034 * 035 * @author tcurdt 036 */ 037 public class ReloadingClassLoader extends ClassLoader implements ReloadNotificationListener { 038 039 private final Log log = LogFactory.getLog(ReloadingClassLoader.class); 040 041 private final ClassLoader parent; 042 private ResourceStore[] stores = new ResourceStore[0]; 043 private ClassLoader delegate; 044 045 public ReloadingClassLoader( final ClassLoader pParent ) { 046 super(pParent); 047 parent = pParent; 048 049 delegate = new ResourceStoreClassLoader(parent, stores); 050 } 051 052 public boolean addResourceStore( final ResourceStore pStore ) { 053 try { 054 final int n = stores.length; 055 final ResourceStore[] newStores = new ResourceStore[n + 1]; 056 System.arraycopy(stores, 0, newStores, 1, n); 057 newStores[0] = pStore; 058 stores = newStores; 059 delegate = new ResourceStoreClassLoader(parent, stores); 060 return true; 061 } catch ( final RuntimeException e ) { 062 log.error("could not add resource store " + pStore); 063 } 064 return false; 065 } 066 067 public boolean removeResourceStore( final ResourceStore pStore ) { 068 069 final int n = stores.length; 070 int i = 0; 071 072 // FIXME: this should be improved with a Map 073 // find the pStore and index position with var i 074 while ( ( i < n ) && ( stores[i] != pStore ) ) { 075 i++; 076 } 077 078 // pStore was not found 079 if ( i == n ) { 080 return false; 081 } 082 083 // if stores length > 1 then array copy old values, else create new empty store 084 final ResourceStore[] newStores = new ResourceStore[n - 1]; 085 if (i > 0) { 086 System.arraycopy(stores, 0, newStores, 0, i); 087 } 088 if (i < n - 1) { 089 System.arraycopy(stores, i + 1, newStores, i, (n - i - 1)); 090 } 091 092 stores = newStores; 093 delegate = new ResourceStoreClassLoader(parent, stores); 094 return true; 095 } 096 097 public void handleNotification() { 098 log.debug("reloading"); 099 delegate = new ResourceStoreClassLoader(parent, stores); 100 } 101 102 @Override 103 public void clearAssertionStatus() { 104 delegate.clearAssertionStatus(); 105 } 106 @Override 107 public URL getResource(String name) { 108 return delegate.getResource(name); 109 } 110 @Override 111 public InputStream getResourceAsStream(String name) { 112 return delegate.getResourceAsStream(name); 113 } 114 @Override 115 public Class<?> loadClass(String name) throws ClassNotFoundException { 116 return delegate.loadClass(name); 117 } 118 @Override 119 public void setClassAssertionStatus(String className, boolean enabled) { 120 delegate.setClassAssertionStatus(className, enabled); 121 } 122 @Override 123 public void setDefaultAssertionStatus(boolean enabled) { 124 delegate.setDefaultAssertionStatus(enabled); 125 } 126 @Override 127 public void setPackageAssertionStatus(String packageName, boolean enabled) { 128 delegate.setPackageAssertionStatus(packageName, enabled); 129 } 130 }