вторник, 22 сентября 2009 г.

glassfish thread pool

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


для начала необходимо его создать, через веб консоль администрирования и дать ему имя:
Configuration -> Thread Pools -> New


использовать так:
...
import com.sun.enterprise.connectors.ConnectorRuntimeException;
import com.sun.enterprise.connectors.work.WorkManagerFactory;
import javax.resource.spi.work.Work;
import javax.resource.spi.work.WorkException;
import javax.resource.spi.work.WorkManager;
...
    try {
        WorkManager workManager = WorkManagerFactory.getWorkManager("threadpoolname");
        Work work = new Work() {
            @Override
            public void release() {
//вызывается если необходимо остановить тред
            }
 
            @Override
            public void run() {
//код, который надо распараллелить
            }
        };
        workManager.scheduleWork(work);
    } catch (WorkException e) {
//что-то сделать
} catch (ConnectorRuntimeException e) {
//что-то сделать
...
}
и не забудьте подключить библиотеку glassfish_dir/lib/appserv-rt.jar

четверг, 17 сентября 2009 г.

жава ее Шедулер своими руками

Все мы иногда что-нибудь планируем, ставим себе галочки в уме что утром будем просыпаться и делать зарядку или что завтра ляжем спать не в два а часов в одинадцать. так вот, если нифига не получается - значит плохой планировщик задач. сегодня напишем свой планировщик задач для javaee app-сервера:
package myproject.ejb;

import java.util.Date;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;

@Stateless
public class UsualBean implements UsualLocal {

@Resource
TimerService timerService;

private static long intervalDuration = 3000;

private void makeMeHappy() {
System.out.println("i am so happy at " + new Date());
}

public void createTimer(long intervalDuration) {
//это что бы два раза не выполнить одно и то же задание
for (Object o : timerService.getTimers()) {
if (o instanceof Timer) {
((Timer) o).cancel();
}
}

this.intervalDuration = intervalDuration;
//обратите внимание на второй параметр, это может быть любой Serializable объект
Timer timer = timerService.createTimer(intervalDuration, "all your base are belong to us");
}

@Timeout
private void timeout(Timer timer) {
this.makeMeHappy();
//таймер срабатывает один раз, мне же надо через определенный интервал
timerService.createTimer(intervalDuration, timer.getInfo());
}
}


теперь осталось только запустить этот шедуллер методом createTimer, можно при старте app-сервера

вторник, 15 сентября 2009 г.

Как выполнить определенный код при старте app-сервера

На днях у меня возникла необходимость запустить шедулер на стороне app-сервера. Про сам шедулер я напишу в одном из следующих сообщений, а про технологию запуска чего-либо при старте апп-сервера расскажу сейчас...

Вообщем надо поправить файл web.xml , если вы не используете веб компоненту в своем энтерпрайз проекте, придется создать пустой проект с одним этим файлеком.


<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xsi="http://www.w3.org/2001/XMLSchema-instance" schemalocation="http://java.sun.co">
<listener>
<listener-class>myproject.ejb.MyContextListener</listener-class>
</listener>
</web-app>

Это тот класс, методы которого будут вызываться, когда изменяется контекст сервлета.

package myproject.ejb.MyContextListener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyContextListener implements ServletContextListener {

public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContextListener::contextDestroyed");
}

public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContextListener::contextInitialized");
}
}


как-то так :)

пятница, 10 июля 2009 г.

manual javaee realm

Недавно я писал о том, как настроить jdbc realm в glassfish. Сейчас я попытаюсь рассказать, о том, как написать свой realm самому.

Итак, что же такое этот realm?
Realm - это такой механизм, отвечающий за аутентификацию пользователя на сервере приложений. Когда пользователь (точнее говорить principal) пытается получить доступ к какому-либо ресурсу сервера приложений, если для этого нужна авторизация, то realm используется для получения списка групп, в которых состоит пользователь. На основании этого списка решается - позволено ли данному пользователю воспользоваться данным ресурсом (будь то java-bean, jdbc-datasource и т.д.).

В совокупности с JAAS фреймворком они представляют собой подсистему аутентификации glassfish`а.

Для того, что бы написать свой realm для glassfish v2.1 необходимо реализовать два класса:

com.sun.appserv.security.AppservRealm
com.sun.appserv.security.AppservPasswordLoginModule

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

и добавить информацию о них в:

domain_dir/config/domain.xml
domain_dir/config/login.conf

замечание: для того что бы эти классы были видны в IDE я подкинул им пару jar-ов из glassfish`a, которые после билда можно исключить из списка файлов, т.к. они уже есть на сервере приложений:
glassfish_dir/lib/appserv-ext.jar
glassfish_dir/lib/appserv-rt.jar

среда, 24 июня 2009 г.

Java Interceptors

Вместе с появлением EJB3.0 в JavaEE появилась очень полезная штука - Interceptors - специальные классы, которые могут перехватывать вызов методов заданного класса.
Для чего это может быть полезно? Если у вас есть сложное приложение и изменение его кода - очень трудоемкий процесс, то для некоторого класса задач можно использовать Interceptor`ы

Например:
  • для изменения некоторых бизнес методов на лету (в т.ч. входных параметров, исключений)
  • для мониторинга производительности приложения
  • для аудита различных событий

Пример:



public class AuditInterceptor {

@AroundInvoke
public Object trace(InvocationContext invocationContext) throws Exception{
System.out.println("Object: " + invocationContext.getTarget().getClass().getName());
System.out.println("Method: " + invocationContext.getMethod());

System.out.println("Parameters:");
for (Object p : invocationContext.getParameters()) {
System.out.println("[" + p.getClass().getName() + "] " + p);
}

return invocationContext.proceed();
}
}


Этот класс может перехватывать события для следуюющего бина:


@Stateless
@Interceptors({AuditInterceptor.class})
public class ComplexBean implements ComplexRemote {

public String makeMeHappy(String param1) {
//some code
}
}


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


воскресенье, 7 июня 2009 г.

полезные аннотации JPA

Вот очень полезные аннотации, при помощи которых можно реализовать java trigger
  • @PostLoad
  • @PrePersist
  • @PostPersist
  • @PreUpdate
  • @PostUpdate
  • @PreRemove
  • @PostRemove
например:


@Entity
public class Human implements Serializable {
...
@Basic
@Column
private String hello;
...
public String getHello() {
return hello;
}
public void setHello(String hello) {
this.hello = hello;
}
...
@PrePersist
@PreUpdate
private void preModify () {
hello = hello.trim().toLowerCase();
}
...
}

Если в @Entity перед каким-либо полем установить аннотацию @Transient, то это поле не будет добавляться в хранилище при вызове em.persist(entity);
Бывает полезно если в entity есть какие то рабочие поля, которые не представляют ни какого поля в хранилище данных, но нужны для реализации бизнес логики приложения

понедельник, 11 мая 2009 г.

JDBC Realm в glassfish

Сегодня удачно создал и использовал jdbc realm в сервере приложений glassfish. Хотя возможность использовать такой тип realm`ов в glassfish`е появилась давно, отмечу скудную и запутанную документированность этой очень полезной фичи.

Начнем с того, что создадим таблички для jdbc-realm`а:
[в качестве операционной системы я использовал - OpenSolaris 5.11 snv_111a, в качестве RDBMS postgresql-8.3 доступный из стандартных репозиториев, сервер приложений Sun GlassFish Enterprise Server v2.1]

для начала я установил нужный jdbc driver для postgresql, (SUNWpostgr-jdbc) и положил его в ${DOMAIN_DIR}/lib/ext

затем создал необходимые таблички, содержащие пользователей и группы в моей БД, вот их структура
[структуру табличек глянул здесь]:

CREATE TABLE users (
user_name text,
user_password text NOT NULL,
CONSTRAINT PK_users PRIMARY KEY (user_name)
);
CREATE TABLE roles (
role_caption text,
CONSTRAINT PK_roles PRIMARY KEY (role_caption)
);
CREATE TABLE users_roles (
user_name text,
role_caption text,
CONSTRAINT PK_users_roles PRIMARY KEY (user_name, role_caption),
CONSTRAINT FK_users_roles_0 FOREIGN KEY (user_name) REFERENCES users(user_name),
CONSTRAINT FK_users_roles_1 FOREIGN KEY (role_caption) REFERENCES roles(role_caption)
);


Для опытов внесем туда что-нибудь:

INSERT INTO users VALUES ('ddosia', '63a9f0ea7bb98050796b649e85481845');
INSERT INTO roles VALUES ('root');
INSERT INTO users_roles VALUES ('ddosia', 'root');


далее создадим datasource, способный вытягивать данные из данной БД.
вначале создаем connection-pool при помощи веб-консоли администрирования:
"Resources"->"JDBC"->"Connection Pools":
кнопаем на "New", указываем имя ["pg_local"], resource type ["javax.sql.DataSource"] и database vendor ["PostgreSQL"];
вводим известные нам значения "ServerName", "DatabaseName", "PortNumber", "User", "Password"

"Resources"->"JDBC"->"JDBC Resources":
щелкаем "New", указываем JNDI-Name ["jdbc/pg"], выбираем "Pool Name" ["pg_pool"]

вуаля, пул готов, далее создадим realm, использующий данный пул:

с помошью консоли администрирования glassfish`а идем в "Configuration"->"Security"->"Realms", кнопаем на "New"
указываем имя ["myJDBCRealm"], "Class Name" ["com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm"]
далее заполняем след свойства:
JAAS context ["JDBCRealm"]
JNDI ["jdbc/pg"]
User Table ["users"]
User Name Column ["user_name"]
Password Column ["user_password"]
Group Table ["users_roles"]
Group Name Column ["role_caption"]

Теперь пришел черед самого приложения:
вначале создадим ejb-bean, что то типа:

TestBean.java:

package realmsample;

import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;

@Stateless (name="TestBean", mappedName="TestRemote")
public class TestBean implements TestRemote {
@RolesAllowed("root")
public String meth1() {
return "11111!!!!";
}
@PermitAll
public String meth2() {
return "22222!!!!";
}
}


TestRemote.java:

package realmsample;

import javax.ejb.Remote;

@Remote
public interface TestRemote {
public String meth1 ();
public String meth2 ();
}


Client.java:

...
try {
InitialContext ctx = new InitialContext();
TestRemote testBean = (TestRemote) ctx.lookup ("TestRemote#" + TestRemote.class.getName());
System.out.println(testBean.meth2());
System.out.println(testBean.meth1());
} catch (NamingException exc) {
exc.printStackTrace();
}
...

так же необходимо в sun-application.xml внести следующее

...
<realm>
myJDBCRealm
</realm>
...

и поставить галочку в
"Configuration"->"Security"
"Default Principal To Role Mapping" -> "Enabled"

собственно после того как все это задеплоить и запустить, например через java-web-start или через netbeans то появится диалоговое окно, которое попросит представится системе. После удачной аутентификиции и авторизации meth1 будет выполнятся только тем кто состоит в группе root, а meth2 любым авторизованным пользователям

четверг, 7 мая 2009 г.

инкрементальные бэкапы в ZFS


на днях приобрел себе usb-потоскунчик с целью сделать резервное копирование некоторых данных с жесткого диска
вот небольшая демонстрация большого процесса...

для начала я подключил диск в usb разъем и убедился что он определился в системе
ddosia@twilight:~# iostat -En
...
c6t0d0 Soft Errors: 0 Hard Errors: 0 Transport Errors: 0
Vendor: StoreJet Product: Transcend Revision: Serial No: Size: 250.06GB <250059350016>
Media Error: 0 Device Not Ready: 0 No Device: 0 Recoverable: 0
Illegal Request: 0 Predictive Failure Analysis: 0
...


среди прочего мы узнали как он определился в системе.
далее создадим новый пул:

ddosia@twilight:~# zpool create bpool c6t0d0


проверим что он появился:

ddosia@twilight:~# zpool list


создадим на нем новый датасет:

ddosia@twilight:~# zfs create bpool/backup


создадим снапшот нужного нам датасета:

ddosia@twilight:~# zfs snapshot rpool/export/home/ddosia@06052009


далее скопируем получившийся снапшот в новый пул:

ddosia@twilight:~# zfs send rpool/export/home/ddosia@06052009 | zfs receive bpool/backup/ddosia@06052009


на следующий день я решил сделать еще один бэкап (все-таки пятница на носу, плавно перерастающая в праздники ;-) ):

ddosia@twilight:~# zfs snapshot rpool/export/home/ddosia@07052009
ddosia@twilight:~# zfs list -t snapshot
...
rpool/export/home/ddosia@06052009 751M - 50,6G -
rpool/export/home/ddosia@07052009 0 - 51,0G -
...

посылаем новый снапшот:

ddosia@twilight:~# zfs send -i rpool/export/home/ddosia@06052009 rpool/export/home/ddosia@07052009 | zfs receive bpool/backup/ddosia


далее отключаем usb-потаскунчик:

ddosia@twilight:~# zpool export bpool



воскресенье, 19 апреля 2009 г.

glassfish в opensolaris

Сегодня настраивал glassfish в opensolaris. Не скажу что этот процесс отличается чем-то от других ОС, но все же хотелось бы описать несколько специфичных шагов:
  1. устанавливаем, используя IPS:
    user@host:~# pkg install glassfishv2
  2. создаем директорию /var/appserver, назначаем на нее владельца, с правами которого будет запущено приложение
    user@host:~# mkdir /var/appserver; chmod 750 /var/appserver; chown appserv:appserv /var/appserver;
  3. создаем домен:
    appserv@host:~$ asadmin create-domain --user admin --adminport 4848 domain0
  4. сразу установим masterpassword:
    appserv@host:~$ asadmin change-master-password
  5. создадим следующие файлы, необходимые для генерации правил SMF, и наполним его необходимыми значениями:
    appserv@host:~$ echo "AS_ADMIN_USER=admin" > /var/appserver/passwd; echo "AS_ADMIN_PASSWORD=adminpassword" >> /var/appserver/passwd; echo "AS_ADMIN_MASTERPASSWORD=changeit" >> /var/appserver/passwd;
  6. затем добавим правило в SMF:
    user@host:~# asadmin create-service --passwordfile /var/appserver/passwd --serviceproperties net_privaddr /var/appserver/domains/domain0
  7. далее убедимся что сервис теперь доступен:
    appserv@host:~$ svcs -a | grep SUNWappserver
Небольшое пояснение некоторых моментов:
параметр
--serviceproperties net_privaddr позволяет слушать порты с номером меньшим чем 1024, что запрещено политикой безопасности по умолчанию

так же в документации говорится о дополнительном свойстве method_credential, позволяющим изменить пользователя, от имени которого будет запущен glassfish. Немного поэкспериментировав, я пришел к выводу что чего-то не то пишу, а именно:
asadmin create-service --passwordfile /var/appserver/passwd --serviceproperties method_credential=appserv --serviceproperties net_privaddr /var/appserver/domains/domain0
по этому, я просто напросто изменил руками нужный xml [/var/svc/manifest/application/SUNWappserver/domain0_var_appserver_domains/Domain-service-smf.xml], выгрузил уже использующийся [svccfg delete domain0] и загрузил его заново [svccfg import /var/svc/manifest/application/SUNWappserver/domain0_var_appserver_domains/Domain-service-smf.xml]

воскресенье, 5 апреля 2009 г.

OpenSolaris::краткий обзор



Итак! Начнем с того, что определим субъект нашего обсуждения!
Что же такое OpenSolaris и с чем его едят?

OpenSolaris - это открытая операционная система семейства unix, распространяющаяся под лицензией CDDL. Ее разработкой занимается сообщество на добровольной основе, при поддержки корпорации Sun.
Если провести аналогию с ОС GNU/Linux то OpenSolaris такая же тестовая платформа для Sun, как и Fedora для RedHat. Все самые удачные и интересные разработки, после процесса проверки надежности и соответствия корпоративным стандартам Sun попадают в закрытую коммерческую версию Solaris.

И чем же так интересна OpenSolaris?
Основные преимущества, на которые ставят ее разработчики это:
  • ZFS - Мощная файловая система и набор утилит для манипулирования ею
  • DTrace - специальный фреймворк для отладки ядра и пользовательских приложений
  • RM - диспетчер ресурсов позволяет контролировать использование доступных системных ресурсов приложениями
  • Zones - изолированные среды выполнения приложений
  • SMF - механизм управления сервисами
  • Crossbow - новый сетевой стек, позволяющий более гибко создавать и манипулировать виртуальными сетевыми устройствами
Так же в новых версиях OpenSolaris наконец-то повернулась лицом к обычным пользователям! По умолчанию в качестве оконного менеджера идет gnome, с очень симпатичной темой + compiz. Есть возможность поставить бинарные драйвера для таких устройств, как видео карты nvidia ^__^ Причем все это делается через удобную графическую программу установки драйверов.
По умолчанию управляет сетевыми устройствами новый демон
nwam, который позволяет легко подключится к wi-fi сети или установить соединение по обычной ethernet карте. В комплекте есть довольно красивый аплет для манипулирования сетевыми соединениями.
Новый менеджер пакетов IPS - детище Яна Мердока, основателя дистрибутива Debian, предоставляет удобный интерфейс взаимодействия с репозиториями и установкой пакетов. Так же в комплекте поставляется удобный GUI для него.

Это все конечно круто, но добавим небольшую ложку дегтя в бочку меда:
  1. Хотя в стандарнтых репозиториях есть такие мультимедийные приложения, как Rhythmbox, Totem и SongBird - нет кодеков для полноценного наслаждения музыкой и фильмами. Если взять к примеру популярный в настоящий момент дистрибутив Ubuntu, то там есть такие же проблемы, но они решаются, в отличии от OpenSolaris парой щелчков мыши. Надеюсь в ближайшее время сообщество добавит в репозитории актуальные сборки таких программ как Mplayer и пр. (Движение в этом направлении уже заметно, совсем недавно добавил новый репозиторий extra и установил поддержку flash для firefox`а)
  2. Ну наверное это характерно для всех систем, находящихся под грифом development - это куча не стабильного софта: например pidgin и transmission у меня периодически вылетают, а об таких фичах как невозможность обновится из-за того, что не возможно сделать snapshot рабочей среды, т.к. я делегировал управления каким-либо dataset`ом зоне я вообще молчу ;-)
  3. подвисшее состояние из-за покупки синим гигантом корпорации Sun microsystems, не знаешь чего ожидать - то ли проект прикроют, то ли нет...
Для меня, как для разработчика софта, активно использующего продукты Sun - это идеальный выбор, для вас - решать вам. Скоро напишу по подробней про каждую компоненту