В своем проекте я использую аплеты.
Структура проекта такова что в нем есть основное окно на котором распологаются <iframe/> таги. Каждый <iframe/> содержит страницу с апплетом.
Проблема в следующем, когда я пытаюсь переместить <iframe/> из одного DIV'а в другой скажем таким кодом:
Здравствуйте, mikkri, Вы писали:
M>А если по сути, то вы можете хранить статус аплета на сервере в сессии клиента и при перезагрузке апплета загружать статус с сервера.
Спасибо за идею mikkri. Но всетаки еще надеюсь на более простое решение.
Нсколько я понимаю, все происходит следующим образом:
— я создал <iframe/> с аплетом, я могу к нему обращаться через JS — все ОК
— как только я передвигаю <iframe/> в другой DIV, JVM пересоздает аплет (причем в моем случае это небыстрый процесс), далее когда я пытаюсь обратиться к аплету через JS то браузер думая, что с аплетом ничего не произошло, пытается обратиться к нему по старой ссылке (указателю, адресу) и я получаю JS error.
Кроме того, аплет, после пересоздания, перестает прорисовываться — update и paint не вызываются даже если их вызывать принудительно...
Я в Java новичок, но от хорошего совета не отказался бы.
Высказывайте любые идеи!
Я приаттачил тестовый аплет, просто запустите index.html. Для загрузки <iframe/> нажимайте Load, для перемещения Move.
Аплет выводит сообщения в консоль.
Здравствуйте, mikalai.kardash, Вы писали:
MK>Нсколько я понимаю, все происходит следующим образом: MK> — я создал <iframe/> с аплетом, я могу к нему обращаться через JS — все ОК MK> — как только я передвигаю <iframe/> в другой DIV, JVM пересоздает аплет (причем в моем случае это небыстрый процесс), далее когда я пытаюсь обратиться к аплету через JS то браузер думая, что с аплетом ничего не произошло, пытается обратиться к нему по старой ссылке (указателю, адресу) и я получаю JS error.
Это на всех браузерах? Что за адрес апплета? Какая именно ошибка JS?
MK>Я приаттачил тестовый аплет, просто запустите index.html. Для загрузки <iframe/> нажимайте Load, для перемещения Move. MK>Аплет выводит сообщения в консоль.
Куда приаттачил?
Re[3]: Проблема с повторной инициализацией аплета
От:
Аноним
Дата:
24.07.07 12:33
Оценка:
Здравствуйте, mikalai.kardash, Вы писали:
MK>Нсколько я понимаю, все происходит следующим образом: MK> — я создал <iframe/> с аплетом, я могу к нему обращаться через JS — все ОК MK> — как только я передвигаю <iframe/> в другой DIV, JVM пересоздает аплет (причем в моем случае это небыстрый процесс), далее когда я пытаюсь обратиться к аплету через JS то браузер думая, что с аплетом ничего не произошло, пытается обратиться к нему по старой ссылке (указателю, адресу) и я получаю JS error.
Как это вы "передвигаете"? Наверное, средствами JS пишете iframe код в другом месте страницы и браузер загружает содержимое iframe (для него это новый iframe), т.е. стартует новый апплет. А старый наверное продолжает работать. Поскольку JVM одна, то два одинаковых апплета, работающих одновременно, мешают друг другу каким-то образом. Таким образом, надо сначала убедиться, что старый апплет остановлен и его состояние сохранено где-нибудь. Не хотите на сервере, тогда попробуйте в браузере, в JS сохранить. А вообще, смешивать JS и апплеты — это как пиво с портвейном. Совершенно неинтересно и неперспективно.
Здравствуйте, Аноним, Вы писали:
А>Как это вы "передвигаете"? Наверное, средствами JS пишете iframe код в другом месте страницы и браузер загружает содержимое iframe (для него это новый iframe), т.е. стартует новый апплет.
Передвигаю я его следующим образом:
document.getElementById('div2').appendChild(
document.getElementById('myframe')
);
Т.е. у фрейма меняется parent елемент.
А>А старый наверное продолжает работать. Поскольку JVM одна, то два одинаковых апплета, работающих одновременно, мешают друг другу каким-то образом. Таким образом, надо сначала убедиться, что старый апплет остановлен и его состояние сохранено где-нибудь. Не хотите на сервере, тогда попробуйте в браузере, в JS сохранить. А вообще, смешивать JS и апплеты — это как пиво с портвейном. Совершенно неинтересно и неперспективно.
Перезагрузки фрейма не происходит. HTML каким был таким и остается. JVM (Sun, не MS), при перемещении аплета, останавливает старый инстанс аплета, вызывает ему destroy(), вызывает init, start для нового инстанса аплета. Что имеем: для браузера (IE) аплет не изменился, ссылки остались на старый инстанс; для JVM аплет поменялся.
Поэтому, даже если я копирую все данные из старого аплета, то мне они никак не пригождаются — новый аплет для меня не существует, я не могу к нему никак обратиться. При обращении к аплету, из JS вызываются методы старого инстанса аплета.
Я сделал тестовый аплет, который только и делает что на init() создает себе ID — рандомный long. JVM log:
//Создаем аплет с ID -1596415299
basic: Loading applet ...
basic: Initializing applet ...
basic: Starting applet ...
Applet: Init called. AppletID = -1596415299
Applet: start method is called. AppletID = -1596415299
Display Panel: PAINT method is called. AppletID = -1596415299
Display Panel: PAINT method is called. AppletID = -1596415299
//в аплете есть функция которую можно вызывать из JS
liveconnect: Invoking method: public void com.applet.MyApplet.scriptCalledFunction(java.lang.String)
liveconnect: Needs conversion: java.lang.String --> java.lang.String
//Все ОК, обращение идет к аплету с ID -1596415299
Display Panel: received message from client [Test message to applet] when AppletID = -1596415299
Display Panel: PAINT method is called. AppletID = -1596415299
Display Panel: PAINT. Message = Test message to applet
//Перемещаем iframe с аплетом в другой DIV
//останавливается аплет
basic: Stopping applet ...
basic: Removed progress listener: sun.plugin.util.GrayBoxPainter@c7e553
basic: Finding information ...
basic: Releasing classloader: sun.plugin.ClassLoaderInfo@16897b2, refcount=0
basic: Caching classloader: sun.plugin.ClassLoaderInfo@16897b2
Applet: stop method is called. AppletID = -1596415299
Display Panel: PAINT method is called. AppletID = -1596415299
Display Panel: PAINT. Message = Test message to applet
//вызывается destroy()
basic: Current classloader cache size: 1
basic: Done ...
basic: Joining applet thread ...
basic: Destroying applet ...
basic: Disposing applet ...
Applet: destroy method is called. AppletID = -1596415299
basic: Joined applet thread ...
basic: Unregistered modality listener
basic: Quiting applet ...
//создается новый аплет с ID -1756904681
basic: Registered modality listener
liveconnect: Invoking JS method: document
liveconnect: Invoking JS method: URL
basic: Referencing classloader: sun.plugin.ClassLoaderInfo@16897b2, refcount=1
basic: Added progress listener: sun.plugin.util.GrayBoxPainter@f4a24a
basic: Loading applet ...
basic: Initializing applet ...
basic: Starting applet ...
Applet: Init called. AppletID = -1756904681
Applet: start method is called. AppletID = -1756904681
Display Panel: PAINT method is called. AppletID = -1756904681
Display Panel: PAINT method is called. AppletID = -1756904681
//пытаемся вызвать из JS функцию аплета
//она вызывается для аплета с ID -1596415299 ... хотя он уже должен бы быть остановлен...
liveconnect: Invoking method: public void com.applet.MyApplet.scriptCalledFunction(java.lang.String)
liveconnect: Needs conversion: java.lang.String --> java.lang.String
Display Panel: received message from client [Test message to applet] when AppletID = -1596415299
liveconnect: Invoking method: public void com.applet.MyApplet.scriptCalledFunction(java.lang.String)
liveconnect: Needs conversion: java.lang.String --> java.lang.String
Display Panel: received message from client [Test message to applet] when AppletID = -1596415299
//прорисовывается только новый аплет
Display Panel: PAINT method is called. AppletID = -1756904681
Display Panel: PAINT method is called. AppletID = -1756904681
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, mikalai.kardash, Вы писали:
MK>>Нсколько я понимаю, все происходит следующим образом: MK>> — я создал <iframe/> с аплетом, я могу к нему обращаться через JS — все ОК MK>> — как только я передвигаю <iframe/> в другой DIV, JVM пересоздает аплет (причем в моем случае это небыстрый процесс), далее когда я пытаюсь обратиться к аплету через JS то браузер думая, что с аплетом ничего не произошло, пытается обратиться к нему по старой ссылке (указателю, адресу) и я получаю JS error.
B>Это на всех браузерах? Что за адрес апплета? Какая именно ошибка JS?
Я тестирую под IE6+SP2 / WinXP.
B>Что за адрес апплета?
Что вы имеете в виду?
MK>>Я приаттачил тестовый аплет, просто запустите index.html. Для загрузки <iframe/> нажимайте Load, для перемещения Move. MK>>Аплет выводит сообщения в консоль. B>Куда приаттачил?
Вот ссылка: http://files.rsdn.ru/67823/test.zip
Немного больше деталей:
Передвигаю я аплет следующим образом:
document.getElementById('div2').appendChild(
document.getElementById('myframe')
);
Т.е. у фрейма меняется parent елемент.
Я сделал тестовый аплет, который только и делает что на init() создает себе ID — рандомный long. JVM log:
//Создаем аплет с ID -1596415299
basic: Loading applet ...
basic: Initializing applet ...
basic: Starting applet ...
Applet: Init called. AppletID = -1596415299
Applet: start method is called. AppletID = -1596415299
Display Panel: PAINT method is called. AppletID = -1596415299
Display Panel: PAINT method is called. AppletID = -1596415299
//в аплете есть функция которую можно вызывать из JS
liveconnect: Invoking method: public void com.applet.MyApplet.scriptCalledFunction(java.lang.String)
liveconnect: Needs conversion: java.lang.String --> java.lang.String
//Все ОК, обращение идет к аплету с ID -1596415299
Display Panel: received message from client [Test message to applet] when AppletID = -1596415299
Display Panel: PAINT method is called. AppletID = -1596415299
Display Panel: PAINT. Message = Test message to applet
//Перемещаем iframe с аплетом в другой DIV
//останавливается аплет
basic: Stopping applet ...
basic: Removed progress listener: sun.plugin.util.GrayBoxPainter@c7e553
basic: Finding information ...
basic: Releasing classloader: sun.plugin.ClassLoaderInfo@16897b2, refcount=0
basic: Caching classloader: sun.plugin.ClassLoaderInfo@16897b2
Applet: stop method is called. AppletID = -1596415299
Display Panel: PAINT method is called. AppletID = -1596415299
Display Panel: PAINT. Message = Test message to applet
//вызывается destroy()
basic: Current classloader cache size: 1
basic: Done ...
basic: Joining applet thread ...
basic: Destroying applet ...
basic: Disposing applet ...
Applet: destroy method is called. AppletID = -1596415299
basic: Joined applet thread ...
basic: Unregistered modality listener
basic: Quiting applet ...
//создается новый аплет с ID -1756904681
basic: Registered modality listener
liveconnect: Invoking JS method: document
liveconnect: Invoking JS method: URL
basic: Referencing classloader: sun.plugin.ClassLoaderInfo@16897b2, refcount=1
basic: Added progress listener: sun.plugin.util.GrayBoxPainter@f4a24a
basic: Loading applet ...
basic: Initializing applet ...
basic: Starting applet ...
Applet: Init called. AppletID = -1756904681
Applet: start method is called. AppletID = -1756904681
Display Panel: PAINT method is called. AppletID = -1756904681
Display Panel: PAINT method is called. AppletID = -1756904681
//пытаемся вызвать из JS функцию аплета
//она вызывается для аплета с ID -1596415299 ... хотя он уже должен бы быть остановлен...
liveconnect: Invoking method: public void com.applet.MyApplet.scriptCalledFunction(java.lang.String)
liveconnect: Needs conversion: java.lang.String --> java.lang.String
Display Panel: received message from client [Test message to applet] when AppletID = -1596415299
liveconnect: Invoking method: public void com.applet.MyApplet.scriptCalledFunction(java.lang.String)
liveconnect: Needs conversion: java.lang.String --> java.lang.String
Display Panel: received message from client [Test message to applet] when AppletID = -1596415299
//прорисовывается только новый аплет
Display Panel: PAINT method is called. AppletID = -1756904681
Display Panel: PAINT method is called. AppletID = -1756904681
Здравствуйте, mikalai.kardash, Вы писали:
MK>>> — как только я передвигаю <iframe/> в другой DIV, JVM пересоздает аплет (причем в моем случае это небыстрый процесс), далее когда я пытаюсь обратиться к аплету через JS то браузер думая, что с аплетом ничего не произошло, пытается обратиться к нему по старой ссылке (указателю, адресу) и я получаю JS error. B>>Что за адрес апплета? MK>Что вы имеете в виду?
Выделено болдом.
MK>Немного больше деталей:
Повторятся было совсем не обязательно. Кому надо и там прочтет.
Здравствуйте, mikalai.kardash, Вы писали:
MK>Поэтому, даже если я копирую все данные из старого аплета, то мне они никак не пригождаются — новый аплет для меня не существует, я не могу к нему никак обратиться. При обращении к аплету, из JS вызываются методы старого инстанса аплета.
1) Покажи JS код. Может там можно переполучить новую ссылку на апплет?
2) Проверь поведение на разных браузерах. Так можно локализовать проблему либо это браузер либо Java-Plug-in
3) В качестве хака можно попробовать все переписать на статические методы. То есть все методы апплета тупо делегируют все вызовы статическим методам. А состояние хранится в статических полях. хотя методы в принципе все равно какие. Главное поля в статические переделать. Тогда у тебя состояние не будет пропадать. Так как оно хранится на уровне классов. А загрузчик классов у тебя судя по логам не меняется. Но надо быть осторожным, тут могут быть и последствия, когда апплет будет загружен заново в том же окне, Java Plug-in не будет уничтожать старый загрузчик. И в результате апплет сразу загрузится в предыдущем состоянии.
Здравствуйте, Blazkowicz, Вы писали:
B>>>Что за адрес апплета?
Конечно же адреса аплета у меня нет... просто каждый понимает по-своему. Для обращения к аплету и вызова его методов я использую следующий JavaScript код:
document.getElementById('myapplet').scriptCalledFunction("Test message to applet");
где myapplet — ID аплета в DOM'е
scriptCalledFunction — public функция аплета
document.getElementById('myapplet').scriptCalledFunction("Test message to applet");
Я пробовал сохранять ссылку на таг аплета в переменной на уровне документа (IFAME) и на уровне страницы, в которую загружается IFRAME... не помогло.
B>2) Проверь поведение на разных браузерах. Так можно локализовать проблему либо это браузер либо Java-Plug-in
В FireFox аплет пересоздается, но, в отличии от IE, JavaScript работает нормально — вызываются функции нового аплета. Вполне возможно, что это IE баг, однако, не понятно почему JVM старается пересоздать аплет вместо того чтобы остановить его сначала (stop) а потом запустить (start).
Постараюсь разузнать на форумах microsoft'а про IE.
B>3) В качестве хака можно попробовать все переписать на статические методы. То есть все методы апплета тупо делегируют все вызовы статическим методам. А состояние хранится в статических полях. хотя методы в принципе все равно какие. Главное поля в статические переделать. Тогда у тебя состояние не будет пропадать. Так как оно хранится на уровне классов. А загрузчик классов у тебя судя по логам не меняется. Но надо быть осторожным, тут могут быть и последствия, когда апплет будет загружен заново в том же окне, Java Plug-in не будет уничтожать старый загрузчик. И в результате апплет сразу загрузится в предыдущем состоянии.
Спасибо!
Да, так можно сделать, но тогда придется сделать чтото вроде Hastable или Map в котором бы хранились состояния апплетов. Потому что на странице может быть загружено несколько одинаковых аплетов и их всех както пирдется отличать... причем для каждого аплета придется делать похожий трюк.
Еще одна идея состоит в том, чтобы перемещать IFRAME не между тагами, а используя абсолютное позиционирование и DIV таги как привязку,
Обе идеи имеют один недостаток: требуют кодирования
Сейчас, очень бы хотелось найти решение позволяющее получить наименьшее сопротивление у команд которые занимаются разработкой различных сторон нашего продукта, таких как разработка аплетов, сервисной части и сайта...
Здравствуйте, sl.ex, Вы писали:
SE>В FireFox аплет пересоздается, но, в отличии от IE, JavaScript работает нормально — вызываются функции нового аплета. Вполне возможно, что это IE баг, однако, не понятно почему JVM старается пересоздать аплет вместо того чтобы остановить его сначала (stop) а потом запустить (start). SE>Постараюсь разузнать на форумах microsoft'а про IE.
Попробуйте вместо <applet> поэксперементировать с <object> и <embed>