Java Web Start+передача класса по сети ClassCircularityError
От: Волк-Призрак Россия http://ghostwolf.newmail.ru
Дата: 29.11.04 16:16
Оценка:
передача класса по сети (изза проблем со Swing передаю форму как файл класса [прямого наследника класса, который есть на сервере и клиенте]). Когда запускаешь программу-клиент просто как jar-файл, всё работает (класс передаётся, загружается из сырой памяти и внедряется (создаётся экземпляр объекта этого класса).
Когда запускаешь клиента через Java Web Start, при вызове "собирателя класса" (метод defineClass), он выбрасывает ClassCircularityError и в качестве класса-причины указывается класс-предок (тот базовый класс, который есть на сервере и на клиенте).
while(Life.getClass().getClassLoader()==Religion.GOD){Life.be();};
Скажи .net корпорации Microsoft! (c) ghostwolf 2004
7 раз поищи в стандартной библиотеке, 1 раз накодь своё.
Re: Java Web Start+передача класса по сети ClassCircularityE
От: dshe  
Дата: 30.11.04 08:39
Оценка:
Здравствуйте, Волк-Призрак, Вы писали:

ВП>передача класса по сети (изза проблем со Swing передаю форму как файл класса [прямого наследника класса, который есть на сервере и клиенте]). Когда запускаешь программу-клиент просто как jar-файл, всё работает (класс передаётся, загружается из сырой памяти и внедряется (создаётся экземпляр объекта этого класса).

ВП>Когда запускаешь клиента через Java Web Start, при вызове "собирателя класса" (метод defineClass), он выбрасывает ClassCircularityError и в качестве класса-причины указывается класс-предок (тот базовый класс, который есть на сервере и на клиенте).

Можешь привести код, а то не совсем понятно, что там у тебя происходит. Вполне возможно, что класслоадер бросает исключение (в defineClass) потому, что класс уже был загружен.
--
Дмитро
Re[2]: Java Web Start+передача класса по сети ClassCirculari
От: Волк-Призрак Россия http://ghostwolf.newmail.ru
Дата: 30.11.04 10:40
Оценка:
Здравствуйте, dshe, Вы писали:

ВП>>передача класса по сети (изза проблем со Swing передаю форму как файл класса [прямого наследника класса, который есть на сервере и клиенте]). Когда запускаешь программу-клиент просто как jar-файл, всё работает (класс передаётся, загружается из сырой памяти и внедряется (создаётся экземпляр объекта этого класса).

ВП>>Когда запускаешь клиента через Java Web Start, при вызове "собирателя класса" (метод defineClass), он выбрасывает ClassCircularityError и в качестве класса-причины указывается класс-предок (тот базовый класс, который есть на сервере и на клиенте).

D>Можешь привести код, а то не совсем понятно, что там у тебя происходит. Вполне возможно, что класслоадер бросает исключение (в defineClass) потому, что класс уже был загружен.


Огромное спасибо за напоминание о возможности "повтороной" загрузки того, что уже загружено или уже есть у клиента.
Вот исправленная версия класса BytesClassLoader:


/*
(c) 2004 Константин Николаевич Исаев aka Ghostwolf, Волк-Призрак. ghostwolf@inbox.ru
Если кому нужно - пользуйте на здоровье, хоть в коммерческих целях, хоть в личных. но
патентовать и иным способом присваивать права на эту и созданную на её основе 
интеллектуальную собственость не разрешаю.
Данный исходный текст разрешаю к распространению в случае неизменности данной записи
об авторском праве и условиях распространения, и самого исходного текста. 
*/

public final class BytesClassLoader extends ClassLoader {

private byte[] bytes=null;

public Class findClass(String name) {
try
{
return getClass().forName(name);
}catch(Throwable err)
  {}
Class c=defineClass(name,bytes,0,bytes.length);
resolveClass(c);
return c;
}

public BytesClassLoader(byte[] classfilebytes){
super();
bytes=classfilebytes;
}

}


А вот класс, который используется как часть "протокола" — "генератор" байтовых блоков с классами):

/*
(c) 2004 Константин Николаевич Исаев aka Ghostwolf, Волк-Призрак. ghostwolf@inbox.ru
Если кому нужно - пользуйте на здоровье, хоть в коммерческих целях, хоть в личных. но
патентовать и иным способом присваивать права на эту и созданную на её основе 
интеллектуальную собственость не разрешаю.
Данный исходный текст разрешаю к распространению в случае неизменности данной записи
об авторском праве и условиях распространения,  и самого исходного текста.*/


import java.lang.*;
import java.io.*;
import java.net.*;
public final class SerializedClass implements Serializable {


private byte[] data=null;

public boolean isValid(){return (data!=null)&&(data.length>0);}

public SerializedClass(final Class theclass) throws NullPointerException,IOException
{
if (theclass==null) throw new NullPointerException("SerializedClass: Не выбран класс для сериализации");
ClassLoader cl=getClass().getClassLoader();
StringBuffer cn=new StringBuffer(theclass.getName());
for(int i=0;i<cn.length();i++){
if(cn.charAt(i)=='.'){cn.setCharAt(i,'/');}
}
String scn=cn.toString()+".class";
System.out.println("Searching for class "+scn);
URL clurl=cl.getResource(scn);
if(clurl==null)
 clurl=cl.getSystemResource(scn);
if(clurl==null)
  throw new NullPointerException("Нет возможности получить файл класса.");
URLConnection clurlconn=clurl.openConnection();
int len=clurlconn.getContentLength();
byte[] buffer=new byte[len];
InputStream clis=clurlconn.getInputStream();
int bytesreaden=clis.read(buffer);
System.out.println("From the url ["+clurl.toString()+"] readen "+new Integer(bytesreaden)+" of "+new Integer(buffer.length)+" declared bytes." );
if(bytesreaden!=buffer.length) throw new ClassFormatError("From the url ["+clurl.toString()+"] readen "+new Integer(bytesreaden)+" of "+new Integer(buffer.length)+" of declared bytes");
data=buffer;
buffer=null;
clis.close();
}

public Class loadClass() throws IllegalStateException {
if(!isValid()) throw new IllegalStateException("SerializedClass: Класс повреждён при транспортеровке");
return new BytesClassLoader(data).findClass(null);

}

}



Сериализованные классы сами по себе берутся, как ресурсы, из того jar-а, в котором они лежат.
Имя берётся из класса, который подан на сериализацию.
Сначала я писал так:
Class theclass=LoginForm.class;
ObjectOutputStream out=getConnectionOutput();
out.writeobject(theclass);
//и наоборот при получении - readObject итп.

Но так не получилось. вот и переделал в вариант с SerializedClass и BytesClassLoader.
while(Life.getClass().getClassLoader()==Religion.GOD){Life.be();};
Скажи .net корпорации Microsoft! (c) ghostwolf 2004
7 раз поищи в стандартной библиотеке, 1 раз накодь своё.
Re[3]: Java Web Start+передача класса по сети ClassCirculari
От: dshe  
Дата: 30.11.04 12:15
Оценка:
Здравствуйте, Волк-Призрак, Вы писали:

ВП>Здравствуйте, dshe, Вы писали:


ВП>>>передача класса по сети (изза проблем со Swing передаю форму как файл класса [прямого наследника класса, который есть на сервере и клиенте]). Когда запускаешь программу-клиент просто как jar-файл, всё работает (класс передаётся, загружается из сырой памяти и внедряется (создаётся экземпляр объекта этого класса).

ВП>>>Когда запускаешь клиента через Java Web Start, при вызове "собирателя класса" (метод defineClass), он выбрасывает ClassCircularityError и в качестве класса-причины указывается класс-предок (тот базовый класс, который есть на сервере и на клиенте).

Извини, но у меня сложилось впечатление, что ты занимаешься извратом. Вполне возможно, что для решения твоей основной задачи тебе не нужны хитрые мансы с класслоадерами. Если тебе нужно передать класс по сети, то почему бы его не запаковать в jar как и все остальные классы и скачать тем же Web Start'ом?

Опиши проблему со Swing'ом, из-за которой ты решил передавать классы по сети таким образом.
--
Дмитро
Re[4]: Java Web Start+передача класса по сети ClassCirculari
От: Волк-Призрак Россия http://ghostwolf.newmail.ru
Дата: 30.11.04 13:03
Оценка:
Здравствуйте, dshe, Вы писали:

D>Извини, но у меня сложилось впечатление, что ты занимаешься извратом. Вполне возможно, что для решения твоей основной задачи тебе не нужны хитрые мансы с класслоадерами. Если тебе нужно передать класс по сети, то почему бы его не запаковать в jar как и все остальные классы и скачать тем же Web Start'ом?


Дело в том, что я использую Java web start не в полной мере.
Де факто я использую jaws только для того, чтобы получить имя сервера, с которого бралась программа
(BasicService.getCodeBase().getHostName()).
Я хотел, чтобы классы брались из изменяемого во время работы программы источника.
Скажем из папки BOOM/Server/ActionClasses/*.class
где * имя формы для действия, берётся из БД,
Это сейчас имя класса берётся из самого класса. потом это изменю так,
чтобы он не сам класс принимал в конструкторе, а просто имя.


D>Опиши проблему со Swing'ом, из-за которой ты решил передавать классы по сети таким образом.

Сначала я передавал Swing-формы как есть, и принимая, проверял объекты на instanceof.
Но так как swing не приспособлен для long term persistence, согласно документации...
Это выглядело как ошибка при приёме объекта, про разные serial у класса javax.swing.JComponent. — т.е. JComponent в 1.3.1 (версиимя в которой компилирую и запускаю сервер) и в 1.4.2.06 (версия где запускается клиент).
Мне нужна защита от "разных версий свинга" у сервера и у клиента.
И динамизм нужен. Чтобы форму например логина можно было поменять. Или добавить новую — скажем расширенный поиск автомобилейв бд. Без остановки сервера. Копируешь класс формы — и регистрируешь её в бд.
while(Life.getClass().getClassLoader()==Religion.GOD){Life.be();};
Скажи .net корпорации Microsoft! (c) ghostwolf 2004
7 раз поищи в стандартной библиотеке, 1 раз накодь своё.
Re[5]: Java Web Start+передача класса по сети ClassCirculari
От: dshe  
Дата: 30.11.04 13:13
Оценка:
Здравствуйте, Волк-Призрак, Вы писали:

D>>Опиши проблему со Swing'ом, из-за которой ты решил передавать классы по сети таким образом.

ВП>Сначала я передавал Swing-формы как есть, и принимая, проверял объекты на instanceof.
ВП>Но так как swing не приспособлен для long term persistence, согласно документации...
ВП>Это выглядело как ошибка при приёме объекта, про разные serial у класса javax.swing.JComponent. — т.е. JComponent в 1.3.1 (версиимя в которой компилирую и запускаю сервер) и в 1.4.2.06 (версия где запускается клиент).
ВП>Мне нужна защита от "разных версий свинга" у сервера и у клиента.

А java.beans.XMLEncoder/java.beans.XMLDecoder не подошел?
--
Дмитро
Re[6]: Java Web Start+передача класса по сети ClassCirculari
От: Lucker Беларусь http://lucker.intervelopers.com/
Дата: 30.11.04 13:17
Оценка:
Здравствуйте, dshe, Вы писали:

D>А java.beans.XMLEncoder/java.beans.XMLDecoder не подошел?


Так у него в одном месте 1.3 стоит. Надо еще парсер цеплять клиентам
ICQ #333355130
Re[7]: Java Web Start+передача класса по сети ClassCirculari
От: Lucker Беларусь http://lucker.intervelopers.com/
Дата: 30.11.04 13:26
Оценка: 5 (1)
Здравствуйте, Lucker, Вы писали:

D>>А java.beans.XMLEncoder/java.beans.XMLDecoder не подошел?


L>Так у него в одном месте 1.3 стоит. Надо еще парсер цеплять клиентам


Во ляпнул. Там не парсер, там 1.4 надо цеплять, штоб заработало. Тогда нах-ра java.beans.XMLEncoder/java.beans.XMLDecoder?

Не, тут идейный подход нужен, типа LaZZlo
ICQ #333355130
Re[8]: Java Web Start+передача класса по сети ClassCirculari
От: dshe  
Дата: 30.11.04 14:07
Оценка:
Здравствуйте, Lucker, Вы писали:

L>Здравствуйте, Lucker, Вы писали:


D>>>А java.beans.XMLEncoder/java.beans.XMLDecoder не подошел?


L>>Так у него в одном месте 1.3 стоит. Надо еще парсер цеплять клиентам


L>Во ляпнул. Там не парсер, там 1.4 надо цеплять, штоб заработало. Тогда нах-ра java.beans.XMLEncoder/java.beans.XMLDecoder?


И то правда! С java.beans.XMLEncoder/java.beans.XMLDecoder'ами я поспешил.
--
Дмитро
Re[9]: Java Web Start+передача класса по сети ClassCirculari
От: Волк-Призрак Россия http://ghostwolf.newmail.ru
Дата: 30.11.04 17:20
Оценка:
Здравствуйте, dshe, Вы писали:

D>Здравствуйте, Lucker, Вы писали:


L>>Здравствуйте, Lucker, Вы писали:


D>>>>А java.beans.XMLEncoder/java.beans.XMLDecoder не подошел?


L>>>Так у него в одном месте 1.3 стоит. Надо еще парсер цеплять клиентам


L>>Во ляпнул. Там не парсер, там 1.4 надо цеплять, штоб заработало. Тогда нах-ра java.beans.XMLEncoder/java.beans.XMLDecoder?


D>И то правда! С java.beans.XMLEncoder/java.beans.XMLDecoder'ами я поспешил.


В общем, спасибо за рекомендацию.
Просто
у меня специфический протокол в системе — передаются сериализованые зипованые объекты,
производные от класса, описываюшего понятие "сообщение".
Я не знаю про этот декодер, в частности, как он отреагирует на то, что результат работы кодера
запишется в ObjectOutputStream, опирающемся на ZipOutputStream, лежащем на ByteArrayStream...
Код просто переносил из дейтаграмного варианта в сокетный. Когда дейтаграмный вариант делал,
дейтаграммы из Одессы в Ростов доходили, а с Москвой наладить связь не удалось. Вот и перешел на сокеты.
Теперь с ними проблемы (не осовобождаются все ресурсы, использованые сокетом),
Т. е. при повторном запуске клиентской программы он выдаёт BindException : address in use.
но это другая тема.
Если на этот пункт здесь реакции не будет, открою как отдельный топик.
while(Life.getClass().getClassLoader()==Religion.GOD){Life.be();};
Скажи .net корпорации Microsoft! (c) ghostwolf 2004
7 раз поищи в стандартной библиотеке, 1 раз накодь своё.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.