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 }