    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    }