2012-09-18 5 views
3

내 요구 사항은 hibernate를 사용하여 다양한 데이터베이스 (특히 SQL Server, MySQl 및 Postgres)를 매핑하는 것이다. db 레코드에서 xml 파일을 만듭니다.OSGi Hibernate에서 런타임 pojos를 가진 단편 번들

나는 최대 절전 모드에서 JAssist를 사용하여 런타임에 hbm 파일과 pojos를 생성합니다. 내 코드는 훌륭하게 작동합니다. 추가 모듈화를 위해 각 데이터베이스의 조각 번들을 구현합니다. 따라서 내 호스트 번들은 런타임 클래스 생성을 처리하고 클래스 로더, hbm 파일 작성 논리 및 BL에 추가합니다. fragment는 매개 변수를 전달하여 호출합니다.

내가 각 데이터베이스에 대한 단편 번들을 만들 때, 나의 호스트 번들에서 만든 런타임 POJO 클래스 내 조각 번들에서 볼 수, 내가 함께 확인 "는 Thread.currentThread(). getContextClassLoader().로 loadClass()" 최대 절전 모드가 테이블 매핑 클래스를 찾을 수없는 경우 하고 인스턴스를 만들 수,

내가 조각 번들에서 최대 절전 모드 기능을 호출 할 때 문제가 이다, 나는 "엔티티가 매핑되지"점점 오전은, AFAIK이 예외가 제공됩니다. 그래서 나는 Hibernate가 나의 런타임 pojo 클래스를 찾지 못하고 있다고 생각한다. 그것은 호스트에서 찾을 수 있습니다.

호스트 : 런타임 뽀조 생성, HBM 및 CFG 생성과 그 갱신 논리 BL은

조각 : 최대 절전 층, 호출 최대 절전 모드 기능, XML 생성 로직은

답변

3

이 문제는 항상 나타납니다 당신이 경우 둘 이상의 번들에 대해 Hibernate를 사용한다. Hibernate 설정에서 매핑 파일과 pojo 클래스 파일이 어느 번들에 들어 있는지 알 수 없다. Hibernate는 OSGI가 이것을 제공하는 메커니즘을 사용하지 않는다. 결과적으로 Hibernate는 Hibernate 라이브러리와 같은 번들에있는 매핑 파일들과 클래스들을 찾는다.

이 문제에 대한 전문적인 솔루션 (타사 제품)이 있는지 여부는 잘 모르겠습니다.

  1. 당신의 조각 번들을 잊고 하나의 묶음으로 모든 하이버 네이트 라이브러리, 매핑 파일, POJO를 모든 데이터베이스에 대한 최대 절전 모드/HQL을 사용하여 클래스를 넣어 :

    이 문제를 해결하기 위해 두 가지 가능성이 있습니다. 다른 hibernate.cfg.xml 파일을 사용할 때 다른 데이터베이스로 전환 할 수 있습니다. 각 데이터베이스에는 자체 구성 파일이 있습니다. 이 hibernate.cfg.xml 파일은 번들 외부에있을 수 있습니다.

    • 도 다른 번들
    • 재정에 POJO 클래스를 찾아 자신의 클래스 로더를 쓰기 당신이

      에있는이 클래스에서 org.hibernate.cfg.Configuration를 확장 자신의 구성 클래스를 쓰기 다른 번들에서도 리소스를 찾는 방식으로 addResource (String resourceName, ClassLoader classLoader)
    • doConfigure 및 buildSessionFactory를 오버라이드하므로 표준 클래스 로더 대신 클래스 로더를 사용합니다 (Thread.setContextClassLoader를 사용하고 수퍼 클래스의 메서드 호출 , from 표준 Hibernate Configuration 클래스).
    • 은 Configuration 인스턴스를 리턴하는 다른 모든 메소드를 오버라이드 (override)하므로, Hibernate Configuration 클래스가 아닌 Configuration 클래스의 인스턴스를 리턴한다.

우리는 그것은 약간의 작업이었다 솔루션 2를했지만 지금은 잘 실행됩니다. (다시 생각해 보면 Hibernate 버전을 다시 바꿀 때 약간의 작업이 필요할 것입니다.)

1

org.hibernate.internal.util.ClassLoaderHelper에 대해 살펴보십시오.

당신이해야 할 일은, 당신의 엔티티 클래스를 해결할 수있는 ClassLoader로 ClassLoader를 대체하기 만하면됩니다. Hibernate-Osgi는 이것을 OSGI ClassLoader (org.hibernate.osgi.HibernateBundleActivator 참조)로 설정하고있다. 그래서 다음과 같은 제안 :

BundleWideClassLoader cl = new BundleWideClassLoader(); 

if (ClassLoaderHelper.overridenClassLoader != null 
    && ClassLoaderHelper.overridenClassLoader instanceof OsgiClassLoader) 
{ 
    OsgiClassLoader ocl = (OsgiClassLoader)ClassLoaderHelper.overridenClassLoader; 
    for (Bundle b : cl.getBundles()) { 
     ocl.addBundle(b); 
    } 
} else { 
    ClassLoaderHelper.overridenClassLoader = new BundleWideClassLoader(); 
} 

나는이 루틴을 수행하고 super.buildSessionFactory을 반환 buildSessionFactory를 재정 의하여 내 HibernateConfiguration 클래스에이를 넣어. 나는 당신의 BundleActivators의 각각의 새로운 BundleClassLoader를 만들고 이렇게 레지스트리의 어떤 종류에 추가하는 것이 좋습니다

public class BundleClassLoader extends ClassLoader 
{ 
/** 
* Bundle context. 
*/ 
private BundleContext context; 

/** 
* Constructor. 
* @param ctx Bundle Context 
*/ 
public BundleClassLoader(BundleContext ctx) { 
    this.context = ctx; 
} 

@Override 
protected Class<?> findClass(String name) throws ClassNotFoundException { 
    return this.context.getBundle().loadClass(name); 
} 

@Override 
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 
    Class clazz = this.findClass(name); 
    if (resolve) { 
     this.resolveClass(clazz); 
    } 

    return clazz; 
} 

@Override 
public URL findResource(String name) { 
    return this.context.getBundle().getResource(name); 
} 

/** 
* Returns bundle context. 
* @return bundle context 
*/ 
public BundleContext getBundleContext() { 
    return this.context; 
} 

} 

:

은 BundleWideClassLoader이

public class BundleWideClassLoader extends ClassLoader 
{ 

@Override 
protected Class<?> findClass(String name) throws ClassNotFoundException { 
    for (BundleClassLoader cl : this.getAllClassLoader()) { 
     try { 
      Class clazz = cl.findClass(name); 
      return clazz; 
     } catch (Exception ex) { 
     } 
    } 
    throw new ClassNotFoundException(name); 
} 

@Override 
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 
    Class clazz = this.findClass(name); 
    if (resolve) { 
     this.resolveClass(clazz); 
    } 
    return clazz; 
} 

@Override 
public URL findResource(String name) { 
    for (BundleClassLoader cl : this.getAllClassLoader()) { 
     URL ret = cl.findResource(name); 
     if (ret != null) { 
      return ret; 
     } 
    } 
    return null; 
} 

/** 
* Returns a list of all available BundleClassLoader. 
* 
* @return classloader 
*/ 
public HashSet<BundleClassLoader> getAllClassLoader() { 
    // 
    // Do some magic here to get your ClassLoaders from all of your Bundles 
    // 
} 

/** 
* Returns a list of all bundles which are registered in this BundleWideClassLoader. 
* 
* @return list of managed bundles 
*/ 
public HashSet<Bundle> getBundles() { 
    HashSet<Bundle> bundles = new HashSet<>(); 
    for (BundleClassLoader cl : this.getAllClassLoader()) { 
     bundles.add(cl.getBundleContext().getBundle()); 
    } 
    return bundles; 
} 

} 

그리고 마지막으로 같은 BundleClassLoader 보인다 BundleWideClassLoader는 거기에서 BundleClassLoader의 목록을 가져올 수 있습니다. 번들이 중지되거나 제거 될 때 BundleClassLoader를 제거하는 것을 잊지 마십시오.

1

현재 Hibernate OSGi에는 몇 가지주의 사항이 있으며, 그 중 하나에는 하나의 지속성 단위 클라이언트 번들이 필요합니다. 다양한 이유로, 우리는 영속성 엔티티, 매핑 및 자원 처리를 담당하는 ClassLoader를 빌드 할 때 "requestingBundle"을 사용해야합니다.

는 살펴 유무 : https://github.com/hibernate/hibernate-orm/blob/master/hibernate-osgi/src/main/java/org/hibernate/osgi/OsgiClassLoader.java

OsgiPersistenceProviderService을하고 서비스를 호출 할 때 OsgiSessionFactoryService는 둘 다 클래스 로더에 "requestingBundle"를 추가합니다. Johanna가 제안했듯이, 어떤 번들이 requestingBundle이나 persistence.xml 파일 자체의 위치를 ​​제외하고 영속성 단위를 구성하는지 알 수있는 적절한 방법은 없습니다.

그러나 이러한 설정을 더 잘 지원하는 방법에 대한 아이디어를 듣고 싶습니다. 원래는 "나는 지속성 단위 x의 일부입니다"라는 의미의 매니페스트에 추가 메타 데이터를 가지고 놀았지만 결코 실제로 생각할 시간이 없었습니다.

확실히 이 아니며은 ClassLoaderHelper를 사용하여 위에서 권장 된 솔루션을 사용하십시오. ORM 5에서 완전히 사라질 것입니다. ORM 4의 정적 인 특성 때문입니다.

+0

생성됨 https://hibernate.atlassian.net/browse/HHH-8658 - 환영합니다 . – brmeyer

+0

brmeyer에게 감사의 말을 전합니다.하지만 jdbc로 옮겼습니다. – sailor