Covering J2EE Security and WebLogic Topics

WebLogicMBeanMaker and Maven

This article illustrates a method of integrating WebLogicMBeanMaker (WebLogic 8.1) into a Maven 2 build.

UPDATE: Joel posted a comment with a much better solution than the one presented in this post. Essentially, adding

<copy file=”${basedir}/conf/ZAuthenticator.xml” todir=”${project.build.directory}/generated-sources/main/java”/>

before the call to WebLogicMBeanMaker prevents you from having to run it twice. Thanks, Joel!

If you’ve ever created a Weblogic security provider, you’ve used the WebLogicMBeanMaker utility. It generates source code for adapting your provider definition to the requirements of the WebLogic security framework. It also compiles some of the classes and can optionally JAR the entire package.

Maven is a project management and build system from Apache. I was lured by its Siren song of dependency management, project comprehension, site building capability, and a promise of less complicated build files. Unbeknownst to me, I set out on an adventure that would make Odysseus himself proud.

Refactoring my Ant file into separate projects started out smoothly enough. Creating separate web application and utility jar projects was quite liberating and I was pleased at the relative simplicity. Then I set about to Mavenize the security provider piece. I should have
borrowed some of Odysseus’ beeswax because I ran head-first into the rocks.

There’s no WebLogicMBeanMaker plugin for Maven but Maven does sport the handy maven-antrun-plugin. This plugin allows you to run Ant snippets within Maven. So, I copied the appropriate parts of the Ant script and did a little tweaking where required. With high hopes I ran "mvn clean compile" and was rewarded with a failed build for my optimism. This was a result that would occur time and time again as I’d check the web, tweak, and try again.

At the time of this writing, the web has a miniscule amount of content on WebLogicMBeanMaker and Maven. As it turns out, most of my flailing was caused by my own stupidity, but one issue remains. I eventually got around the problem but the solution is U-G-L-Y. Regardless, I’m posting the build file snippet here in the hopes that it might help someone.

The following script uses WebLogicMBeanMaker to generate the sources. I don’t care about the class files it makes (in fact I delete them) because I want to use Maven to control compilation so that I can be specific about the compiler version. The generated source tree is added to Maven’s source tree for compilation. Finally, I don’t use WebLogicMBeanMaker to JAR the provider because I let Maven handle that as well.

Here’s the snippet:

<!-- Run WebLogicMBeanMaker to build the authentication provider --> 
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <phase>generate-sources</phase>
      <configuration>
        <tasks>

          <!-- IMPORTANT NOTE: When the WebLogicMbeanMaker is run from
               a clean state, eveything works up until a class not found
               error against ZAuthenticatorMBI even though it's there.
               No real clue about why... However, it will work if 
               WebLogicMBeanMaker is run a second time (not from a clean
               slate).
                                    
               Thus, the workaround is to run WebLogicMBeanMaker twice. 
               The first one's failonerror attribute is set to false and the 
               second is set to true to catch any errors. -->

          <echo>Building Authentication provider with WebLogicMBeanMaker...</echo>
          <echo/>
          <echo>*** IGNORE THE CLASSNOTFOUND FOR ZAuthenticatorMBI ***</echo>
          <echo/>

          <!-- Ensure that WebLogicMBeanMaker starts from a clean slate -->
          <delete dir="${project.build.directory}/generated-sources"/>

          <path id="gen.path">
            <pathelement path=
              "${project.build.directory}\generated-sources\main\java"/>
            <path refid="maven.compile.classpath"/>
          </path>

          <!-- Build the MDF (mbean definition file) for the authenticator -->
          <java classname="weblogic.management.commo.WebLogicMBeanMaker" 
                fork="true" failonerror="false">
            <jvmarg 
              line="-Dfiles=${project.build.directory}/generated-sources/main/java 
                    -DMDF=${basedir}/conf/ZAuthenticator.xml 
                    -DcreateStubs=true -Dverbose=true "/>
            <classpath>
              <path refid="gen.path"/>
            </classpath>
          </java>

          <java classname="weblogic.management.commo.WebLogicMBeanMaker" 
                fork="true" failonerror="true">
            <jvmarg 
              line="-Dfiles=${project.build.directory}/generated-sources/main/java 
                    -DMDF=${basedir}/conf/ZAuthenticator.xml 
                    -DcreateStubs=true -Dverbose=true "/>
            <classpath>
              <path refid="gen.path"/>
            </classpath>
          </java>

          <!-- Move the generated Java source files to the appropriate spot -->
          <move todir=
            "${project.build.directory}/generated-sources/main/java/com/z/provider">
            <fileset dir="${project.build.directory}/generated-sources/main/java">
              <include name="**/*.java"/>        
              <exclude name="**/*MBI.java"/>
            </fileset>
          </move>

          <!-- Delete the class files created by WebLogicMBeanMaker -->
          <delete>
            <fileset dir="${project.build.directory}/generated-sources" 
                     includes="**/*.class"/>
          </delete>

          <!-- Copy meta-data files to the target/classes directory so they 
               get jarred -->
          <copy todir="${project.build.directory}/classes">
            <fileset dir="${basedir}/conf">
              <include name="**/*.xml"/> <!-- ZAuthenticator.xml -->
              <include name="**/*.dtd"/> <!-- commo.dtd --> 
            </fileset>
            <fileset dir="${project.build.directory}/generated-sources/main/java">
              <include name="**/*.mbi"/> <!-- ZAuthenticator.mbi -->
            </fileset>
          </copy>

          <echo/>
          <echo>*** IGNORE THE CLASSNOTFOUND FOR ZAuthenticatorMBI ***</echo>
          <echo/>
          <echo>Building Authentication provider with WebLogicMBeanMaker. DONE!</echo>
        </tasks>
        
        <!-- Add the generated sources to the Maven source directory list -->
        <sourceRoot>${project.build.directory}/generated-sources/main/java</sourceRoot>
      </configuration>

      <goals>
        <goal>run</goal>
      </goals>
    </execution>
  </executions>
</plugin>

This script is very similar to the one presented in the WebLogic documentation. My ugly kludge is to run WebLogicMBeanMaker twice. Yep, the first time it fails at a certain point and the second time it works like a champ. Here’s part of the ouput when it fails:

[java] Creating the MBI file…
[java] Could not create MBI.
[java] java.lang.ClassNotFoundException: ZAuthenticatorMBI

The class is there regardless of what the error says. I’ve manipulated my classpath a million times trying to fix this silliness. I’m sure it’s probably something really stupid that I’m missing. Wouldn’t be the first time. But for now, I’ll just let it be and get on with my life. If you know the answer, please comment and let me know.

I almost forgot to mention that for me, the jury is still out on Maven. However, I’ve dusted myself off after smashing into the rocks and can now enjoy the Siren song for the time being, at least. Just add some reporting plugins and run "mvn site". That’s pretty nifty. Oh, and that dependency management piece is very nice. No beeswax required.

 

Bookmark this page on del.icio.us