Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Загрузка библиотеки из программы


Автор: Andyb 26.5.2005, 08:54
Вопрос собственно вот в чем:
Есть программа которая должна загрузить библиотеки
(*.zip и *.jar), а затем использовать их классы.
!java - classpath не подходит, т.к. программка работает через webStart!
... smile если можно

Автор: Domestic Cat 26.5.2005, 09:16
Не совсем понятно - откуда загрузить? Где архивы ?

Автор: Andyb 26.5.2005, 09:35
Цитата
Где архивы ?

архивы на локальной машине - С:\\SQLLIB\java\db2java.zip например

Автор: tux 26.5.2005, 09:43
Если речь идет об изменении classpath на лету, могу предложить реализацию расширяемого класс-лоудера.
Код

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

/**
 * Класс реализует <code>ClassLoader</code>, позволяющий динамически расширять
 * маршрут поиска классов и ресурсов 
 */
public class ExtendableClassLoader extends ClassLoader implements Serializable {

    private Hashtable cache;

    private ArrayList paths;

    private ClassLoader currentLoader = null;

    public ExtendableClassLoader() {
        cache = new Hashtable();
        paths = new ArrayList();
    }

    /**
     * Устанавливает новый загрузчик классов для текущего потока, используя 
     * данный экземпляр класса расширенного загрузчика. Перед установкой
     * выполняется проверка не был ли уже установлен такой загрузчик
     */    
    public void setCurrentThreadClassLoader() {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        if (loader instanceof ExtendableClassLoader) return;
        else {
            currentLoader = loader;
            Thread.currentThread().setContextClassLoader(this);
        }
    }
    
    /**
     * Добавляет строку в CLASSPATH
     * @param path Добавляемая строка
     */
    public void addClassPath(String path) {
        paths.add(path);
    }

    /**
     * Удаляет строку из CLASSPATH
     * @param path Удаляемая строка
     */
    public void removeClassPath(String path) {
        int index = paths.indexOf(path);
        paths.remove(index);
    }

    /**
     * Преобразует имя пакета в путь к каталогу
     * @param className преобразуемое имя класса
     * @return полученное имя файла
     */
    private String classNameToFileName(String className) {
        return className.replace(
            '.',
            System.getProperty("file.separator").charAt(0))
            + ".class";
    }

    /**
     * Метод ищет класс в созданном CLASSPATH и возвращает массив байтов
     * @param className the class to load
     * @return a byte array containing the byte code of the class
     */
    private byte[] getClassFromAddedClassPaths(String className) {
        
        try {
            ByteArrayOutputStream st = new ByteArrayOutputStream();
            String fsep = System.getProperty("file.separator");
            String fileName = classNameToFileName(className);

            // Поиск класса в добавленных путях поиска
            for (Iterator e = paths.iterator(); e.hasNext();) {
                String path = (String) e.next();
                File pathFile = new File(path);
                if (pathFile.isDirectory()) {
                    File f = new File(path + fsep + fileName);
                    if (f.exists()) {
                        FileInputStream fis = new FileInputStream(f);
                        log.info("Class "+className+" was found in "+path);
                        int length = fis.available();
                        return createByteArray(fis);
                    }
                } else {
                    JarFile jarFile = new JarFile(pathFile);
                    ZipEntry entry = jarFile.getEntry(fileName);
                    if (entry == null) continue;
                    InputStream stream = jarFile.getInputStream(entry);
                    log.info("Class "+className+" was found in "+path);
                    int length = stream.available();
                    return createByteArray(stream);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * Создает массив байтов из входного потока
     * @param in Входной поток
     * @return Массив байтов
     * @throws IOException
     */
    private byte[] createByteArray(InputStream in) throws IOException {
        final int bufferSize = 2048;
        byte result[] = new byte[bufferSize];
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int len = 0;
        while ((len = in.read(result)) != -1) out.write(result, 0, len);
        return out.toByteArray();
    }

    protected URL findResource(String name) {
        byte result[] = null;
        
        URL res = ClassLoader.getSystemResource(name);
        if (res != null) return res;

        try {
            String fsep = System.getProperty("file.separator");

            // Поиск ресура в добавленных маршрутах поиска
            for (Iterator e = paths.iterator(); e.hasNext();) {
                String path = (String) e.next();
                File pathFile = new File(path);
                if (pathFile.isDirectory()) {
                    File f = new File(path + fsep + name);
                    if (f.exists()) return f.toURL();
                } else {
                    JarFile jarFile = new JarFile(pathFile);
                    ZipEntry entry = jarFile.getEntry(name);
                    if (entry == null) return null;
                    String url = createJarResourceURL(pathFile, name, fsep);
                    return new URL(url);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    private String createJarResourceURL(File jarFile, String resourceName, String fsep) throws MalformedURLException {
        String url = "jar:" + jarFile.toURL() + "!" + fsep + resourceName;
        return url; 
    }

    /**
     * @see java.lang.ClassLoader#findClass(java.lang.String)
     */
    protected synchronized Class findClass(String className) throws ClassNotFoundException {
        Class result;
        byte classData[];
        
        log.info("Class to be found: "+className);

        // Проверяем кэш классов. Если класса в кэше нет, тогда применяются другие средства
        result = (Class) cache.get(className);
        if (result != null) {
            return result;
        }

        // Проверяется нет ли такого класса в стандартном пути 
        try {
            // если загрузчик классов текущего потока уже является расширенным,
            // используем сохраненное значение загрузчика классов
            if (Thread.currentThread().getContextClassLoader() instanceof ExtendableClassLoader) {
                if (this.currentLoader == null) throw new ClassNotFoundException();
                else result = this.currentLoader.loadClass(className);
            } else
                result = Thread.currentThread().getContextClassLoader().loadClass(className);
            return result;
        } catch (ClassNotFoundException e) {
            log.info("Class was not found in the default classloader");
        } catch (Exception e) {
            log.info("Exception happens: "+e.getStackTrace());
        }

        // Попытка загрузить класс из добавленного пути
        classData = getClassFromAddedClassPaths(className);
        if (classData == null) {
            throw new ClassNotFoundException();
        }

        // определение класса
        result = super.defineClass(className, classData, 0, classData.length);
        if (result == null) throw new ClassFormatError();

        resolveClass(result);

        // Полученный класс добавляется в кэш классов
        cache.put(className, result);

        return result;
    }

}


Автор: Domestic Cat 26.5.2005, 09:49
А почему их нельжя распространять вместе с самим приложением?

Посмотри тут
http://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/syntax.html#resources

и вообще
http://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/faq.html

Автор: Andyb 26.5.2005, 10:13
Цитата
А почему их нельжя распространять вместе с самим приложением?

В связи с переходом на новую версию базы данных получилась такая ситуация:
у одних стоит старая клиентская часть,которая не работает с новыми библиотеками, у других новая,которая не работает со старыми, а указать могу только одну...

Цитата
реализацию расширяемого класс-лоудера.

надо попробовать! СПАСИБО!

Автор: Andyb 26.5.2005, 10:25
Код

....
ExtendableClassLoader cl = new ExtendableClassLoader();
      cl.addClassPath("C:/SQLLIB/java/db2java.zip");
....

и такой облом:
The driver: COM.ibm.db2.jdbc.app.DB2Driver could not be loaded. This could be a problem with the driver itself, or that the driver is not found on the classpath.

при запуске, может что не так делаю? smile

Автор: Domestic Cat 26.5.2005, 10:31
А у него права есть читать с локальной машины?

Автор: tux 26.5.2005, 10:41
Попробуй установить класслоудер текущего потока
Код

public void setCurrentThreadClassLoader();

или грузить нужные классы таким способом:
Код

ExtendableClassLoader loader = new ExtendableClassLoader();
...
Object obj = loader.loadClass(className).newInstance();


Автор: Andyb 26.5.2005, 10:44
Цитата
А у него права есть читать с локальной машины?

права есть, причем полные-в jnlp файле определяются

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)