Мне удалось заставить поставщика EclipseLink 2.3.0 JPA работать с классами домена, которые не внутри пакета, следующим образом.
Далее я покажу, как настроить приложение grails, использующее EclipseLink в качестве поставщика JPA, для сохранения классов домена и запуска приложения в веб-контейнере Tomcat 6.
Начните с
Подсказка: не помещайте доменные классы в пакеты. EclipseLink потерпит неудачу при обработке, например, "model.Person" из-за точки в имени, но будет хорошо, например, с. «Персона» (сравните с вышеупомянутым постом).
Отредактируйте "grails-app \ domain \ Person.groovy" следующим образом:
import javax.persistence.*;
@Entity
class Person {
@Id
@GeneratedValue
long id;
@Basic
long version;
@Basic
String firstName
@Basic
String lastName
static constraints = {
firstName(nullable:true)
lastName(nullable:true)
}
}
Создание контроллера и представления для определенной сущности:
grails generate-controller Person
grails generate-view Person
Теперь нам нужно немного изменить сгенерированный контроллер, чтобы все действия, модифицирующие сущность (сохранение, редактирование, обновление, удаление), были инкапсулированы в транзакцию (сравните с ошибкой GPGORMJPA-6). Это делается путем инкапсуляции всего действия в блок «Person.withTransaction».
Измените "grails-app \ controllers \ PersonController.groovy" следующим образом:
[...]
def save = {
Person.withTransaction {
[...original code stays in this block...]
}
}
[...]
def edit = {
Person.withTransaction {
[...original code stays in this block...] }
}
}
def update = {
Person.withTransaction {
[...original code stays in this block...]
}
}
def delete = {
Person.withTransaction {
[...original code stays in this block...]
}
}
[...]
Теперь мы определяем единицу сохраняемости "manager", которая задает набор классов для управления сохранением (класс "Person") и какой поставщик JPA будет использовать для этих классов (в нашем случае EclipseLink).
Создайте файл "web-app \ WEB-INF \ classes \ META-INF \ 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">
<persistence-unit name="manager" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>Person</class>
<properties>
<property name="eclipselink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>
Обратите внимание: файл будет удален, если очищен «целевой» каталог проекта, например, когда "grails clean" вызывается явно. Так что неплохо сделать резервную копию файла вне «целевой» директории.
Чтобы сделать EclipseLink доступным для проекта grails, загрузите ZIP-файл установщика EclipseLink 2.3.0 и извлеките «eclipselink.jar» из «eclipselink \ jlib \» в ZIP-папку «lib» проекта grails:
lib\eclipselink.jar
Теперь нам нужно убедиться, что bean-объект "entityManagerFactory" и "actionManager "создаются при запуске веб-приложения. Бины предоставят необходимый доступ JPA-провайдеру, который будет управлять всей устойчивостью.
Отредактируйте "grails-app \ conf \ spring \ resources.groovy" следующим образом:
beans = {
entityManagerFactory(org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean) {
dataSource = ref("dataSource")
beanClassLoader = ref("classLoader")
loadTimeWeaver = new org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver()
}
transactionManager(org.springframework.orm.jpa.JpaTransactionManager) {
entityManagerFactory = entityManagerFactory
}
}
Обратите внимание, что в указанных выше объявлениях мы указали специальный loadTimeWeaver, который позволяет поставщику постоянства JPA подключаться к байт-коду java на лету во время выполнения. При использовании EclipseLink это важно. Если просто использовать org.springframework.instrument.classloading.SimpleLoadTimeWeaver для целей тестирования, это позволяет запустить веб-приложение, но при доступе к сущностям JPA вы столкнетесь с такими исключениями, как «0 не является известным типом сущности», так как поставщик сохраняемости не может подключиться к управлению классами сущностей во время выполнения.
Использование InstrumentationLoadTimeWeaver немного хлопотно, так как будет работать, только если
- виртуальная машина java, выполняющая сервер веб-приложений, запускается с использованием java-агента «spring-agent», AND
- наше веб-приложение загружается сервером Tomcat с помощью специального загрузчика классов с именем "TomcatInstrumentableClassLoader"
Для этого сначала загрузите spring-agent-2.5.6.SEC02.jar и spring-instrument-tomcat-3.0.5.RELEASE.jar .
Предположим, что вы установили сервер Tomcat в каталог% CATALINA_HOME%.
- Скопируйте загруженные файлы jar "spring-agent-2.5.6.SEC02.jar" и "spring-instrument-tomcat-3.0.5.RELEASE.jar" в% CATALINA_HOME% \ lib
Теперь мы изменим "% CATALINA_HOME% \ bin \ catalina.bat", который используется, например, сценарии запуска и остановки Tomcat, чтобы убедиться, что JVM, выполняющая Tomcat, работает с Java-агентом «spring-agent».
Добавьте следующее в "% CATALINA_HOME% \ bin \ catalina.bat" в разделе "Выполнить требуемую команду" после всех эхосигналов:
if exist "%CATALINA_HOME%\lib\spring-agent-2.5.6.SEC02.jar" set JAVA_OPTS=%JAVA_OPTS% -javaagent:%CATALINA_HOME%\lib\spring-agent-2.5.6.SEC02.jar
Когда Tomcat запущен, скрипт теперь проверит, находится ли «spring-agent-2.5.6.SEC02.jar» в директории lib, и если это так, он добавит его в качестве агента java к JAVA_OPTS, которые используются в качестве параметров командной строки для JVM при запуске Tomcat.
Чтобы включить «TomcatInstrumentableClassLoader» в качестве загрузчика классов для нашего веб-приложения, мы добавляем файл «web-app \ META-INF \ context.xml» в наш проект grails со следующим содержимым:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
</Context>
Обратите внимание, что теги в "context.xml" чувствительны к регистру. Поэтому не пытайтесь изменить <<b> C ontext> на <<b> c ontext> (или аналогичные вещи) - это не удастся!
Перед тем, как упаковать и развернуть наше веб-приложение, мы определяем, какой источник данных использовать для обеспечения устойчивости. Для тестирования мы просто определяем базу данных HSQLDB in-memeory.
Отредактируйте "grails-app \ conf \ DataSource.groovy" следующим образом:
[...]
development {
dataSource {
dbCreate = "create-drop"
url = "jdbc:hsqldb:mem:testDB"
}
}
test {
dataSource {
dbCreate = "create-drop"
url = "jdbc:hsqldb:mem:testDb"
}
}
production {
dataSource {
dbCreate = "create-drop"
url = "jdbc:hsqldb:mem:testDB"
}
}
[...]
Теперь мы готовы создать WAR-архив нашего веб-приложения, используя:
grails war
WAR будет помещен в «целевой» каталог нашего проекта.
В "% CATALINA_HOME% \ webapps"
- создать каталог "GrailsJPA"
- извлечь все содержимое созданного архива WAR в этот каталог
Обратите внимание: не помещайте WAR в "% CATALINA_HOME% \ webapps" и надейтесь, что он развернут при запуске Tomcat. Это не удастся!
Теперь запустите сервер Tomcat, используя скрипт
"%CATALINA_HOME%\bin\startup.bat"
После того, как Tomcat запущен и работает, используйте ваш браузер, чтобы перейти к
http://localhost:8080/GrailsJPA
Теперь нажмите на контроллер «PersonController», чтобы создавать, обновлять, перечислять и удалять сущности Person через JPA с использованием поставщика EclipseLink JPA.
Но с использованием классов домена, которые находятся внутри пакета, все равно потерпит неудачу за исключением упомянутого выше поста. Эта проблема до сих пор не решена.
Ссылки для скачивания