Additional Blogs by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
sabine_heider
Explorer

If you consider using EclipseLink as the JPA provider for your application, give the area of weaving careful thought. Weaving is a bytecode manipulation technique that EclipseLink uses for various optimizations in the handling of JPA entities, including lazy loading of relations and attributes, and change detection. While you could, in principle, run EclipseLink completely without bytecode weaving, you wouldn't do so in a production environment as it improves the performance of your application significantly.

SAP NetWeaver AS Java doesn't allow any bytecode modifications at class loading time, so you have to perform the weaving earlier when actually compiling the application – a technique referred to as "static weaving". EclipseLink provides an Ant task for that purpose, which you can integrate into the build process. Users of the SAP NetWeaver Development Infrastructure (NWDI) might find this task rather challenging, mainly because the knowledge about the build extension mechanism isn't widely spread. In this blog, I'll show you step-by-step how to include EclipseLink's static weaving into the NWDI component build.

Note: In more general terms you can consider \ this description an example for integrating an arbitrary Ant task into the NWDI component build.

Implement EclipseLink's Static Weaving as a Build Infrastructure Extension

In the NWDI, each Development Component (DC) has a dependency to a particular Build Plugin DC that implements the build process for that DC type. This dependency is set automatically when you create a new DC in the SAP NetWeaver Developer Studio.

A Build Infrastructure Extension DC allows you extend the predefined build process, thus adapting it to your specific needs. To enable these changes for the build of a particular DC, simply add a build-time dependency on the Build Infrastructure Extension DC to your DC. The Build Infrastructure Extension can contain Java code or Apache Velocity macros. An extension DC also contains a special descriptor file for the build plugin framework to define the extension.

EclipseLink's Ant Task for Static Weaving

As a prerequisite for integrating EclipseLink's weaving into the NWDI component build, you should get an EclipseLink archive (including the matching javax.persistence API) of exactly the same version that is deployed on your application server. Note that a version mismatch might cause problems with the woven classes. You can download EclipseLink from this location: http://www.eclipse.org/eclipselink/downloads/index.php

The eclipselink.jar file contains an Ant task that can weave a set of already compiled java classes: org.eclipse.persistence.tools.weaving.jpa.StaticWeaveAntTask. See EclipseLink's weaving documentation for details on how to use the Ant task.

Create a Build Infrastructure Extension DC

In order to integrate the static weaving with the NWDI component build, you have to create a Build Infrastructure Extension DC, which is invoked immediately after the regular Java build and which simply calls EclipseLink's weaving task:

  1. Choose File → New → Other and select Development Infrastructure → Development Component to create a new DC Project.
  2. Choose DC Build → Build Infrastructure Extension as Development Component type.
  3. Select the software component for the Build Infrastructure Extension DC.
    In this example, I use LocalDevelopment → MyComponents.
  4. Provide vendor and name for the DC.
    I use demo.sap.com as vendor and el_static_weaving as name.
  5. Choose Finish.
  6. As a result, you should have a folder structure like this:

  7. Note: You might have to disable the filter on the ".* resources" in order to see the .bpfext file.
  8. Copy the following JAR files from the unpacked EclipseLink download archive to the bp/lib/java\ folder:
    • eclipselink.jar
    • javax.persistence_<version>.jar

  1. Edit the .bpfext descriptor to define an EclipseLink static weaving extension for the Java compiler with a special postprocessor macro (see below). In case that you chose another name or vendor for your extension DC, note that you need to adapt the macro definition accordingly (where highlighted).
  2. <?xml version="1.0" encoding="UTF-8"?>
    <technologies version="1">
      <technology name="demo.sap.com/el_static_weaving">
        <uses>sap.com/tc/bi/javatech</uses>
        <generators>
          <extension
            type="demo.sap.com~el_static_weaving"
            extends="sap.com~javac"
            implementation-type="macro"
            implementation-after="EclipseLinkWeaving"/>
        </generators>
      </technology>
    </technologies>
  3. This tells the Build Plugin Framework to execute a macro called EclipseLinkWeaving with a predefined signature after each invocation of the Java compiler.

  4. Edit the Velocity macro file demo.sap.com_el_static_weaving.vm to define the EclipseLinkWeaving macro:
  5. #macro(EclipseLinkWeaving $input $output $used $params)
        ## define task
        ## Use antBase to avoid duplicate definitions and
        ## to put the definition in the project itself.
        $antBase.taskdef("staticweaver", "org.eclipse.persistence.tools.weaving.jpa.StaticWeaveAntTask")

        ## find persistence.xml in source folders
        #set($persistenceXMLpath = false)  
        #set($inputpaths = $input.get("default"))
        #foreach($inputpath in $inputpaths)
            #if ($dc_util.isFile("${inputpath}/META-INF/persistence.xml"))
                #set($persistenceXMLpath = $inputpath)
            #end
        #end

        ## copy persistence.xml and orm.xml to output folder
        ## static weaver needs them
        #set ($outputpath = $output.get("default"))
        <copy todir="${outputpath}/META-INF" verbose="true" failonerror="true">
            <fileset dir="${persistenceXMLpath}/META-INF">
                <include name="persistence.xml"/>
                <include name="orm.xml"/>
            </fileset>
        </copy>

        ## invoke staticweaver ant task
        ## loglevel set toFINEST to produce some output
        #StartTimer()
        <staticweaver
                source="${outputpath}"
                target="${outputpath}"
                loglevel="FINEST">
            <classpath>
            #set ($usedpaths = $used.get("default"))
            #foreach($usedpath in $usedpaths)
                <path location="${inputpath}"/>
            #end
            </classpath>
        </staticweaver>
        #ShowTimer("EclipseLink static weaving")

        ## remove persistence.xml and orm.xml to avoid build warning (duplicates)
        <delete verbose="true">
            <fileset dir="${outputpath}/META-INF">
                <include name="persistence.xml"/>
                <include name="orm.xml"/>
            </fileset>
        </delete>
    #end

  6. This macro renders the <staticweaver> task to an Ant build script using the same default input path (i.e. package folders defined for the DC), the same default used path (or "classpath") and the same output path that the Java compiler used.

  7. For more info on the Velocity Template Language, refer to http://velocity.apache.org/.

  8. In the Component Properties view of the Build Infrastructure Extension, go to the Folders tab and remove the src folder. This folder is actually empty and would cause a warning in the build.
  9. Build the DC.

Use the Build Infrastructure Extension for Your Application

Once you have defined the Build Infrastructure Extension for EclipseLink's weaving, you can use it to add static weaving to the build of your JPA application DC:

  1. In the Component Properties view of the JPA application, add a build-time dependency on the def public part of the Build Infrastructure Extension DC. This public part has been added automatically when creating the extension.
  2. Build the DC.
  3. Check the build log. There should be some output produced by the weaving task indicating that the weaving actually worked (see below). Any error that might have occurred would also be reported here.
  4. [copy] Copying 1 file to C:\\temp\\nwds\\workspace.jdi\\LocalDevelopment\\t\\1E783F30932B07B16D7E78DDA43001D5\\classes\\META-INF
    [copy] Copying C:\\temp\\nwds\\workspace.jdi\\LocalDevelopment\\DCs\\demo.sap.com\\my_jpa_app\\_comp\\ejbModule\\META-INF\\persistence.xml
    to C:\\temp\\nwds\\workspace.jdi\\LocalDevelopment\\t\\1E783F30932B07B16D7E78DDA43001D5\\classes\\META-INF\\persistence.xml
    [staticweaver] [EL Finest]: 2010-08-05 14:03:33.857
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--property=eclipselink.jpa.uppercase-column-names; default value=false
    [staticweaver] [EL Finer]: 2010-08-05 14:03:33.873
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Searching for default mapping file in file:/C:/temp/nwds/
    workspace.jdi/LocalDevelopment/t/1E783F30932B07B16D7E78DDA43001D5/classes/
    [staticweaver] [EL Finer]: 2010-08-05 14:03:33.873
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Searching for default mapping file in file:/C:/temp/nwds/
    workspace.jdi/LocalDevelopment/t/1E783F30932B07B16D7E78DDA43001D5/classes/
    [staticweaver] [EL Config]: 2010-08-05 14:03:33.998
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The access type for the persistent class [class entities.EntityB]
    is set to [FIELD].
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.606
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The access type for the persistent class [class entities.EntityA]
    is set to [FIELD].
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.606
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The target entity (reference) class for the one to one mapping
    element [field b] is being defaulted to: class entities.EntityB.
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.606
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The alias name for the entity class [class entities.EntityB]
    is being defaulted to: EntityB.
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.637
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The column name for element [field id] is being defaulted
    to: ID.
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.637
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The alias name for the entity class [class entities.EntityA]
    is being defaulted to: EntityA.
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.637
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The column name for element [field id] is being defaulted to:
    ID.
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.668
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The primary key column name for the mapping element
    [field b] is being defaulted to: ID.
    [staticweaver] [EL Config]: 2010-08-05 14:03:34.668
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--The foreign key column name for the mapping element
    [field b] is being defaulted to: B_ID.
    [staticweaver] [EL Finer]: 2010-08-05 14:03:34.668
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Class [entities.EntityB] registered to be processed by weaver.
    [staticweaver] [EL Finer]: 2010-08-05 14:03:34.668
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Class [entities.EntityA] registered to be processed by weaver.
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.7
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Begin weaver class transformer processing class
    [entities/EntityA].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved persistence (PersistenceEntity) [entities/EntityA].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved change tracking (ChangeTracker) [entities/EntityA].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved lazy (ValueHolder indirection) [entities/EntityA].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved fetch groups (FetchGroupTracker) [entities/EntityA].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--End weaver class transformer processing class [entities/EntityA].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Begin weaverclass transformer processing class [entities/EntityB].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved persistence (PersistenceEntity) [entities/EntityB].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved change tracking (ChangeTracker) [entities/EntityB].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--Weaved fetch groups (FetchGroupTracker) [entities/EntityB].
    [staticweaver] [EL Finest]: 2010-08-05 14:03:34.715
    --ServerSession(16527316)--Thread(Thread[Worker-17,5,main])--End weaver class transformer processing class [entities/EntityB].
    [timer] EclipseLink static weaving finished in 1.045 seconds

    [delete] Deleting 1 files from C:\\temp\\nwds\\workspace.jdi\\LocalDevelopment\\
    t\\1E783F30932B07B16D7E78DDA43001D5\\classes\\META-INF
    [delete] Deleting C:\\temp\\nwds\\workspace.jdi\\LocalDevelopment\\
    t\\1E783F30932B07B16D7E78DDA43001D5\\classes\\META-INF\\persistence.xml
  5. A slight warning: Check the build log, especially the[staticweaver] output, carefully. If EclipseLink didn't detect any entities (for example due to a missing persistence.xml file), the build would still succeed but the entities wouldn't be woven – and thus not be mentioned in the [staticweaver] log.

Further Information

Build Plugin Framework Reference for NWDI

If you have a SAP Service Marketplace user, you can refer to SAP Support Note 1061467 to get more information on the Build Plugin Framework.

Summary

That's basically all you have to do to add EclipseLink's static weaving to the NWDI component build:

  1. Create a Build Infrastructure Extension for static weaving.
  2. Add a dependency on the extension to your application DC.

Admittedly, creating the Build Infrastructure Extension is a bit tricky, but it's a one-time-only task. Once you have the definition in place, you can use it over and over again for all your EclipseLink applications.

5 Comments