Forwarding with proper prefix.

Sanjiva.
--- Begin Message ---
Hi,

        I'm trying to convert my previous axis services to axis2 to take
advantage of the async functionalities. Anyhow, I found that the
DeploymentClassLoader used offers very poor performance because it has
to go through all the lib jars for every class even when loading
multiple classes in the same jar all at once. So, I patched my class
using the 0.93 sources. Basically, while it loads the list, it also
loads the content and puts it in a HashMap so that it can directly
define the classes when needed, freeing the memory at the same time. It
does mean that unused classes in the lib jars will have their bytecode
use up memory for nothing, but the gain in performance was more then
wort it, at least in my case. I've attached the modified java file, hope
it can help...

Steve
/*
 * Copyright 2004,2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.axis2.deployment;

import org.apache.axis2.i18n.Messages;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class DeploymentClassLoader extends URLClassLoader {

    //urls which gives to create the classLoader
    private URL[] urls;

    //To keep jar files inside /lib directory in the main jar
    private ArrayList lib_jars_list;

    private HashMap loadedClass;
    private HashMap loadedBytes;


    /**
     * DeploymentClassLoader is exetend form URLClassLoader , and the constructor
     * has not overide the super constroctor , but has done some stuff to find out
     * jar fils inside /lib director
     *
     * @param urls   <code>URL</code>
     * @param parent parent classloader <code>ClassLoader</code>
     */
    public DeploymentClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
        this.urls = urls;
        lib_jars_list = new ArrayList();
        loadedClass = new HashMap();
        loadedBytes = new HashMap();
        findLibJars();
    }

    /**
     * This just search for jar files inside /lib dirctory and if there are any then those
     * will be added to the arraylit (only the name of the jar file)
     */
    private void findLibJars() {
        /**
         * though the URL array can contains one or more urls , I have only consider the
         * first one , that is this classLoader is only for Axis2 stuff and the classloader
         * is created by Deployment , so there wont be any chance to have more the one urls for
         * the URL array list
         */
        File file = new File(urls[0].getFile());
        try {
            ZipInputStream parentZin = new ZipInputStream(new FileInputStream(file));
            ZipEntry parentEntry;
            String parentEntryName;
            while ((parentEntry = parentZin.getNextEntry()) != null) {
                parentEntryName = parentEntry.getName();
                /**
                 * id the entry name start with /lib and end with .jar
                 * then those entry name will be added to the arraylist
                 */
                if (parentEntryName != null && (parentEntryName.startsWith("lib/") ||
                        parentEntryName.startsWith("Lib/")) &&
                        parentEntryName.endsWith(".jar")) {
                        String libjar_name = parentEntryName;
                        InputStream in = this.getResourceAsStream(libjar_name);
                        try {
                            ZipInputStream zin = new ZipInputStream(in);
                            ZipEntry entry;
                            String entryName ;
                            while ((entry = zin.getNextEntry()) != null) {
                                entryName = entry.getName();
                                if (entryName != null && entryName.endsWith(".class")) {
            						String name = entryName.substring(0, entryName.length()-6).replace('/', '.');
                                    if( !loadedClass.containsKey(name) ) {
                						try
                						{
                							Class cla = super.findClass(name);
                							loadedClass.put(name, cla);
                						}
                						catch( ClassNotFoundException ex ){
                                            byte data[] = new byte[2048];
                                            ByteArrayOutputStream out = new ByteArrayOutputStream();
                                            int count;
                                            while ((count = zin.read(data, 0, 2048)) != -1) {
                                                out.write(data, 0, count);
                                            }
            	                        	byte[] tmpRaw = out.toByteArray();
                                            out.close();
           		                            loadedBytes.put(name, tmpRaw);
            							}
            	                    }
                                }
                            }
                            zin.close();
                        } catch (IOException e) {
                            throw e;
                        }

                }
            }
            parentZin.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param name <code>String</code>  Name of the file to be loaded
     * @return <code>Class</code> return a class object if it found else
     *         will return null or classNotfoun exeption
     *         <p/>
     *         The method has ovride in the following way
     *         1. called the super class and check to see wether the class is there
     *         if the class is found then return that , else if super returns ClassNotfoundExeption
     *         2. Check wether the entry corresponding to the class name exsit in one of jar files
     *         in /lib director
     *         3. If it is there get the byte array out of that and creat a Class object out of that
     *         by calling "defineClass()" , if it sucssed then return that else
     *         4. Throw classNotfound exeption
     * @throws ClassNotFoundException
     */
    protected Class findClass(final String name)
            throws ClassNotFoundException {
        Class cla ;
        try {
            cla = (Class)loadedClass.get(name);
            if(cla != null){
                return cla;
            }
            boolean foundClass ;
            try {
                cla = super.findClass(name);
                loadedClass.put(name, cla);
                loadedBytes.remove(name);
                return cla;
            } catch (ClassNotFoundException e) {
                foundClass = false;
            }
            if (!foundClass) {
                try {
                    byte raw[] = getBytes(name);
                    cla = defineClass(name, raw, 0, raw.length);
                    loadedClass.put(name, cla);
                    return cla;
                } catch (Exception e) {
                    foundClass = false;
                } catch (ClassFormatError classFormatError) {
                    foundClass = false;
                }
            }
            if (!foundClass) {
                throw new ClassNotFoundException(Messages.getMessage(
                        DeploymentErrorMsgs.CLASS_NOT_FOUND, name));
            }

        } catch (Exception e) {
             throw new ClassNotFoundException(Messages.getMessage(
                        DeploymentErrorMsgs.CLASS_NOT_FOUND, name));
        }
        return null;
    }

    /**
     * Read jar file (/lib) one by one , then for each file craete <code>ZipInputStream</code>
     * that and check to see wether there is any entry eith given name if it found then
     * Creat ByteArrayOutPutStream and get the class bytes to that .
     * after goning throgh each and evry jar file if there is no entry with given name
     * will throug a ClassNotFound execption
     *
     * @param filename <code>String</code>  Name of the file to be loaded (Class Name)
     * @return bytt[]
     * @throws java.io.IOException <code>Exception</code>
     */
    private byte[] getBytes(String filename) throws Exception {
        byte raw[] = null;
    	if( loadedBytes.containsKey(filename) )
    		raw = (byte[]) loadedBytes.remove(filename);

    	if( raw == null )
        	throw new ClassNotFoundException(Messages.getMessage(
                DeploymentErrorMsgs.CLASS_NOT_FOUND, filename));
        
        return raw;
    }
}


--- End Message ---

Reply via email to