1> РЕЗЮМЕ
Изначально я пробовал этот класс с загрузочной изоляцией для загрузки Jiber Hibernate 3.6.4 с JBoss 5.1.0.GA.
Это определенно НЕ возможно. Под колпаком скрывается магия, которая не позволяет использовать любую версию Hibernate с поддержкой JPA2.
Я действительно разочарован тем, что проект JBoss не предоставил какой-либо патч или пакет обновления для поддержки JPA2 на 5.1.0.GA.
2> ВРЕМЕННОЕ РЕШЕНИЕ : «Решение ядра»
Мне удалось использовать JPA2 с JBoss 5.1.0.GA
Я опишу здесь мой рецепт. Это скорее подтверждение концепции, которую вы можете использовать для создания собственного решения.
Ингредиенты:
- 1 WAR архив
- 1 сервлет
- 1 автономное Java-приложение (J2SE)
Рецепт:
Шаг 1 : создание автономного приложения (APP)
Это приложение будет получать инструкции от сервлета для использования Hibernate.
Я оставляю вам выбор способа общения.
Поскольку приложение использует JPA2, ему потребуется файл persistence.xml
, расположенный в папке META-INF
.
Начиная с JBoss 5.x, когда вы развертываете WAR, JBoss будет сканировать WAR и все его вспомогательные развертывания для поиска и развертывания вслепую persistence.xml
файлов. Например, переименуйте ваш файл persistence.xml
в my-persistence.xml
. Используйте приведенный ниже код при сборке EntityManagerFactory
(не позволяйте JBoss развертывать файл persistence.xml).
UPDATE:
Этот метод работает, но Hibernate выдвигает некоторые странные предупреждения. Чтобы прекратить эти предупреждения, я решил поместить папку META-INF
и файл постоянства (теперь переименованный в persistence.xml
) за пределы WAR. В моем случае я выбрал специальную папку конфигурации на жестком диске и добавил ее в путь к классам. Больше нет странных предупреждений и не требуется специальный загрузчик классов для загрузки файла персистентности.
Я оставляю на ваше усмотрение выбор между использованием пользовательского загрузчика классов или изменением местоположения файла постоянства. В обоих случаях JBoss не найдет файл персистентности.
Шаг 2 : Сборка сервлета
Когда сервлету требуется доступ к базе данных, он запускает приложение и сообщает ему, что делать.
За запуск APP сервлет отвечает за создание новой JVM и создание пути к классам APP. Прочитайте код ниже для (порождение JVM). Путь к классам легко может быть собран, поскольку все необходимые файлы jar будут в каталоге /lib
архива WAR ...
Шаг 3 : создание архива WAR
Создайте WAR-архив, в который вы поместите сервлет и автономное приложение, упакованное в JAR-файл. Приложение будет зависеть от WAR.
Запретить JBoss развертывание persistence.xml
// Install a proxy class loader for adding renamed persistence.xml file
Thread t = Thread.currentThread();
ClassLoader clOriginal = t.getContextClassLoader();
t.setContextClassLoader(new SpecialClassLoader(clOriginal, "META-INF/my-persistence.xml"));
// Build EntityManagerFactory
EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName);
// Restore original class loader
t.setContextClassLoader(clOriginal);
//...
private class ProxyClassLoader extends ClassLoader {
private ClassLoader realClassLoader;
private String hiddenFromJBossPersistenceFile;
public ProxyClassLoader(ClassLoader realClassLoader, String hiddenFromJBossPersistenceFile) {
this.realClassLoader = realClassLoader;
this.hiddenFromJBossPersistenceFile = hiddenFromJBossPersistenceFile;
}
public void clearAssertionStatus() {
realClassLoader.clearAssertionStatus();
}
public boolean equals(Object obj) {
return realClassLoader.equals(obj);
}
public URL getResource(String name) {
return realClassLoader.getResource(name);
}
public InputStream getResourceAsStream(String name) {
return realClassLoader.getResourceAsStream(name);
}
public Enumeration<URL> getResources(String name) throws IOException {
ArrayList<URL> resources = new ArrayList<URL>();
if (name.equalsIgnoreCase("META-INF/persistence.xml")) {
resources.add(getResource(this.hiddenFromJBossPersistenceFile));
}
resources.addAll(Collections.list(realClassLoader.getResources(name)));
return Collections.enumeration(resources);
}
public int hashCode() {
return realClassLoader.hashCode();
}
public Class<?> loadClass(String name) throws ClassNotFoundException {
return realClassLoader.loadClass(name);
}
public void setClassAssertionStatus(String className, boolean enabled) {
realClassLoader.setClassAssertionStatus(className, enabled);
}
public void setDefaultAssertionStatus(boolean enabled) {
realClassLoader.setDefaultAssertionStatus(enabled);
}
public void setPackageAssertionStatus(String packageName, boolean enabled) {
realClassLoader.setPackageAssertionStatus(packageName, enabled);
}
public String toString() {
return realClassLoader.toString();
}
}
Создание JVM
public static Process createProcess(final String optionsAsString, final String workingDir, final String mainClass, final String[] arguments) throws IOException {
String jvm = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
String[] options = optionsAsString.split(" ");
List<String> command = new ArrayList<String>();
command.add(jvm);
command.addAll(Arrays.asList(options));
command.add(mainClass);
command.addAll(Arrays.asList(arguments));
//System.out.println(command);
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.directory(new File(workingDir));
return processBuilder.start();
}
public static void makeItRun() {
try {
// Start JVM
String classPath = buildClassPath();
String workingDir = getSuitableWorkingDir();//or just "."
Process java = createProcess("-cp \"" + classPath + "\"", workingDir, my.package.APP.class.getCanonicalName(), "-the -options -of -my -APP");
// Communicate with your APP here ...
// Stop JVM
java.destroy();
} catch(Throwable t) {
t.printStackTrace();
}
}