/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2005 Bull S.A.
 * Contact: jonas-team@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id:JClassLoader.java 10822 2007-07-04 08:26:06Z durieuxp $
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.lib.bootstrap.loader;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * This class implements a URLClassLoader, that permits to add some URLs in it.
 * @author Ludovic Bert
 * @author Florent Benoit
 */
public class JClassLoader extends URLClassLoader {

    /**
     * JClassLoader name
     */
    private String name = null;

    /**
     * Need to recompute toString() value ? (urls have changed)
     * True by default (not done).
     * Then, compute is done only when required and if needed
     */
    private boolean recomputeToString = true;

    /**
     * Need to recompute getClassPath() value ? (urls have changed)
     * True by default (not done).
     * Then, compute is done only when required and if needed
     */
    private boolean recomputeClassPath = true;

    /**
     * String representation used by toString() method
     */
    private String toStringValue = null;

    /**
     * Classpath value
     */
    private String classpath = null;

    /**
     * Constructs a new ClassLoader with the specified URLs.
     * @param name ClassLoader name (used for Display)
     * @param urls the URLs to add at the ClassLoader creation.
     * @param parent parent ClassLoader, null if no parent.
     */
    public JClassLoader(String name, URL[] urls, ClassLoader parent) {
        super(urls, parent);
        this.name = name;
        this.recomputeToString = true;
        this.recomputeClassPath = true;
    }

    /**
     * Constructs a new ClassLoader with the specified URLs.
     * Uses the default delegation parent classloader.
     * @param name ClassLoader name (used for Display)
     * @param urls the URLs to add at the ClassLoader creation.
     */
    public JClassLoader(String name, URL[] urls) {
        super(urls, Thread.currentThread().getContextClassLoader());
        this.name = name;
        this.recomputeToString = true;
        this.recomputeClassPath = true;
    }

    /**
     * Add the specified URL to this ClassLoader.
     * @param url the URL to add to this ClassLoader.
     */
    public void addURL(URL url) {
        if (url != null) {
            super.addURL(url);
        }
        this.recomputeToString = true;
        this.recomputeClassPath = true;
    }

    /**
     * Add the specified URLs to this ClassLoader.
     * @param urls the URLs to add to this ClassLoader.
     */
    public void addURLs(URL[] urls) {
        if (urls != null) {
            for (int i = 0; i < urls.length; i++) {
                if (urls[i] != null) {
                    super.addURL(urls[i]);
                }
            }
        }
        this.recomputeToString = true;
        this.recomputeClassPath = true;
    }

    /**
     * Display all the URLs from the class loader
     */
    public void printURLs() {
        System.out.println(name  + " ClassLoader :");
        URL[] urls = super.getURLs();
        for (int i = 0; i < urls.length; i++) {
            System.out.println("url=" + (new File(urls[i].getFile())).getAbsolutePath());
        }
        // display parent classloader
        if (getParent() != null && getParent() instanceof JClassLoader) {
            System.out.println("parent :");
            ((JClassLoader) getParent()).printURLs();
        }
    }

    /**
     * Get the class path of this classloader
     * @return the class path of this classloader
     */
    public String getClassPath() {
        // urls have changed, need to build value
        if (recomputeClassPath) {
            computeClassPath();
        }
        return classpath;
    }

    /**
     * Displays useful information
     * @return information
     */
    public String toString() {
        // urls have changed, need to build value
        if (recomputeToString) {
            computeToString();
        }
        return toStringValue;
    }

    /**
     * Compute a string representation used by toString() method
     */
    private void computeToString() {
        StringBuffer sb = new StringBuffer();
        sb.append(this.getClass().getName());
        sb.append("[");
        sb.append(name);
        sb.append(", urls=");
        URL[] urls = getURLs();
        for (int u = 0; u < urls.length; u++) {
            sb.append(urls[u]);
            if (u != urls.length - 1) {
                sb.append(";");
            }
        }
        sb.append("]");
        toStringValue = sb.toString();

        // value is updated, no need to do it again.
        recomputeToString = false;
   }

    /**
     * Compute classpath value
     */
    private void computeClassPath() {
        String cp = "";
        // add parent classpath before
        if (getParent() != null && getParent() instanceof JClassLoader) {
            cp += ((JClassLoader) getParent()).getClassPath();
        }
        URL[] urls = super.getURLs();
        for (int i = 0; i < urls.length; i++) {
            cp = cp + File.pathSeparator + (new File(urls[i].getFile())).getAbsolutePath();
        }
        classpath = cp;
        // update value
        recomputeClassPath = false;
    }


}
