Sunday, August 20, 2017

EJB naming conventions


How does Oracle official JEE 7 tutorial say?

ItemsSyntaxExample
EJB bean namenameBeanHelloBean
EJB bean java class namenameBeanHelloBean
Business interfacenameHello

How is Java SE API doing?


Interface NameImplementation Class Name
java.util.List<E>AbstractList
AbstractSequentialList
ArrayList
AttributeList
LinkedList
java.util.Map<K,V>AbstractMap
Attributes
AuthProvider
ConcurrentHashMap
ConcurrentSkipListMap
EnumMap
HashMap
Hashtable
IdentityHashMap
LinkedHashMap
Properties
TreeMap
There is a lot examples in java api. Some abstract classes' name and their implementation classes are all named very well. Anyway, I never see something like IList, ListInter or ListInterface ......

How do you name your interface and enterprise session bean? 

Implement an Enterprise Session Bean

This post complies JEE 7, and test in weblogic 12c2.

How does container know a class is Session Bean?

The container regards a class as enterprise session bean if this class is annotated with either @Stateless, @Stateful or @Singleton annotation and no matter it's annotated with @Local, @Remote or @LocalBean annotation or it implements any interface which is annotated with @Local or @Remote annotation.
Now we know the key to make class an EJB is to annotate it with @Stateless, @Stateful or @Singleton regardless it has business interface or not.
There 2 styles of session bean, one is having business interface, another one is no-interface.
Clients access enterprise beans either through a no-interface view or through a business interface. A no-interface view of an enterprise bean exposes the public methods of the enterprise bean implementation class to clients.
Session beans can have more than one business interface. Session beans should, but are
not required to, implement their business interface or interfaces.

The ways to create EJB

We always take Local Stateless EJB as examples in below sections. 

1. Implement an interface which is annotated with @Local or @Remote

public interface Hello {
    void say(String msg);
}

/* Most of time in practice we also create a RemoteHello interface and implementation class implements these 2 interfaces meanwhile to let this bean have remote and local bean characters at the same time.*/
@Local
public interface LocalHello extends Hello{
    
}

/* EJB */
@Stateless(name="ejb/LocalHelloBean")
public class LocalHelloBean implements LocalHello{

    @Override
    public void say(String msg) {
        ...
    }
    
}
LocalHelloBean is a local ejb and has business interface LocalHello .

2. Annotate class with @Local or @Remote

public interface Hello {
    void say(String msg);
}

/* EJB */
@Local(com.nwb.jpractice.jee7.helloworld.ejb.api.Hello.class)
@Stateless(name="ejb/HelloBean")
public class HelloBean implements Hello{

    @Override
    public void say(String msg) {
        ...
    }
 
}
HelloBean is local ejb and has business interface Hello.

3. Annotate class with @LocalBean

No interface local view EJB
@LocalBean
@Stateless(name="ejb/LocalBeanAnnotatedHelloBean")
public class LocalBeanAnnotatedHelloBean {
 
    public void say(String msg) {
        ...
    }
 
}
LocalBeanAnnotatedHelloBean is a local ejb and has no-interface view.

4. No @Local, @Remote or @LocalBean annotation and implement an interface without @Local or @Remote annotation

This is the most magical case.
public interface Hello {
    void say(String msg);
}

@Stateless(name="ejb/NoLocalAnnotatedHelloBean")
public class NoLocalAnnotatedHelloBean implements Hello{
 
    public void say(String msg) {
        ...
    }
 
}
Interface Hello is not annotated with Local or Remove but container will automatically regard it as business interface. So NoLocalAnnotatedHelloBean is a local ejb and business interface Hello.

5. No @Local, @Remote or @LocalBean annotation and No implement any interface

@Stateless(name="ejb/NoLocalAnnotationNoInterfaceHelloBean")
public class NoLocalAnnotationNoInterfaceHelloBean {
 
    public void say(String msg) {
        ...
    }
 
}

NoLocalAnnotationNoInterfaceHelloBean is local ejb and has no-interface view. This case is completely as same as @LocalBean case at section 3.

Now we have been able to create our own session bean. After we have some beans how do we get the reference of the ejb?

Tuesday, August 15, 2017

Create Java EE Maven Project

Project structures

Illustrate how to create Java EE application project with maven. The whole application has one parent pom, 1 web module, 1 ejb module, 1 normal java module and 1 ear assembly project to package former those modules together.
Final structures should be like below,

+helloworld
 |----helloworld-ear
 |----helloworld-war
 |----helloworld-ejb-local
 |----helloworld-ejb-api
 |----pom.xml

maven commands

Run following maven commands,
cd <baseDir>
mvn archetype:generate -B -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=pom-root -DarchetypeVersion=1.1 -DgroupId=com.nwb.jpractice.jee7 -DartifactId=helloworld -Dversion=1.0-SNAPSHOT

cd <baseDir>/helloworld
mvn archetype:generate -B -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.1 -DgroupId=com.nwb.jpractice.jee7 -DartifactId=helloworld-ejb-api -Dversion=1.0-SNAPSHOT

mvn archetype:generate -B -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=ejb-javaee7 -DgroupId=com.nwb.jpractice.jee7 -DartifactId=helloworld-ejb-local -Dversion=1.0-SNAPSHOT

mvn archetype:generate -B -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=webapp-javaee7 -DgroupId=com.nwb.jpractice.jee7 -DartifactId=helloworld-war -Dversion=1.0-SNAPSHOT

mvn archetype:generate -B -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=ear-javaee7 -DgroupId=com.nwb.jpractice.jee7 -DartifactId=helloworld-ear -Dversion=1.0-SNAPSHOT

Optimise pom and deployment descriptor

After that manually optimise some the pom and jee deployment descriptors.

Parent pom

  • Specify encoding UTF-8
  • Specify source code java version
  • Specify which jvm version the compiled class compatible
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties> 

EAR Pom

Configure maven-ear-plugin
  • Specify assembled modules [1]
  • Customize module filename [2]. You may want to simply helloworld-ejb-local-1.0-SNAPSHOT.jar to helloworld-ejb-local.jar.
  • Adopt skinny wars [3]. Libraries should have been in WEB-INF/lib are copied to EAR's lib and shared within whole application to shrink the size of war.
  • Specify context-root for web module [4]. The context-root will be written into META-INF/application.xml. You don't have to create application.xml manually maven ear plugin is able to generate it when building project.
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-ear-plugin</artifactId>
                <version>2.8</version>
                <configuration>
                    <defaultLibBundleDir>lib</defaultLibBundleDir><!-- libraries of this application, this path is written into each META-INF/MANIFEST.MF during build-->
                    <skinnyWars>true</skinnyWars><!-- [3]-->
                    <modules>
                        <ejbModule><!-- [1] ejb module-->
                            <groupId>com.nwb.jpractice.jee7</groupId>
                            <artifactId>helloworld-ejb-local</artifactId>
                            <bundleFileName>helloworld-ejb-local.jar</bundleFileName><!-- [2]-->
                        </ejbModule>
                        <webModule><!-- [1] war module-->
                            <groupId>com.nwb.jpractice.jee7</groupId>
                            <artifactId>helloworld-war</artifactId>
                            <bundleFileName>helloworld-web.war</bundleFileName><!-- [2]-->
                        </webModule>
                    </modules>
                </configuration>
            </plugin>
        </plugins>
    </build>
 
    <dependencies>
        <dependency>
            <groupId>com.nwb.jpractice.jee7</groupId>
            <artifactId>helloworld-war</artifactId>
            <version>1.0-SNAPSHOT</version>
            <type>war</type>
        </dependency>
        <dependency>
            <groupId>org.nwb.jpractice.jee7</groupId>
            <artifactId>helloworld-ejb-local</artifactId>
            <version>1.0-SNAPSHOT</version>
            <type>ejb</type>
        </dependency>
        <!-- helloworld-ejb-api and other dependencies will be in ear's lib folder -->
        <dependency>
            <groupId>com.nwb.jpractice.jee7</groupId>
            <artifactId>helloworld-ejb-api</artifactId>
            <version>1.0-SNAPSHOT</version>
            <type>jar</type>
        </dependency>
    </dependencies>

Now this application can work, you can start building it and deploy it to weblogic.







Wednesday, August 9, 2017

Java EE application maven project and package

Package structure of JEE application

Typically a Java EE application is designed to have multiple modules or layers. Nowadays we often divide a general web application into 3 tiers, presentation, business logic, and persistence. Most of the time we directly split whole application into 3 modules according to this 3-tiers architecture thought.
From Java EE technology perspective presentation tier is a web module, and business tier (ejb3) and persistence tier (jpa) are both ejb modules. The whole application is the assembly of these web and ejb modules.
From deployment perspective a Java EE application is a .ear package (Enterprise Application aRchive), web module is .war package (Web Application aRchive), and ejb module is .jar package. .war and .jar are all packaged inside .ear.
Java EE module types
Package types Structure Description
EAR(.ear) META-INF/application.xml
lib/*.jar
<web-module>.war
<ejb-module>.jar
...
An enterprise application. It may contains several web and ejb modules.
application.xml is Java EE standard deployment descriptor of EAR.
Sometimes Java EE container specific application deployment descriptor is also in META-INF, for example, weblogic-application.xml is weblogic-specific deployment descriptor.
lib contains shared libraries.
EJB(.jar) META-INF/ejb-jar.xml
*.class
An EJB module. ejb-jar.xml is EJB standard deployment descriptor. It has been optional since JEE5 introduced equivalent annotations. There may be also container-specific deployment descriptor under META-INF folder.
WAR(.war) WEB-INF/web.xml
WEB-INF/classes/*.class
WEB-INF/lib/*.jar
*.jsp
*.js
*.css
*.html
An WEB module. web.xml is WEB application standard deployment descriptor. It has been optional since JEE5 introduced equivalent annotations. There may be also container-specific deployment descriptor under WEB-INF folder, for example, weblogic.xml for weblogic.

Maven projects of JEE application 

Now I create a complete maven project skeleton for a JEE application, a simplest project, helloworld. The whole application includes 2 modules, one web module and one ejb module. We still need one more project which is to package and assembly these 2 modules into one EAR, one complete JEE application.
Creating these 3 maven projects are sufficient to illustrate a complete JEE application structure.
We also hope this application complies with JEE 7 specification, is able to deploy on weblogic12c, and support JDK 8 runtime environment.

EJB module

1. pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    ...
    <packaging>ejb</packaging>
    ...
    <build>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-ejb-plugin</artifactId>
            <version>2.5.1</version>
            <configuration>
                <ejbVersion>3.1</ejbVersion>
            </configuration>
        </plugin>
    </build>
    ...
    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
Key points:
  • ejb packaging
  • maven-ejb-plugin maven plugin
  • javaee-api dependency

2. src/main/resources/META-INF/ejb-jar.xml

<ejb-jar version="3.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd">
    <module-name>helloworld-ejb</module-name>
</ejb-jar>
This module name is used by container and is very useful to looks up resource within container.

WEB module

1. pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    ...
    <packaging>war</packaging>
    ...
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>
    ...
    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    ...
</project>
Key points:
  • war packaging
  • maven-war-plugin plugin
  • javaee-web-api dependency

2. src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <!--<module-name>helloworld-web</module-name>-->
    ...
</web-app>
web.xml is optional, if no this file application still works because nowadays servlet can be declared with annotation.
And please notice the module-name declared here. It would overwrite the context-root in container specific descriptor WEB-INF/weblogic.xml if you set and <module>/<context-root> in META-INF/application.xml. For example, if you set module-name helloworld-web the URL to access the application would become http://hostname:port/helloworld-web, the context-root is replaced by module-name. For context-root declaration priority sequence is web.xml > application.xml > weblogic.xml.

EAR (Assembly) module

1. pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    ...
    <packaging>ear</packaging>
    ...
    <build>
        <plugins>
            ...
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-ear-plugin</artifactId>
                <configuration>
                    <version>7</version>
                    <defaultLibBundleDir>lib</defaultLibBundleDir>
                    <skinnyWars>true</skinnyWars>
                    <modules>
                        <ejbModule>
                            <groupId>org.example</groupId>
                            <artifactId>helloworld-ejb</artifactId>
                            <bundleFileName>helloworld-ejb.jar</bundleFileName>
                        </ejbModule>
                        <webModule>
                            <groupId>org.example</groupId>
                            <artifactId>helloworld-web</artifactId>
                            <bundleFileName>helloworld-web.war</bundleFileName>
                        </webModule>
                    </modules>
                </configuration>
            </plugin>
        </plugins>
    </build>
 
    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>helloworld-jar</artifactId>
            <version>1.0-SNAPSHOT</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>helloworld-ejb</artifactId>
            <version>1.0-SNAPSHOT</version>
            <type>ejb</type>
        </dependency>
    </dependencies>
</project>
Key point:

  • ear packaging
  • maven-ear-plugin plugin
  • Declare the modules you want to package inside maven-ear-plugin configuration
  • Add sub-modules as dependencies 

2. application.xml

<?xml version="1.0" encoding="UTF-8"?>
<application version="7" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/application_7.xsd">
    <display-name>helloworld</display-name>
    <!-- application name inside container -->
    <application-name>helloworld-app</application-name>
    <module>
        <ejb>helloworld-ejb.jar</ejb>
    </module>
    <module>
        <web>
            <web-uri>helloworld-web.war</web-uri>
            <!-- Higher priority than context-root of weblogic.xml. The highest is module-name of web.xml -->
            <context-root>/helloworld</context-root>
        </web>
    </module>
</application>

Some other maven settings you may consider

  1. Create parent pom to put sharing settings within modules
  2. Config maven-compiler-plugin plugin. Specify source code java version and target version.
  3. Config maven-dependency-plugin plugin