Показаны сообщения с ярлыком java. Показать все сообщения
Показаны сообщения с ярлыком java. Показать все сообщения

среда, 19 августа 2009 г.

Запуск JSTL в Eclipse Dynamic Web Project

Оказывается не все так просто, если запускать Tomcat под Eclipse.
Если в Eclipse создать Dynamic Web Project, то простое добавление
jstl.jar и standard.jar в WEB_INF/lib может не помочь,
даже если в Java Build Path они есть.
При этом, если экпортировать .war, то в Tomcat запустится нормально.
Не запускается именно из-под Eclipse.

Помогло следующее:
при вызове контекстного меню в Run As -> Run configuration
выбирает нужный сервер из списка Apache Tomcat (перед этим нужно остановить)
справа выбираем сервер и в закладке Classpath и добавляем (Add jars):
jstl.jar, standard.jsr, servlet-api.jar, jsp-api.jar, el-api.jar

вторник, 18 августа 2009 г.

Hibernate: ошибка связанная с SLF4J

Проблема:
При запуске нового проекта на Hibernate 3.3.2 скопированы с архива (папка lib) все необходимые библиотеки, в том числе и slf4j-api-1.5.8.jar.
Но при старте теста появляется ошибка:

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. Exception in thread "main" java.lang.ExceptionInInitializerError

Решение:
На сайте http://www.slf4j.org/codes.html#StaticLoggerBinder эту ошибку описывают так:
"This error is reported when the org.slf4j.impl.StaticLoggerBinder class could not be loaded into memory. This happens when no appropriate SLF4J binding could be found on the class path. Placing one (and only one) of slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar or logback-classic.jar on the class path should solve the problem."
То есть нужно в пути к библиотекам добавить один из (и только один slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar or logback-classic.jar)

Скачать необходимую библиотеку можно с сайта http://www.slf4j.org/dist/ (берем ту же версию, что и slf4j-api).
В Jar архиве есть необходимые библиотеки.
Я взял slf4j-jdk14-1.5.8.jar.

понедельник, 10 августа 2009 г.

Как правильно закрывать сессию. session.invalidate() - не достаточно

Описание проблемы:
Есть сайт, с такими условными частями:
1) login.jsp - в котором вводятся логин и пароль
2) dispatcher - сервлет, который обрабатывает данные формы из login.jsp, проверяя из БД логин и пароль и перенаправляет (или назад в login.jsp (если проверка неудачна) или в welcome.jsp)
3) welcome.jsp (или home.jsp), на этой странице приветствия, профайл пользователя, домашняя страница пользователя, или любая другая страница с конфиденциальными данными и ссылками.
Пользователь нажимает по ссылке "выйти", dispatcher закрывает сессию и перенаправляет на страницу регистрации login.jsp.
4) вспомогательный объект, в котором находятся дополнительные/вспомогательные данные сессии.

Задача:
Правильно сделать так, чтобы пользователь, нажав на кнопку браузера "Назад" ("Back") не смог просматривать конфиденциальные данные предыдущего пользователя. Браузер кеширует данные.

Обсуждение:
Все оказалось не так просто.
session.invalidate() - проблему не решил.
session.removeAttribute("myObject")
- тоже может воскреснуть.
session.removeParameter("login")
- не существует
запретить кеширование: с одной стороны на это надеяться нельзя, поскольку сервер не может полностью контролировать работу браузеров всех версий и под все платформы, это клиентская часть. С другой стороны, и это во многих случая не помогает.
Отменять кеширование можно либо программным способом:
response.setContentType("text/html");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Pragma","no-cache")
либо (по сути это одно и тоже, к тому же скриптлеты уже считаются плохой манерой):
META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
META HTTP-EQUIV="Expires" CONTENT="-1">

и даже response.
sendRedirect() вместо
RequestDispatcher rd =
this.getServletConfig()
.getServletContext()
.getRequestDispatcher("login.jsp");
rd.forward(request, response);
не помогает.

Все дело в том, что когда пользователь, нажал кнопку назад в welcome.jsp объект, то объект, в котором мы храним данные сессии практически потерян, НО если нажать кнопку обновить (F5), он снова восстанавливается, поскольку браузер все-равно сохранил параметры этой страницы (request.getParameter("login") все-еще срабатывает со старыми данными).
Дополнительной мерой защиты есть создание Ajax-запроса на сервер для проверки наличия объекта сессии, который хранит результаты регистрации.
Пример сервлета:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=UTF-8");
request.setCharacterEncoding("UTF-8");
HttpSession session = request.getSession();
Helper helper = (Helper) session.getAttribute("helper");
PrintWriter out = response.getWriter();
if (helper.isLoged()) {
out.println("1"); // valid
} else {
out.println("0"); // invalid
}
}


Пример клиента (с помощью JQuery):
function validate(){
$.ajax({
url: "checkSession",
type: "POST",
data: {0: 0}, //any minimal data
error: function(){ alert("виникла помилка Ajax"); } ,
success: function (data){
if (data != 1){
location.href="login.jsp";
}
}
}); // ajax
}


И welcome.jsp вызываем эту функцию.

Такой метод хорош. Но все-таки можно успеть остановить перенаправление (мне это удалось сделать) и опять же обновить страницу...

Хорошим трюком есть использование токенов.
В сервлете создаем генерацию токенов:
public static int TOKEN ;
public static int getNextToken(){
TOKEN++;
return TOKEN;
}

на странице с формой логина создаем дополнительный скрытый параметр:
input type="hidden" name="token" value="<%= Dispatcher.getNextToken() %>"
и в том же (предыдущем) сервлете делаем проверку:
if (new Long(reaquest.getParameter("token")) {
forward(request, response, "/login.jsp");
}

И срабатывает! Дело в том, что когда пользователь нажал на кнопку "выйти", его перенаплавило на login.jsp, в котором счетчик TOKEN увеличился. Но в закешированной странице это значение осталось старым, поэтому оно будет меньше текущего


И еще дополнительным способом (наверное даже самым лучшим) это использовать в login.jsp AJAX, который будет проверять в базе логин и пароль и перенаправит (в случае успешной аутентификации) на нужную страницу, которая НЕ ХРАНИТ И НЕ КЕШИРУЕТ результаты. В таком случае, параметр ACTION вместо сервлета перенаправления нужно установить action="#"

четверг, 12 февраля 2009 г.

java ConcurrentModificationException

Эта ошибка может возникнуть в случае, когда происходит попытка изменить коллекцию внутри итерации этой же коллекции. Например:
List originalList = new ArrayList();
for (Iterator it =
originalList.iterator(); it.hasNext(); ) {
originalList.add(someObject);
}

Решение: создать копию коллекции и изменять нужную коллекцию внутри итерации по копии. Пример:
List copy = new ArrayList(originalList);
for (Iterator it = copy.iterator(); it.hasNext(); ) {
originalList.add(someObject);
}

Заметка: можно также использовать специальные классы колекций (что-то типа
CopyOnWriteArrayList), но в большинстве случаев лучше использовать копии.
Для дополнительной информации:

Class ConcurrentModificationException (англ.)

описание решения проблемы на форуме Sun (англ.)

пятница, 7 ноября 2008 г.

решение проблемы: java.lang.OutOfMemoryError: PermGen space


При возникновении ошибки java.lang.OutOfMemoryError: PermGen space
Eclipse
может просто неожиданно завершить работу и предложить просмотреть логи.
Хочу заметить, что я впервые встретился с этой ошибкой, когда начал использовать Eclipse для рисования UML диаграмм. То есть в тот момент, когда Eclipse начал использовать плагины org.eclipse.gef и org.eclipse.emf,
а эти плагины есть также в Eclipse IDE for Java EE Developers. В этом можно убедиться тут.
Также эта ошибка может появляться при использовании HQL запросов, когда активно используется Hibernate.

Почему возникает эта ошибка сейчас я описывать не буду. Об этом можно почитать, например, в этой статье (на английском)

И так, если кратко, то решить быстро это проблему можно так:
в директории, где находится eclipse или eclipse.exe (для Windows) нужно найти файл eclipse.ini и открыть в текстовом редакторе, в котором нужно добавить/отредактировать следующие строки:
-Xms512m
-Xmx512m
-XX:PermSize=512m
-XX:MaxPermSize=512m

Это пример моих настроек. Настраивайте параметры в зависимости от объема памяти на вашем компьютере. Кратко об этих параметрах:
Xms - это минимальный объем выделяемой памяти (кучи - heap)
Xmx - это максимальный объем выделяемой памяти (кучи - heap)
XX:PermSize - это начальный размер permanent generation (о нем подробней позже...). Он создается в дополнение к объему Xms.
XX:MaxPermSize - максимальный размер permanent generation.

Теперь осталось запустить eclipse c ключем -clean
eclipse -clean
(Примечание: начиная с версии 3.4 (GANYMEDE) запускать -clean не нужно)

НО! Все-таки нужно убедиться что эти параметры задействованы. Дело в том, что на некоторых Unix* ОС настройки файла eclipse.ini не срабатывают, даже если описаны правильно.
Для того, чтобы убедиться изменения в настройках можно просмотреть:
Help -> About Eclipse Platform -> Configuration details
и смотрим строку eclipse.vmargs=

Чтобы окончательно победить проблему есть 2 способа:

1-й способ. Window -> Preferences -> Java -> Installed JREs -> выбор нашего JRE -> Edit и в строке Default VM Arguments пишем
-vmargs -Xms512m -Xmx512m -XX:PermSize=512m -XX:MaxPermSize=512m

2-й способ. Написать скрипт запуска eclipse. Например, в создать файл eclipse.sh, дать права на запуск () и прописать в файле:
#!/bin/bash

eclipse -vmargs -Xms512m -Xmx512m -XX:PermSize=512m -XX:MaxPermSize=512m

Надеюсь, этот баг больше возникать не будет ;)
О дополнительных способах борьбы с этой проблемой можно почитать в этой статье

PS Доп. материал:

MaxPermSize and how it relates to the overall heap

Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine

Frequently Asked Questions about Garbage Collection in the HotspotTM JavaTM Virtual Machine

Java Performance Documentation

Tuning Java Virtual Machines (JVMs)

Memory Analyzer (MAT)

четверг, 6 ноября 2008 г.

Как настроить Linux, чтобы просматривать Java аплеты в Firefox и Opera



Все-таки Flash на сегодня (2008 год) используется на много больше, чем Java аплеты, несмотря на то, что у аплетов больше возможностей.

Одной из главных причин есть то, что Flash не нужно устанавливать и нет проблем в настройке для обычного пользователя Innternet.
Проблема, думаю, не в сложностях технической реализации, а скорее в политике - такие IT-гиганты как Microsoft и Sun не сумели подружиться и ...
Но сейчас не об этом.

Предполагаю, что Java уже установлен. Проблем с установкой Java возникает редко и особых усилий не нужно (можно просто скачать .bin файлик с java.sun.com и запустить его)

Если возникли проблема с запуском аплетов существует самый простой способ, который должен подойти для большинства браузеров.

Нужно просто создать символическую ссылку /usr/lib/browser-plugins/libjavaplugin.so на файл $JAVA_HOME/plugin/i386/ns7/libjavaplugin_oji.so

Пример:
cd /usr/lib/browser-plugins/
ln -s /usr/java/default/jre/plugin/i386/ns7/libjavaplugin_oji.so libjavaplugin.so

и перезагрузить браузер.
Ни в коем случае не следует копировать файл. Иначе браузер виснет при отображении аплетов

Если что-то не получается существуют еще вариаты:
Для Firefox
Необходимо создать ссылку в папке $HOME/.mozilla/plugins/ (если папки plugins нет, то нужно ее создать)
на файлик libjavaplugin_oji.so с директории $JRE_HOME/plugin/i386/ns7
Пример команды:
mkdir /home/user/.mozilla/plugins (если plugins там нет)
ln -s /usr/java/default/jre/plugin/i386/ns7/libjavaplugin_oji.so /home/user/.mozilla/plugins/libjavaplugin_oji.so

На некоторых сайтах рекомендуют еще создать переменную окружения MOZ_PLUGIN_PATH
(в основном это не обязательно).
Для этого в файлике .bash_profile нужно добавить:
MOZ_PLUGIN_PATH=$HOME/.mozilla/plugins
export MOZ_PLUGIN_PATH
Чтобы переменная окружения заработала нужно либо перелогиниться либо запустить: sh ./.bash_profile

Перезапускаем Firefox на всякий случай проверяем разрешен ли в настройках Java (Настройки-Содержание)

для Opera все намного проще:
Настройки-Дополнительно(закладка)-Содержание(в списке)-ставим галочку "включить Java", нажимаем на кнопке "Параметры Java", указываем путь к Java (у меня /usr/java/jdk1.6.0_10/jre/lib/i386), проверяем путь с помощью кнопки проверки.
Если путь является корректным, то перезапускаем Opera.

И радуемся богатством технологий Java