FAQ
Dain Sundstrom (who is a member of Geronimo project) did some
preliminary testing of Cayenne JPA provider in the OpenEJB container
last week - you've seen some jiras that he opened. I am taking
further discussion to the list (not sure if Dain is subscribed, so I
am cc'ying to him as well).

So the enhancer... I tried to run the OpenEJB JpaTest [1] with
Cayenne provider. It fails to enhance the Employee object [2], even
if it is explicitly mentioned in the PersistenceUnit, because it was
loaded in the JVM *before* Cayenne provider was started and
Provider.createContainerEntityManagerFactory(..) was called.

I was trying to think of ways to "fix" it, but considering that
java.lang.instrument.Instrumentation doesn't allow to enhance already
loaded classes ("redefineClasses" method places serious limitations
on what can be done, namely adding new fields is not allowed), looks
like JPA users will have to deal with specific startup order
requirements. In-container and Java SE operation modes will look
different:

1. In-container: provider shouldn't directly access its own agent,
and simply register a needed ClassTransformer with container-provided
PersistenceUnitInfo. Container on the other hand has the
responsibility to hook up PersistenceUnitInfo implementor to the
agent, and ensure that provider is started *before* and persistence
classes are loaded in the app class loader. So I wonder whether the
fact that JpaTest worked with OpenJPA provider by some coincidence?

2. Standalone: for the enhancer to work, an application must ensure a
call to Persistence.createEntityManagerFactory() prior to the entity
classes loaded in runtime. This sucks, and the only way around is to
run enhancer straight from the agent. I think that's what OpenJPA
does. Some time ago we decided [3] to avoid putting any Cayenne
runtime classes in the agent, but it looks like we don't have a
choice. Unless somebody can suggest a better way of providing
reliable runtime enhancement, I will change the behavior to provide a
"fat" agent.

[1] https://svn.apache.org/repos/asf/incubator/openejb/trunk/openejb3/
container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/
JpaTest.java
[2] https://svn.apache.org/repos/asf/incubator/openejb/trunk/openejb3/
container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/
Employee.java
[3] http://objectstyle.org/cayenne/lists/cayenne-devel/2006/08/0088.html

Andrus

P.S. Dain - are there any other show stopper issues in your testing
(except for no EJBQL)?

Search Discussions

  • Dain Sundstrom at Feb 22, 2007 at 5:46 pm
    Sorry, got busy and missed this email.

    This is such a common problem, it was addressed directly by the JPA
    specs. When loading classes for inspection use the class loader
    returned from
    javax.persistence.spi.PersistenceUnitInfo.getNewTempClassLoader().

    For Cayenne's own PersistenceUnitInfo implementation, I suggest you
    copy org.apache.openejb.core.TemporaryClassLoader which I copied from
    OpenJPA and cleaned up.

    -dain
    On Feb 20, 2007, at 4:31 AM, Andrus Adamchik wrote:

    Dain Sundstrom (who is a member of Geronimo project) did some
    preliminary testing of Cayenne JPA provider in the OpenEJB
    container last week - you've seen some jiras that he opened. I am
    taking further discussion to the list (not sure if Dain is
    subscribed, so I am cc'ying to him as well).

    So the enhancer... I tried to run the OpenEJB JpaTest [1] with
    Cayenne provider. It fails to enhance the Employee object [2], even
    if it is explicitly mentioned in the PersistenceUnit, because it
    was loaded in the JVM *before* Cayenne provider was started and
    Provider.createContainerEntityManagerFactory(..) was called.

    I was trying to think of ways to "fix" it, but considering that
    java.lang.instrument.Instrumentation doesn't allow to enhance
    already loaded classes ("redefineClasses" method places serious
    limitations on what can be done, namely adding new fields is not
    allowed), looks like JPA users will have to deal with specific
    startup order requirements. In-container and Java SE operation
    modes will look different:

    1. In-container: provider shouldn't directly access its own agent,
    and simply register a needed ClassTransformer with container-
    provided PersistenceUnitInfo. Container on the other hand has the
    responsibility to hook up PersistenceUnitInfo implementor to the
    agent, and ensure that provider is started *before* and persistence
    classes are loaded in the app class loader. So I wonder whether the
    fact that JpaTest worked with OpenJPA provider by some coincidence?

    2. Standalone: for the enhancer to work, an application must ensure
    a call to Persistence.createEntityManagerFactory() prior to the
    entity classes loaded in runtime. This sucks, and the only way
    around is to run enhancer straight from the agent. I think that's
    what OpenJPA does. Some time ago we decided [3] to avoid putting
    any Cayenne runtime classes in the agent, but it looks like we
    don't have a choice. Unless somebody can suggest a better way of
    providing reliable runtime enhancement, I will change the behavior
    to provide a "fat" agent.

    [1] https://svn.apache.org/repos/asf/incubator/openejb/trunk/
    openejb3/container/openejb-core/src/test/java/org/apache/openejb/
    core/cmp/jpa/JpaTest.java
    [2] https://svn.apache.org/repos/asf/incubator/openejb/trunk/
    openejb3/container/openejb-core/src/test/java/org/apache/openejb/
    core/cmp/jpa/Employee.java
    [3] http://objectstyle.org/cayenne/lists/cayenne-devel/
    2006/08/0088.html

    Andrus

    P.S. Dain - are there any other show stopper issues in your testing
    (except for no EJBQL)?
  • Andrus Adamchik at Feb 22, 2007 at 6:22 pm
    I see how TemporaryClassLoader operates. We haven't been using
    'getNewTempClassLoader' in the provider code as of yet. Let me poke
    around and see if I am overcomplicating the issue... I still don't
    understand how to push an enhanced class back into the app
    classloader space, but maybe I am wrong (still thinking in Cayenne
    classic terms), and this is not needed.

    Andrus

    On Feb 22, 2007, at 7:46 PM, Dain Sundstrom wrote:
    Sorry, got busy and missed this email.

    This is such a common problem, it was addressed directly by the JPA
    specs. When loading classes for inspection use the class loader
    returned from
    javax.persistence.spi.PersistenceUnitInfo.getNewTempClassLoader().

    For Cayenne's own PersistenceUnitInfo implementation, I suggest you
    copy org.apache.openejb.core.TemporaryClassLoader which I copied
    from OpenJPA and cleaned up.

    -dain
  • Dain Sundstrom at Feb 22, 2007 at 6:46 pm
    You can't really push a class back into the app. Instead you must
    wait for the app to load (pull) a class and hook the load via the
    javaagent.

    In a managed (container) environment this works quite well because
    the container can guarantee that the JPA provider is full initialized
    before any app code is called. In an unmanaged environment life is
    much more difficult since it is by definition the application code
    that initializes the system. To get around this, you will need the
    javaagent to search for persistence units and determine which classes
    need to be enhanced. One nice thing, is most people will use the
    @Entity annotation instead of XML to declare their persistent beans,
    and this entity is easy to detect directly using asm. You should ask
    David Blevins about his xbean-finder code which is designed to detect
    such annotations.

    -dain
    On Feb 22, 2007, at 10:21 AM, Andrus Adamchik wrote:

    I see how TemporaryClassLoader operates. We haven't been using
    'getNewTempClassLoader' in the provider code as of yet. Let me poke
    around and see if I am overcomplicating the issue... I still don't
    understand how to push an enhanced class back into the app
    classloader space, but maybe I am wrong (still thinking in Cayenne
    classic terms), and this is not needed.

    Andrus

    On Feb 22, 2007, at 7:46 PM, Dain Sundstrom wrote:
    Sorry, got busy and missed this email.

    This is such a common problem, it was addressed directly by the
    JPA specs. When loading classes for inspection use the class
    loader returned from
    javax.persistence.spi.PersistenceUnitInfo.getNewTempClassLoader().

    For Cayenne's own PersistenceUnitInfo implementation, I suggest
    you copy org.apache.openejb.core.TemporaryClassLoader which I
    copied from OpenJPA and cleaned up.

    -dain
  • Craig L Russell at Feb 23, 2007 at 1:22 am
    +1 to what Dain says here. All the persistence providers that I'm
    familiar with use the -javaagent on the java command line in Java SE
    mode to do the instrumentation (bytecode enhancement) regardless of
    the load order of the persistent classes and the persistence provider.

    Craig
    On Feb 22, 2007, at 10:45 AM, Dain Sundstrom wrote:

    You can't really push a class back into the app. Instead you must
    wait for the app to load (pull) a class and hook the load via the
    javaagent.

    In a managed (container) environment this works quite well because
    the container can guarantee that the JPA provider is full
    initialized before any app code is called. In an unmanaged
    environment life is much more difficult since it is by definition
    the application code that initializes the system. To get around
    this, you will need the javaagent to search for persistence units
    and determine which classes need to be enhanced. One nice thing,
    is most people will use the @Entity annotation instead of XML to
    declare their persistent beans, and this entity is easy to detect
    directly using asm. You should ask David Blevins about his xbean-
    finder code which is designed to detect such annotations.

    -dain
    On Feb 22, 2007, at 10:21 AM, Andrus Adamchik wrote:

    I see how TemporaryClassLoader operates. We haven't been using
    'getNewTempClassLoader' in the provider code as of yet. Let me
    poke around and see if I am overcomplicating the issue... I still
    don't understand how to push an enhanced class back into the app
    classloader space, but maybe I am wrong (still thinking in Cayenne
    classic terms), and this is not needed.

    Andrus

    On Feb 22, 2007, at 7:46 PM, Dain Sundstrom wrote:
    Sorry, got busy and missed this email.

    This is such a common problem, it was addressed directly by the
    JPA specs. When loading classes for inspection use the class
    loader returned from
    javax.persistence.spi.PersistenceUnitInfo.getNewTempClassLoader().

    For Cayenne's own PersistenceUnitInfo implementation, I suggest
    you copy org.apache.openejb.core.TemporaryClassLoader which I
    copied from OpenJPA and cleaned up.

    -dain
    Craig Russell
    Architect, Sun Java Enterprise System http://java.sun.com/products/jdo
    408 276-5638 mailto:Craig.Russell@sun.com
    P.S. A good JDO? O, Gasp!
  • Andrus Adamchik at Feb 23, 2007 at 11:11 am
    Ok, that matches my assessment - we need a JPA-aware agent (what I
    called fat agent).

    BTW, this discussion happened to be very helpful in straightening
    Cayenne PersistentUnitInfo ClassLoaders. We had our own version of
    TemporaryClassLoader from the beginning, but is was used as the main
    PersistentUnitInfo class loader, not the temp one (and provider
    incorrectly called PersistentUnitInfo.getClassLoader() as a result).
    I fixed it and got further down with OpenEJB JpaTest. Enhancer now
    works. I'll see if I can address other errors.
    You should ask David Blevins about his xbean-finder code which is
    designed to detect such annotations.
    I'll check it out.

    Andrus

    On Feb 22, 2007, at 8:45 PM, Dain Sundstrom wrote:

    You can't really push a class back into the app. Instead you must
    wait for the app to load (pull) a class and hook the load via the
    javaagent.

    In a managed (container) environment this works quite well because
    the container can guarantee that the JPA provider is full
    initialized before any app code is called. In an unmanaged
    environment life is much more difficult since it is by definition
    the application code that initializes the system. To get around
    this, you will need the javaagent to search for persistence units
    and determine which classes need to be enhanced. One nice thing,
    is most people will use the @Entity annotation instead of XML to
    declare their persistent beans, and this entity is easy to detect
    directly using asm. You should ask David Blevins about his xbean-
    finder code which is designed to detect such annotations.

    -dain
    On Feb 22, 2007, at 10:21 AM, Andrus Adamchik wrote:

    I see how TemporaryClassLoader operates. We haven't been using
    'getNewTempClassLoader' in the provider code as of yet. Let me
    poke around and see if I am overcomplicating the issue... I still
    don't understand how to push an enhanced class back into the app
    classloader space, but maybe I am wrong (still thinking in Cayenne
    classic terms), and this is not needed.

    Andrus

    On Feb 22, 2007, at 7:46 PM, Dain Sundstrom wrote:
    Sorry, got busy and missed this email.

    This is such a common problem, it was addressed directly by the
    JPA specs. When loading classes for inspection use the class
    loader returned from
    javax.persistence.spi.PersistenceUnitInfo.getNewTempClassLoader().

    For Cayenne's own PersistenceUnitInfo implementation, I suggest
    you copy org.apache.openejb.core.TemporaryClassLoader which I
    copied from OpenJPA and cleaned up.

    -dain
  • Dain Sundstrom at Feb 23, 2007 at 3:30 pm

    On Feb 23, 2007, at 3:11 AM, Andrus Adamchik wrote:

    BTW, this discussion happened to be very helpful in straightening
    Cayenne PersistentUnitInfo ClassLoaders. We had our own version of
    TemporaryClassLoader from the beginning, but is was used as the
    main PersistentUnitInfo class loader, not the temp one (and
    provider incorrectly called PersistentUnitInfo.getClassLoader() as
    a result). I fixed it and got further down with OpenEJB JpaTest.
    Enhancer now works. I'll see if I can address other errors.
    I suggest you compare you temp class loader to the one I pointed
    out. It is very easy to get the code wrong (I did my first two
    attempts at it).

    -dain

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupdev @
categoriescayenne
postedFeb 20, '07 at 12:31p
activeFeb 23, '07 at 3:30p
posts7
users3
websitecayenne.apache.org

People

Translate

site design / logo © 2022 Grokbase