Lotus Domino + JPA + Guice

Использование Domino в качестве application server может быть вызвано двумя причинами:
- желание обойтись единственным сервером приложений, в случае, когда уже есть инфраструктура на Domino
- чисто спортивным интересом

Если в компании есть готовая инфраструктура на стеке Lotus Domino/Notes, то появляется соблазн использовать LDN в качестве полноценного java appserver. Категорически рекомендую отказаться от этой идеи и использовать нормальные сервера: доступ к встроенному app серверу индусы попытались максимально ограничить, чтобы не создавать внутреннюю конкуренцию между LDN и WebSphere. Отсутствие поддержки дескрипторов web.xml ( или тем более Java EE ) превращает java разработку в ад. Т.о. несмотря на наличие поддержки JSF 1.2 ( aka XPages ), использовать Domino как полноценный java app server крайне затруднительно. Значительно проще убрать Domino в бэкенд, выставив в качестве фронтенда полноценный сервер типа GlassFish, JBoss, Tomcat или Jetty. Такую конфигурацию как-нибудь опишу( суть в создании нотусовой сессии из внешнего контейнера. В качестве решения можно использовать Basic авторизацию либо LTPA токены, на основании которых делается SSO: проброс сессии до LDN ).

Однако, некоторые горячие головы не отпускает мысль использовать возможности встроенного контейнера Domino для решения enterprise задач. На практике такое решение будет проигрывать полноценному app серверу, но с академической точки зрения задача имеет смысл.

В данной статье описывается решение для интеграции Domino с внешней РСУБД, при этом домино выступает в качестве WEB фронтенда.
Задача: задеплоить на Lotus Domino Server приложение, используещее ORM для хранения объектов в РСУБД( т.е. сами данные в domino не хранятся ).
Решение: JPA+Hibernate в качестве ORM решения и Guice в качестве контейнера IoC.

Зависимости

Для сборки зависимых библиотек используем технику, ранее описанную тут
Создаем новый maven проект и подключаем библиотеки:

<dependencies>
	<!-- IoC container -->
	<dependency>
		<groupId>com.google.inject</groupId>
		<artifactId>guice</artifactId>
		<version>3.0</version>
	</dependency>
	<dependency>
		<groupId>com.google.inject.extensions</groupId>
		<artifactId>guice-persist</artifactId>
		<version>3.0</version>
	</dependency>

	<!-- hibernate jpa -->
	<dependency>
	   <groupId>hibernate</groupId>
	   <artifactId>hibernate-entitymanager</artifactId>
	   <version>3.4.0.GA</version>
	</dependency>

	<!-- database -->
	<dependency>
		<groupId>com.h2database</groupId>
		<artifactId>h2</artifactId>
		<version>1.3.154</version>
		<type>jar</type>
		<scope>compile</scope>
	</dependency>

	<!-- logging -->
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-simple</artifactId>
		<version>1.6.1</version>
		<type>jar</type>
		<scope>compile</scope>
	</dependency>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-api</artifactId>
		<version>1.6.1</version>
		<type>jar</type>
		<scope>compile</scope>
	</dependency>

</dependencies>

добавляем папку src/meain/webapp/WEB-INF/ и кладем туда пустой web.xml.
Выполнив mvn war:war в корне проекта, получим, кроме прочего, папку target\PROJECT_VERSION\WEB-INF\lib , содержащую все указанные зависимости.

В Domino Designer Eclipse создаем новую БД, переключаемся на java perspective и создаем папки WebContent\WEB_INF\lib и WebContent\WEB_INF\src. Подробности можно почитать здесь
Копируем в WEB_INF\lib наши зависимости и подключаем их в Build Path проекта.

JPA:

Person Entity:

import javax.persistence.*;
@Entity
public class Person {
	@Id @GeneratedValue
	private String id;
	private String fn;
	private String email;

	public Person(){}

	public Person(String fn, String email) {
		this.fn = fn;
		this.email = email;
	}

	// getters, setters, equals, hashCode, toString
}

Person DAO

import javax.persistence.EntityManager;

import com.google.inject.Inject;
import com.google.inject.persist.Transactional;

public class PersonDao {
    @Inject EntityManager em;

    @Transactional
    public Person savePerson(Person person) {
        return em.merge(person);
    }

    @Transactional
    public List<Person> getAll(){
    	return em.createQuery("Select person from Person person").getResultList();
    }
}

persistence.xml

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
	version="1.0">

	<!-- A JPA Persistence Unit -->
	<persistence-unit name="myFirstJpaUnit"
		transaction-type="RESOURCE_LOCAL">
		<provider>org.hibernate.ejb.HibernatePersistence</provider>
		<!-- JPA entities must be registered here -->
		<class>ru.turumbay.demo.guice_jpa.Person</class>
		<exclude-unlisted-classes>true</exclude-unlisted-classes>
		<properties>
			<property name="hibernate.hbm2ddl.auto" value="update" />
			<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
			<property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
			<property name="hibernate.connection.url" value="jdbc:h2:mem:test"/>
		</properties>
	</persistence-unit>
</persistence>

Guice Persistence

Guice ( aka джус ) – IoC фреймворк от google. Был выбран исключительно из желания познакомиться с альтернативами хорошо известному Spring. Стремительно рекомендую: проект крайне дружелюбен и легок в использовании

import com.google.inject.Inject;
import com.google.inject.persist.PersistService;

public class PersistServiceStarter{
	 @Inject
	 PersistServiceStarter(PersistService service) {
		  service.start();
	 }
}

На этом написание собственно серверной части заканчивается. Осталось заставить работать это добро под домино.

Domino Integration

Создадим managed bean. Теоретически, можно сделать управляемым сам PersonDao, но мы пойдем свои путем:

public class MyBean {
	static {
		new DbInitializer(); // токмо в целях демонстрации...
	}
	private Injector injector;
	public MyBean(){
		injector = Guice.createInjector(new JpaPersistModule("myFirstJpaUnit"));
    	injector.getInstance(PersistServiceStarter.class);
	}

	public List<Person> getAll(){
		PersonDao dao = injector.getInstance(PersonDao.class);
		return dao.getAll();
	}
}

Т.к. в примере используется in-memory h2 database, то время жизни данных в РСУБД равно времени жизни JVM(точнее, времени жизни нашего приложения). Чтобы было чего демонстрировать, нужно при каждом запуске набивать БД данными. Использование статического блока инициализации не самый правильный, зато самый простой способ: в кач-ве quick and dirty варианта вполне сгодится.
class DbInitializer {
	public DbInitializer(){
		Injector injector= Guice.createInjector(new JpaPersistModule("myFirstJpaUnit"));
		injector.getInstance(PersistServiceStarter.class);
		PersonDao service = injector.getInstance(PersonDao.class);

		service.savePerson( new Person("Vasya Pupken", "pupken@mail.ru") );
		service.savePerson( new Person("Ilya Golberg", "turumbay@gmil.com") );
	}
}

Делаем наш бин управляемым(managed):
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
  <managed-bean>
    <managed-bean-name>mybean</managed-bean-name>
    <managed-bean-class>ru.turumbay.xpages.MyBean</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
  </managed-bean>
</faces-config>

Ну и собственно сама XPage:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
	Preved from Guice and Hibernate JPA:
	<xp:br></xp:br>
	<xp:dataTable id="dataTable1" rows="30" value="#{mybean.all}"
		var="currentPerson">
		<xp:column id="fnColumn">
			<xp:text escape="true" id="fnField" value="#{currentPerson.fn}">
			</xp:text>
		</xp:column>
		<xp:column id="emailColumn">
			<xp:text escape="true" id="emailField" value="#{currentPerson.email}">
			</xp:text>
		</xp:column>
	</xp:dataTable>
</xp:view>

Вид проекта в DDE

Результат:

This entry was posted in Using Java in Lotus Notes. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s