Table of Contents
This chapter introduces advanced modules of an application client.
This chapter discusses the types and JNDI default binding names of resources, for which a client container performs dependency injection. It also introduces services (e.g. security and transaction service) that can be used by application clients and clients that runs without a client container.
When executing a JEUS client without using a client container, it should be noted that the client cannot use the dependency injection service of the client container. By configuring security settings, JEUS's various services can be executed, and by using the transaction functions, it is possible to manage the resources and applications as global transactions.
All details of injection mentioned in this section apply to application clients, web applications, EJB applications, etc.
Injection can be performed for resources like an environment variable, which can be mapped to an EJB object. In general, a resource's name can be found in java:comp/env context, a JNDI context of the application component. Since the actual resource is bound to the JNDI global context, a user needs to know the global binding name.
Resources have their own JNDI global binding names. The JNDI global binding name of an EJB application should be specified by one of the following methods:
<export-name> of jeus-ejb-dd.xml
<mapped-name> of ejb-jar.xml in the standard
mappedName of an annotation specified in the EJB application
Bind the EJB to JEUS's default JNDI name suggested in "JEUS EJB Guide".
To obtain an EJB through JNDI without a client container, it is necessary to understand the rules for setting the default JNDI name. Because it is hard for a developer to know to which name the EJB will be bound to, it is recommended to specify a JNDI binding name using either of the suggested ways.
To inject a resource, specify a JNDI global binding name in jeus-ejb-dd.xml, jeus-web-dd.xml, and jeus-client-dd.xml, which are JEUS DD files. You can also map to the value specified by mapped-name in the standard DD file, such as ejb-jar.xml, web.xml or application-client.xml, or to the mappedName in the annotation. If nothing is specified, use a name according to the basic rules of JEUS.
In the actual development, it is recommended to use XML in specifying the JNDI global binding name, rather than using the mappedName of the annotation. If the application will be executed in many places, XML should be used since it needs to use a global name according to the environment. Injection is normally done for annotated setter methods and variables. However, it is possible to perform injection for non-annotated setter methods and variables, if they are specified by XML descriptor.
1. For more information about injection, refer to Java EE 7 technologies (http://www.oracle.com/technetwork/java/javaee/tech/index-jsp-142185.html) and about resources which can be injected, refer to "5. Resources, Naming and Injection" section of this guide.
2.For information about EJBContext injection for EJB applications, refer to "JEUS EJB Guide".
The following example shows how a client injects an EJB application using a mappedName of the annotation. Since statelessEJB1 application uses 'MyEJB1' as its JNDI global binding name, the client specifies the same name for mappedName of the @EJB annotation. If the client uses JNDI Lookup instead of Injection, it is possible to directly use the JNDI global binding name for lookup. If the client runs in a client container, it is possible to use the name, java:comp/env/ejb/sless1, from the application context using the application-client.xml file.
[Example 2.1] EJB Reference Injection
import ejb1.RemoteSession; @Stateless(name="StatelessEJB1", mappedName="MyEJB1") public class StatelessEJB1 implements RemoteSession, LocalSession {... } ... @EJB(name="sless1", beanName="StatelessEJB1", mappedName="MyEJB1") private RemoteSession sless1; ... RemoteSession session = context.lookup("MyEJB1"); ... // with client container and application-client.xml descriptor RemoteSession session = context.lookup("java:comp/env/ejb/sless1");
For EJB reference Injection, the following binding names are used.
If the variable type is a business interface:
If a mappedName is specified, the global name used for lookup should be the following format:
mappedName + "#" + Business_Interface_Name
In the previous example, the name will be set to MyEJB1 or MyEJB1#RemoteSession. If deployed as EAR or EJB JAR file and if ejb-link is given to the ejb-jar.xml file or if there is a beanName in the annotation, find an EJB in the same application and use its mappedName as the global name for lookup. Otherwise, find an EJB in the application with a business interface name, and use the EJB's mappedName as the global name.
Finally, perform JNDI Lookup with the business interface name. In the previous example, the name, 'java:global/<module-name>/MyEJB1' 'java:global/<module-name>/MyEJB1!ejb1.RemoteSession,' is used for Lookup. In this way, use a default binding name when there is no mappedName for EJB deployment.
If the variable type is a sub interface of EJBHome/EJBObject interface:
If there is a mappedName, use it as the global name. If deployed as EAR or EJB JAR file and if ejb-link is given to the ejb-jar.xml file or if there is a beanName in the annotation, find an EJB in the same application and use its mappedName as the global name for lookup. Otherwise, find an EJB in the application with a variable type interface name, and use the EJB's mappedName as the global name.
Finally, perform JNDI Lookup with the variable type interface name.
It is possible to use the @Resource annotation for resources.
If a mappedName is specified, use it as the resource's JNDI global binding name for lookup.
If not specified, use the name value of @Resource as the JNDI global binding name.
If no name value is specified, the following format is used according to the specifications.
application class + / + the property name of the setter method or the variable
In the example below, the name 'jdbc/DB2' is used for JNDI Lookup. If no name is specified, the name 'test.Client/myDataSource3' is used for lookup.
[Example 2.2] Resource injection
package test; class Client { @Resource(name="jdbc/DB2") // default mapping if no mapped-name private javax.sql.DataSource myDataSource3; ... }
When there is a name specified or a default value is specified for a name attribute that is not set, the value is mapped to the application context. However, for the actual JNDI global binding name different rules apply for each vendor. Thus for compatibility reasons, the mappedName should be used.
In addition, it is possible to obtain a web service object, an EntityManager object, and an EntityManagerFactory object through Injection, by using annotations like @WebServiceRef, @PersistenceUnit and @PersistenceContext.
For more information, refer to Java EE 7 Technologies (http://www.oracle.com/technetwork/java/javaee/tech/index-jsp-142185.html).
It is possible to use JEUS resources and applications through JEUS JNDI, without using an application container. To do so, execute a client program whose class path is set to the jclient.jar file in the JEUS_HOME\lib\client directory.
Since it is impossible to use dependency injection in this case, you need to modify the sources as shown in the following example. In the example, a binding name of the EJB application should follow JEUS's default name binding rule. The client can run on a client container. This means that all clients which do not use a client container can run on a client container.
[Example 2.3] <<HelloClient.java>>
package helloejb; import java.io.*; import javax.ejb.EJB; import javax.naming.Context; import javax.naming.InitialContext; import java.util.Hashtable; /** * HelloEJB application client */ public class HelloClient { private static Hello hello; public static void main(String[] args) { try { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY,"jeus.jndi.JNSContextFactory"); Context context = new InitialContext(env); hello = (Hello) context.lookup("helloejb.Hello"); System.out.println("EJB output : " + hello.sayHello()); } catch (Exception ex) { ex.printStackTrace(); } } }
Client packaging is not performed in a client container that processes XML files. Thus, create a JAR file without the standard or JEUS XML file. For deployment, copy the JAR file to any location. For execution, execute the previous client class just like executing a general Java class.
The result is as follows:
$ java -cp /jeus/lib/client/jclient.jar;./hello-client.jar helloejb.HelloClient
[2012.05.23 22:45:51][2] [t-1] [Network-0405] [Endpoint] exporting Endpoint (0:192.168.0.16:9756:-1:0x79F24F28)
[2012.05.23 22:45:51][2] [t-1] [Network-0002] [Acceptor] start to listen NonBlockingChannelAcceptor: /192.168.0.16:9756
EJB output : Hello EJB!
To use JEUS's Java EE services, a client has to provide its username and password to the client runtime in order to verify authorization for using the services. The services include EJB applications and JMS resources. The following are three ways to specify a username and password:
Using jeus-client-dd.xml
If <security-info> in the jeus-client-dd.xml file is specified, a user has to sign in with the specified username and password before starting an application in the client container. After this, the application attempts authentication using this username when using JEUS services. For more information about the jeus-client-dd.xml settings, refer to "JEUS XML Reference."
[Example 2.4] <<jeus-client-dd.xml>>
<jeus-client-dd> ... <security-info> <provider-node-name>jeusNode</provider-node-name> <user>user1</user> <passwd>password1</passwd> </security-info> ... </jeus-client-dd>
Using the JNDI context
When a client creates the JNDI context for an application, the client can use the JNDI properties to sign in with a username and password, which are used for authentication. This method of providing account information is available even without a client container. For the detailed information about the JNDI settings, refer to JEUS Server Guide. "Chapter 4. JNDI Naming Server".
[Example 2.5] <<Client.java>>
Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "jeus.jndi.JNSContextFactory"); env.put(Context.PROVIDER_URL, "192.168.0.16:9736"); env.put(Context.SECURITY_PRINCIPAL, "user1"); env.put(Context.SECURITY_CREDENTIALS, "password1"); Context context = new InitialContext(env);
Using JEUS Security API
It is possible to sign in by using JEUS Security API. For details about the Security API, refer to "JEUS Security Guide".
UserTransaction is used to utilize EJB client applications, JDBC DataSource, JMS connection factory and destination, and more as one global transaction or an XA transaction.
The transaction manager used by a client is either a server transaction manager or client transaction manager depending on whether it has direct control over resources.
1. For details about UserTransaction, refer to Java EE 7 Technologies (http://www.oracle.com/technetwork/java/javaee/tech/index-jsp-142185.html).
2. For details about transaction manager, refer toJEUS Server Guide. "Chapter 7. Transaction Manager".