Sun Java logo     Previous      Contents      Index      Next     

Sun logo
Sun Java System Application Server 7 2004Q2 Developer's Guide to Clients 

Chapter 2
Using the Application Client Container

This chapter describes how to access the application server using RMI/IIOP protocol, and how to use the Application Client Container (ACC) to develop and package application clients.

This chapter contains the following sections:


Introducing the Application Client Container

The Application Client Container (ACC) includes a set of Java classes, libraries, and other files that are required and distributed along with Java client programs that execute on their own Java Virtual Machine. It manages the execution of the application client components. The ACC provides system services that enable a Java client program to execute. It communicates with Application Server using RMI/IIOP and manages the details of RMI/IIOP communication using the client ORB that is bundled with it. The ACC is specific to the EJB container and is often provided by the same vendor. Compared to other J2EE containers that reside on the server, this container is lightweight.

Application Client Container Features

Security

The ACC is responsible for collecting authentication data such as the username and password from the user. Sends the collected data over RMI/IIOP to the server. The server then processes the authentication data using the configured JavaTM Authentication and Authorization Service (JAAS) module. See Authenticating an Application Client Using the JAAS Module.

Authentication techniques are provided by the client container, and are not under the control of the application client. The container integrates with the platform’s authentication system. When you execute a client application, it displays a login window and collects authentication data from the user. It also support SSL (Secure Socket Layer)/IIOP if configured and when it is necessary.

Naming

The client container enables the application clients to use Java Naming and Directory Interface (JNDI) to look up EJB components and to reference configurable parameters set at the time of deployment.


Developing Application Clients

This section describes the procedure to develop, assemble, and deploy client applications, how to use the ACC to package such applications and deploy them to the server. This section describes the following topics:

Creating an Application Client

A J2EE application client is a program written in the Java programming language. At runtime, the client program executes in a different virtual machine than the J2EE server.

Code examples from the Converter sample application illustrate the following steps involved in the development of an application client:

Locating the Home Interface

Use the Java Naming and Directory InterfaceTM (JNDI) to lookup and locate an EJB component’s home interface. The following steps describe the procedure to locate an EJB component’s home interface.

  1. Create an initial naming context.
  2. Context initial = new InitialContext();
    Context myEnv = (Context)initial.lookup(“java:comp/env”);

    The context interface is part of JNDI. An initial context object, which implements the Context interface, provides the starting point for the resolution of names. All naming operations are relative to a context.

  3. Retrieve the object bound to the name RMCConverter.
  4. Object objref = myEnv.lookup(“ejb/RMIConverter”);

    The RMIConverter name is bound to an enterprise bean reference, a logical name for the home of an enterprise bean component. In this case, the RMIConverter name refers to the ConverterHome object. The names of enterprise bean components should reside in the java:com/env/ejb subcontext.

  5. Narrow the reference to a ConverterHome object.
  6. ConverterHome home =(ConverterHome) PortableRemoteObject.narrow(objref, ConverterHome.class);

Creating an Enterprise Bean Instance

To create the bean instance, the client invokes the create method on the ConverterHome object. The create method returns an object whose type is Converter. The remote converter interface defines the business methods of the bean that the client may call and the EJB container instantiates the bean and then invokes the ConverterBean.ejbCreate method.

Converter currencyConverter = home.create();

Invoking a Business Method

To invoke a business method, you first need to invoke a method on the Converter object. The EJB container will invoke the corresponding method on the ConverterEJB instance that is running on the server. The client invokes the dollarToYen business method in the following lines of code:

BigDecimal param = new BigDecimal ("100.00");

BigDecimal amount = currencyConverter.dollarToYen(param);

Creating an ACC Client With Load Balancing and Failover Support (Enterprise Edition)

Sun Java System Application Server, Enterprise Edition provides a highly available J2EE application through the use of load balancing and a sophisticated failover mechanism on the RMI/IIOP path.

The following features are supported:

High availability of J2EE application means that, if between method invocations, the server instance to the EJB object becomes unavailable, then subsequent invocations are redirected to an alternate available server instance in the cluster.

For more information on High Availability, see the Sun Java System Application Server Administration Guide.

Introducing the Properties that Support LB/FO for ACC Clients

In order to enable load balancing capabilities in your ACC client, Sun Java System Application Server supports the following two properties:

Configuration Changes

Define the load balancing properties in the sun-acc.xml file to provide a highly available ACC client. The properties are defined as property elements in the sun-acc.xml file.

For example:

<client-container>

  <target-server name="qasol-e1" address="qasol-e1" port="3700">

  <property name="com.sun.appserv.iiop.loadbalancingpolicy" value="ic-based" />

<property name="com.sun.appserv.iiop.endpoints" value="qasol-e1:3700", “qasol-el:3800” />

</client-container>

To failover an ACC client on the RMI/IIOP path, information about all the endpoints in a cluster to which the RMI/ IIOP requests can be failed over must be available. You must have defined the IIOP endpoints in the server.xml file. The iiop-cluster element under the availability-service element defines the IIOP endpoints.


Note

The endpoints are categorized as those configured for non-SSL and those configured for SSL. Only endpoints configured for non-SSL are supported. For more information on defining IIOP endpoints, see the Sun Java System Application Server Administration Guide.


Using an Application Client to Invoke an EJB Module

This section describes how an application client can be used to call a stand-alone EJB module, or an EJB module residing in another J2EE application client.

To call an EJB module from an application client, perform the following steps:

  1. Define the element <ejb-ref> in the application-client.xml file. The deployer provides the JNDI name for the <ejb-ref> in the corresponding sun-application-client.xml file.
  2. For more information on the sun-application-client.xml file, see Sun Java System Application Client Deployment Descriptor.

  3. Make sure that the JNDI name matches with the JNDI name defined in the EJB module.
  4. Deploy the EJB module using the Administration interface. For more information on deploying an EJB module using the Administration Interface, see the Sun Java System Application Server Administration Guide.
  5. The client JAR file is created at the following location:
    /application/j2ee-modules/ejbmodulename/appclient.jar

  6. Distribute your appclient.jar file to the location that the client JVM can access.
  7. Ensure that the appclient.jar file includes the following files:
    • a Java class to access the bean
    • application-client.xml
    • sun-application-client-.xml
    • The MANIFEST.MF file. This file contains the main class, which states the complete package prefix and classname of the Java client.
  8. Run the application client to access the EJB component. The following line of code illustrates how to invoke an EJB component using the ACC:
  9. appclient -client jarpath -mainclass client application main class|-name name -xml config_xml_file app-args

    • -client is required and specifies the name and location of the application client jar file.
    • -mainclass is optional and specifies the class name, that is located within the appclient.jar file whose main() method is to be invoked. By default, the class specified in the client jars Main-class attribute of the MANIFEST file is used.
    • -name is optional and specifies the display name that is located within the appclient.jar. By default, the display name is specified in the client jar application-client.xml file as display-name attribute.
    • -xml, which specifies the name and location of the ACC configuration xml file, is required if you are not using the default domain and instance. By default, the ACC uses instance_dir/config/sun-acc.xml for clients running on the application server, or install_dir//lib/appclient/sun-acc.xml for clients that are packaged using the package-applclient script.
    • app-args are optional and they represent the arguments passed to the client’s main() method.
  10. To deploy the application client, assemble the application client to create a standard J2EE .ear file and then deploy the application client to Sun Java System Application Server.

Making a Remote Call on the EJB

If you need to access the EJB components that are residing in a remote system other than the system where the application client is being developed, make the following changes into the sun-acc.xml fie.

This information can be obtained from the server.xml file on the remote system. For more information on server.xml file, see the Sun Java System Application Server Administrator’s Configuration File Reference.

Using an Application Client to Access JMS Resources

This section describes the procedure to develop an application client that can access JMS resources to send a JMS message to a destination. The following two scenarios are discussed:

Before creating the client application, you must create JMS resources on the server. For information on creating JMS resources, see the Sun Java System Application Server Developer’s Guide to J2EE Services and APIs.

Application Client Accessing JMS Resources Without Using the ACC

A stand-alone client uses the RMI/IIOP standard to communicate with Sun Java System Application Server. The J2EE 1.3 specification requires that a stand-alone client operate within the ACC context. However, Sun Java System Application Server allows Java platform clients to directly access the resources residing on the server. This section describes how you can develop a stand-alone client that can access the JMS resources directly without using the ACC path.

The sample application SimpleQueueClient.java is used here to describe the steps involved in developing a stand-alone client that looks up the JMS resources outside ACC and also send and receive messages to a queue on Sun Java System Application Server.

To create an application client:

  1. Import the JMS packages.
  2. import javax.jms.*;
    import javax.naming.*;

  3. Create an initial context.
  4. Context initialContext = new InitialContext();

    Do not pass any environment properties to the InitialContext constructor. Instead, obtain the ORBhost name and port number through the command line options.

  5. Look up the Queue by its JNDI name. Use the jms/sampleQCF string to lookup the JMS destination.
  6. private static final String LOOKUP_STRING_FACTORY = "jms/sampleQCF";

    private static final String LOOKUP_STRING_QUEUE = "jms/sampleQ";

    factory = (QueueConnectionFactory) initialContext.lookup(LOOKUP_STRING_FACTORY);

    queue = (Queue) initialContext.lookup(LOOKUP_STRING_QUEUE);

    InitialContext method is used to retrieve administered objects.

  7. To send and receive messages, you must follow the procedure to create a JMS client:
    • Create a QueueConnection to the message service. The connection provides access to the underlying transport of the message, and is also used to create sessions. Use the CreateQueueConnection() method on the factory object to create a connection.
    • Start the connection. Unless the connection is started, MessageConsumers associated with the messages cannot receive any messages.
    • Create a QueueSession. Sessions provide context for producing and consuming messages. Sessions are used to create message producers and message consumers, as well as build message themselves.
    • Create message producers. Use the session and destination to create a message producer. In this example, a QueueSender is created.
    • Create message consumers. Use the session and destination to create message consumer. In this example, a QueueReceiver is created.
    • Build a message. Use session to create an empty message and add the data.
    • Send the message. The message is passed to the send method on the QueueSender.
    • Receive the message. Use the QueueReceiver method to receive the message.
    • Retrieve the message contents. Call the receive method with a timeout argument (in milliseconds) greater than 0.
    • Close all JMS resources.
    • For detailed instructions on developing a JMS client, see the Sun Java System Application Server Developer's Guide to J2EE Services and APIs.

  8. Next, configure JMS resources on Sun Java System Application Server. You can either use the Administration Interface or the command line options to configure the resources.
  9. You need to configure the following general properties:

    • jmshost - Application Server host name
    • adminusr - Admin instance user name
    • adminpwd - Admin instance password
    • adminport - Admin instance port number
    • Configure the following Connection Factory and Destination resource.

      Connection Factory:

    • JNDI Name: jms/sampleQCF
    • Resource Type: javax.jms.QueueConnectionFactory
    • Destination Resource:

    • JNDI Name: jms/sampleQ
    • Resource Type: javax.jms/Queue
    • For information on configuring JMS resources, see the Sun Java System Application Server Administration Guide.


      Note

      You do not have to deploy this application on an ACC or Sun Java System Application Server as it is a stand-alone client.


  10. Run the client.
    1. Set the environment variable LD_LIBRARY_PATH. This variable should point to the Application Server, the Sun Java System MQ jar files and shared libraries:
    2. LD_LIBRARY_PATH=/usr/lib/mps:/opt/SUNWappserver7/lib:/usr/lib

      If the Application Server is on a different system, copy all the jar files and shared libraries from the /opt/SUNWappserver7/lib, /usr/share/lib/imq and /usr/lib/mps directories to the target system.

    3. Before running the client, set the values for the Java Virtual Machine startup options:
    4. jvmarg value = “-Dorg.omg.CORBA.ORBInitialHost=${ORBhost}”
      jvmarg value = “-Dorg.omg.CORBA.ORBInitialPort=${
      ORBport}”

      Here ORBhost is the Application Server hostname and ORBport is the ORB port number (default 3700 for server1 instance).

    5. Run the client.

The code of the sample application is given below:

package samples.jms.client;

import javax.jms.*;
import javax.naming.*;
import java.io.IOException;
import java.util.*;

public class SimpleQueueClient {

  private QueueConnectionFactory factory;
  private Queue queue;
  

  private static final String LOOKUP_STRING_FACTORY =    "jms/sampleQCF";
  private static final String LOOKUP_STRING_QUEUE = "jms/sampleQ";

  public static void main(String[] args) throws Exception

  {

  SimpleQueueClient client = new SimpleQueueClient ( );
  client.execute();
  }

public SimpleQueueClient ( ) throws Exception {

try {

  // create the initial context
  Context initialContext = new InitialContext();

  out("Looking up the queue connection factory from JNDI :"+LOOKUP_STRING_FACTORY);

  // look up the connection factory from the object store
  factory = (QueueConnectionFactory)
initialContext.lookup(LOOKUP_STRING_FACTORY);
out(LOOKUP_STRING_FACTORY + ": " + factory);

  // look up queue from the object store
  out("Looking up the queue from JNDI");
  queue = (Queue) initialContext.lookup(LOOKUP_STRING_QUEUE);
  out(LOOKUP_STRING_QUEUE + ": " + queue);

}

catch (NamingException e) {

  String msg = "An error was encountered trying to lookup an object from JNDI";
out(msg);
e.printStackTrace();

}

}

public void execute()

  throws IOException {

  final String  messageBody = "This is a sample message. It was " + "sent at " + new Date();

  QueueSession        session       =null;
  QueueConnection         connection       =null;
  QueueSender         queueSender       = null;
  QueueReceiver         queueReceiver       = null;
  String         successText       ="SUCCESSFUL";
  TextMessage         msgReceived       =null;

  try {

    // Creating a QueueConnection to the Message service

    out("Creating QueueConnection using the factory");

  connection = factory.createQueueConnection();
     out("Starting the Connection");
     connection.start();

  // Creating a session within the connection

    session = connection.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);
out("Creating a QueueSender");
queueSender = session.createSender(queue);
out("Creating a QueueReceiver");
queueReceiver = session.createReceiver(queue);

  // Building a message text

    out("Building a message" );
    TextMessage msgSent = session.createTextMessage();
    msgSent.setText(messageBody);

  // Sending message to the target queue

    out("Sending message to " + queue.getQueueName() );
    queueSender.send(msgSent);
    out( "Waiting for the return message" );

/* comment the following line to leave the message on the queue. then use the message queue product's admin tools to verify that the message was placed on the queue.
*/

// Retrieving the next message that arrives within the timeout interval of 2000 miliseconds

    msgReceived = (TextMessage) queueReceiver.receive(2000);

    if (msgReceived == null) {
    out("An error has occurred. The return message was not received.");
  successText = "UNSUCCESSFUL";

     } else {

    //Retreive the contents of the message.
if (msgReceived instanceof TextMessage) {

      TextMessage txtMsg = (TextMessage) msgReceived;

      out("\nMessage received: " + txtMsg.getText());

    }

  }

}

catch (JMSException e) {

  out("An unexpected exception occurred: " + e);
  Exception linkedException = e.getLinkedException();
  if (linkedException != null) {
    out("The linked exception is: " + linkedException);
  }

  e.printStackTrace();
  successText = "UNSUCCESSFUL";

} finally {

  // Close all JMS resources

  if (queueReceiver != null) {

    try {
   out("Closing QueueReceiver");
   queueReceiver.close();
   } catch (JMSException e) {
   out("There was an error closing the receiver");
   e.printStackTrace();

    }

  }

  if (queueSender != null) {
    try {
   out("Closing QueueSender");
   queueSender.close();
   } catch (JMSException e) {
   out("There was an error closing the sender");
   e.printStackTrace();

   }

   }

   if (session != null) {

     try {
      out("Closing session");
      session.close();
      } catch (JMSException e) {
   out("There was an error closing the session");
   e.printStackTrace()
   }
  }

  

  if (connection != null) {
    try {
      out("Closing connection");
      connection.close();
      } catch (JMSException e) {
      out("There was an error closing the connection");
      e.printStackTrace();

   }
   }

  destroy();

  }

}

public void destroy() {
  factory = null;
  queue = null;
}

private void out(String message) {
    System.out.println(message);
  }

}

Application Client Packaged in an Application Client Container Accessing JMS Resources

When the application client is packaged in an application client container, make the following changes to the code. In the sample application SimpleQueueClient.java, make the following changes:

  1. A J2EE application can be packaged using the Application Client Container. Use the java:comp/env/jms/ string to lookup the JMS resources. This is the J2EE application namespace.
  2. private static final String LOOKUP_STRING_FACTORY = "java:comp/env/jms/sampleQCF";

    private static final String LOOKUP_STRING_QUEUE = "java:comp/env/jms/sampleQ";

  3. The Application Client Container gets the ORB hostname and port number from the ACC configuration file sun-acc.xml.
  4. The <name> entry in this file will be the Application Server hostname and the port is the ORB port number (default 3700 for server1 instance).

  5. Assemble the application client to create a jar file. Include the two configuration files in the client jar file.
  6. sun-application-client.xml - Sun Java System Application Server specific J2EE client application

    For information on sun-application-client.xml file, see Sun Java System Application Client Deployment Descriptor.

    The contents of the sun-application-client.xml is as follows:

    <?xml version="1.0" encoding="UTF-8"?>

    <!DOCTYPE sun-application-client PUBLIC '-//Sun Microsystems, Inc.//DTD Sun ONE Application Server 7 Application Client 1.3//EN'

    'http://www.sun.com/software/appserver/dtds/sun-application-client_1_3-0.dtd'>

    <sun-application-client>

    <resource-ref>

    <res-ref-name>jms/sampleQ</res-ref-name>
    <jndi-name>jms/sampleQ</jndi-name>

    </resource-ref>

    <resource-ref>

    <res-ref-name>jms/sampleQCF</res-ref-name>
    <jndi-name>jms/sampleQCF</jndi-name>

    <resource-ref>
    <sun-application-client>

    application-client.xml - J2EE 1.3 application client deployment descriptor

    The contents of the application-client.xml is as follows:

    <?xml version="1.0" encoding="UTF-8"?>

    <!DOCTYPE application-client PUBLIC '-//Sun Microsystems, Inc.//DTD J2EE Application Client 1.3//EN' 'http://java.sun.com/dtd/application-client_1_3.dtd'>

    <application-client>

    <display-name>SimpleQueue</display-name>

    <resource-ref>

    <res-ref-name>jms/sampleQ</res-ref-name>

    <res-type>javax.jms.Queue</res-type>

    <res-auth>Container</res-auth>

    </resource-ref>

    <resource-ref>

    <res-ref-name>jms/sampleQCF</res-ref-name>

    <res-type>javax.jms.QueueConnectionFactory</res-type>

    <res-auth>Container</res-auth>

    </resource-ref>

    </application-client>

    These deployment descriptors describe the external JMS resources (administered objects) referenced by the sample application.

  7. Package the application client using the appclient script. See Packaging an Application Client Using the ACC.
  8. package-appclient script also creates a MANIFEST file that contains the main class, which states the complete package prefix and classname of the Java platform client.

  9. Run the application client using the ACC. For instructions, see Running an Application Client Using the ACC.

Authenticating an Application Client Using the JAAS Module

Using the JAAS module, you can provide security in your application client code. Create a LoginModule that describes the interface implemented by authentication technology providers. LoginModules are plugged in under applications to provide a particular type of authentication.The following steps are involved in creating a LoginModule:

  1. Write the LoginModule interface.
  2. public class ClientPasswordLoginModule implements LoginModule{

    private static Logger _logger=null;

    static{

    _logger=LogDomains.getLogger(LogDomains.SECURITY_LOGGER);

    }

    }

    private Subject subject;
    private CallbackHandler callbackHandler;
    private Map sharedState;
    private Map options;

    The standard JAAS package required by this class is javax.security. The code line below illustrates how you can import the package in your client application:

    import javax.security.*;

  3. Initialize the LoginModule interface that you just created.
  4. public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {

    this.subject = subject;
    this.callbackHandler = callbackHandler;
    this.sharedState = sharedState;
    this.options = options;

    }

    • The parameter subject, is the subject to be authenticated.
    • callbackHandler, for communicating with the end user which prompts for the username and password.
    • sharedState, is the shared LoginModule state.
    • options, the options specified in the configuration file of the LoginModule.
  5. Use login() method to fetch the login information from the client application and authenticate the user.
  6. public boolean login() throws LoginException {

    if (uname != null) {
      username = new String (uname);
      pswd = System.getProperty (LOGIN_PASSWORD);

    }

    The login information is fetched using the CallBackHandler.

    Callback[] callbacks = new Callback[2];

    callbacks[0] = new NameCallback(localStrings.getLocalString("login.username", "ClientPasswordModule username: "));

    callbacks[1] = new PasswordCallback(localStrings.getLocalString("login.password", "ClientPasswordModule password: "), false);

    username = ((NameCallback)callbacks[0]).getName();

    char[] tmpPassword = ((PasswordCallback)callbacks[1]).getPassword();

    The login() method tries to connect to the server using the login information that is fetched. If the connection is established, the method returns the value true.

  7. Use commit() method to set the subject in the session to the username that is verified by the login method. If the commit method returns a value true, then this method associates PrincipalImpl with the subject located in the LoginModule. If this LoginModule’s own authentication attempt is failed, then this method removes any state that was originally saved.
  8. public boolean commit() throws LoginException {
    if (succeeded == false) {
      return false;
      } else {
      // add a Principal (authenticated identity)to the Subject
      // assume the user we authenticated is the PrincipalImpl
        userPrincipal = new PrincipalImpl(username);

  9. Use logout() method to remove the privilege settings associated with the roles of the subject.
  10. public boolean logout() throws LoginException {

    subject.getPrincipals().remove(userPrincipal);
    succeeded = false;
    succeeded = commitSucceeded;
    username = null;
    if (password != null) {
      for (int i = 0; i < password.length; i++)
        password[i] = ’ ’;
        password = null;
    }
    userPrincipal = null;
    return true;
    }

  11. Edit the sun-acc.xml deployment descriptor to configure JAAS authentication for the client. See auth-realm.
  12. Integrate the LoginModule with the application server.
  13. Edit the deployment descriptor to make the following changes:

    • Configure the server with a realm that uses a specific LoginModule for security authentication.
    • Map the application realm and roles to the realm and roles defined by the LoginModule.
  14. Assemble the application client. See Packaging an Application Client Using the ACC.
Sample Code

The sample code of ClinetLoginPasswordModule is given below:

package com.sun.enterprise.security.auth.login;

import java.util.*;
import java.io.IOException;
import javax.security.auth.*;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
import javax.security.auth.spi.*;
import com.sun.enterprise.security.auth.login.PasswordCredential;
import com.sun.enterprise.security.PrincipalImpl;
import com.sun.enterprise.security.auth.LoginContextDriver;
import com.sun.enterprise.util.LocalStringManagerImpl;
import java.util.logging.*;
import com.sun.logging.*;

public class ClientPasswordLoginModule implements LoginModule {

private static Logger _logger=null;
  static{
    _logger=LogDomains.getLogger(LogDomains.SECURITY_LOGGER);
  }

private static final String DEFAULT_REALMNAME = "default";
private static LocalStringManagerImpl localStrings =
  new LocalStringManagerImpl(ClientPasswordLoginModule.class);

// initial state

private Subject subject;
private CallbackHandler callbackHandler;
private Map sharedState;
private Map options;

private boolean debug = com.iplanet.ias.util.logging.Debug.enabled;

// the authentication status

private boolean succeeded = false;
private boolean commitSucceeded = false;

// username and password

private String username;
private char[] password;

private final PasswordCredential passwordCredential=null;

// testUser’s PrincipalImpl

private PrincipalImpl userPrincipal;
public static String LOGIN_NAME = "j2eelogin.name";
public static String LOGIN_PASSWORD = "j2eelogin.password";

public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {

    this.subject = subject;
    this.callbackHandler = callbackHandler;
    this.sharedState = sharedState;
    this.options = options;

// initialize any configured options

    debug = "true".equalsIgnoreCase((String)options.get("debug"));

}

/* Authenticate the user by prompting for a username and password. @return true in all cases since this <code>LoginModule</code> should not be ignored.*/

/* @exception FailedLoginException if the authentication fails. @exception LoginException if this <code>LoginModule</code> is unable to perform the authentication.*/

public boolean login() throws LoginException {

// prompt for a username and password

if (callbackHandler == null){

  String failure = localStrings.getLocalString("login.nocallback","Error: no CallbackHandler available to garner authentication information from the user");

  throw new LoginException(failure);
}

String uname = System.getProperty (LOGIN_NAME);
String pswd;

if (uname != null) {

  username = new String (uname);
  pswd = System.getProperty (LOGIN_PASSWORD);
  char[] dest;
  if (pswd == null){
    dest = new char[0];
    password = new char[0];
  } else {
    int length = pswd.length();
    dest = new char[length];
    pswd.getChars(0, length, dest, 0 );
    password = new char[length];
  }
  System.arraycopy (dest, 0, password, 0, dest.length);
  } else{
    Callback[] callbacks = new Callback[2];
    callbacks[0] = new NameCallback(localStrings.getLocalString("login.username", "ClientPasswordModule username: "));
    callbacks[1] = new PasswordCallback(localStrings.getLocalString("login.password", "ClientPasswordModule password: "), false);

  try {
    callbackHandler.handle(callbacks);
    username = ((NameCallback)callbacks[0]).getName();
    if(username == null){
      String fail = localStrings.getLocalString("login.nousername", "No user specified");
      throw new LoginException(fail);
    }

    char[] tmpPassword = ((PasswordCallback)callbacks[1]).getPassword();

    if (tmpPassword == null) {
  // treat a NULL password as an empty password
    tmpPassword = new char[0];
    }
    password = new char[tmpPassword.length];
    System.arraycopy(tmpPassword, 0,
    password, 0, tmpPassword.length);
    ((PasswordCallback)callbacks[1]).clearPassword();
    } catch (java.io.IOException ioe) {
    throw new LoginException(ioe.toString());
    } catch (UnsupportedCallbackException uce) {
String nocallback = localStrings.getLocalString("login.callback","Error: Callback not available to garner authentication information from user(CallbackName):" );
throw new LoginException(nocallback + uce.getCallback().toString());

}

}

// print debugging information
if (debug) {

for (int i = 0; i < password.length; i++){
//System.out.print(password[i]);
}
//System.out.println();
}

// by default - the client side login module will always say
// that the login successful. The actual login will take place
// on the server side.
if (debug)

{
_logger.log(Level.FINE,"    [ClientPasswordLoginModule] " +"authentication succeeded");
succeeded = true;
return true;

}

public boolean commit() throws LoginException {
if (succeeded == false) {
  return false;
  } else {
  // add a Principal (authenticated identity)to the Subject
  // assume the user we authenticated is the PrincipalImpl
    userPrincipal = new PrincipalImpl(username);
    if (!subject.getPrincipals().contains(userPrincipal))
      subject.getPrincipals().add(userPrincipal);
      if (debug) {
      _logger.log(Level.FINE,"    [ClientPasswordLoginModule] " +"added PrincipalImpl to Subject");
  }

PasswordCredential pc = new PasswordCredential(username, new String(password), realm);
if(!subject.getPrivateCredentials().contains(pc))subject.getPrivateCredent ials().add(pc);

username = null;
for (int i = 0; i < password.length; i++){
password[i] = ’ ’;
password = null;
commitSucceeded = true;
return true;
}
}

public boolean abort() throws LoginException {
if (succeeded == false) {
return false;
} else if (succeeded == true && commitSucceeded == false) {
// login succeeded but overall authentication failed
  succeeded = false;
  username = null;
  if (password != null) {
    for (int i = 0; i < password.length; i++)
      password[i] = ’ ’;
      password = en das ull;
    }
    userPrincipal = null;
    } else {

    // overall authentication succeeded and commit succeeded,
    // but someone else’s commit failed
    logout();
    }
    return true;
    }

public boolean logout() throws LoginException {

subject.getPrincipals().remove(userPrincipal);
succeeded = false;
succeeded = commitSucceeded;
username = null;
if (password != null) {
  for (int i = 0; i < password.length; i++)
    password[i] = ’ ’;
    password = null;
}
userPrincipal = null;
return true;
}

}


Note

Sun Java System Application Server does not support authentication of RMI/IIOP Clients that do not use the ACC (non-ACC clients).


Invoking an RMI/IIOP-based Client Without Using the ACC

You can invoke a J2EE client without using the ACC. When you are creating an application client that does not use the ACC, you need to setup your development environment as follows:

  1. Include the following non-java libraries in the client’s classpath.
  2. Windows:

    The following libraries can be found at install_dir/bin:

    • cis.dll
    • libnspr4.dll
    • libplc4.dll
    • nss3.dll
    • ssl3.dll
    • Solaris:

      The following libraries can be found at install_dir/lib:

    • libcis.so
    • libnspr4.so
    • libplc4.so
    • libnss3.so
    • libssl3.so
  3. In addition to the non-java libraries, copy the following jar files to the client system and add them to the classpath:
    • appserv-ext.jar
    • appserv-rt.jar
    • fscontext.jar
    • imq.jar
    • imqadmin.jar
    • imqutil.jar

The following steps describe the procedure to create a client:

  1. Define the main class as shown in the code illustration below:
  2. public static void main(String[] args) {

    String url = null;

    String jndiname = null;

    boolean acc = true;

    }

  3. If the code sees the url and jndiname passed in, the acc flag is set to false and does the EJB lookup differently than it does if this client code is called by the application client utility without any arguments.
  4. if (args.length == 2 ) {

      url = args[0];
      jndiname = args[1];
      acc = false;
      System.out.println("url = "+url);

    }

  5. Obtain the naming initial context and perform the JNDI look up.
  6. Properties env = new Properties();

    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory");

    env.put(Context.PROVIDER_URL, url);

    initial = new InitialContext(env);

    objref = initial.lookup(jndiname);

  7. Run the client from the command line.

JNDIName matches the JNDIName specified in the deployment file.

Packaging an Application Client Using the ACC

After installing Sun Java System Application Server, the ACC can be run by executing the appclient script located+ in the install_dir/bin directory. The script package-appclient that is located in the same directory, is used to package a client application into a single appclient.jar file. Packaging an application client involves the following main steps:

Editing the Configuration File

Modify the environment variables in asenv.conf file located in the default-config_dir directory as shown below:

Editing the appclient Script

Modify the appclient script file as follows:

UNIX:

Change $CONFIG_HOME/asenv.conf to your_ACC_dir/config/asenv.conf.

Windows:

Change %CONFIG_HOME%\config\asenv.bat to your_ACC_dir\config\asenv.bat

Editing the sun-acc.xml File

Modify sun-acc.xml file to set the following attributes:

For more information on the sun-acc.xml file, see Application Client Container Configuration File.

Setting Security Options

You can run the application client using SSL with certificate authentication. In order to set the security options, modify the sun-acc.xml file as shown in the code illustration below. For more information on the sun-acc.xml file, see the Application Client Container Configuration File.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE client-container SYSTEM

"file:////export3/sun/appserver7/appserv/lib/dtds/sun-application-clien t-container_1_0.dtd">

<client-container>

<target-server name="qasol-e1" address="qasol-e1" port="3700">

<security>

<ssl cert-nickname="cts" ssl2-enabled="false" ssl2-ciphers="-rc4,-rc4export,-rc2,-rc2export,-des,-desede3"

ssl3-enabled="true"

ssl3-tls-ciphers="+rsa_rc4_128_md5,-rsa_rc4_40_md5,+rsa3_des_sha,+rsa_d es_sha,-rsa_rc2_40_md5,-rsa_null_md5,-rsa_des_56_sha,-rsa_rc4_56_sha"

tls-enabled="true" tls-rollback-enabled="true"/>

<cert-db path="/export3/ctsdata/ctscertdb" password="changeit"/>

</security>

</target-server>

<client-credential user-name="j2ee" password="j2ee"/>

<log-service file="" level="WARNING"/>

</client-container>

Using the package-appclient Script

The following steps describe the procedure to use the package-appclient script that is bundled with Sun Java System Application Server:

  1. Under install_dir/bin directory, run the package-appclient script. This creates an appclient.jar file and stores it under install_dir/lib/appclient/ directory.

  2. Note

    The appclient.jar file provides an application client container package targeted at remote hosts and does not contain a server installation. You can run this file from a remote machine with the same operating system as where it is created. That is, appclient.jar created on a Solaris platform will not function on Windows.


  3. Copy the install_dir/lib/appclient/appclient.jar file to the desired location. The appclient.jar file contains the following files:
    • appclient/bin - contains the appclient script which you use to launch the ACC.
    • appclient/lib - contains the JAR and runtime shared library files.
    • appclient/lib/appclient - contains the following files:
      • sun-acc.xml - the ACC configuration file.
      • client.policy file- the security manager policy file for the ACC.
      • appclientlogin.conf file - the login configuration file.
      • client.jar file - is created during the deployment of the client application.
    • appclient/lib/dtds - contains sun-application_client-contianer_1_3-0.dtd which is the DTD corresponding to sun-acc.xml.
client.policy

client.policy file is the J2SE policy file used by the application client. Each application client has a client.policy file. The default policy file limits the permissions of J2EE deployed application clients to the minimal set of permissions required for these applications to operate correctly. If you develop an application client that requires more than this default set of permissions, you can edit the client.policy file to add the custom permissions that your applications need. You can use the J2SE standard policy tool or any text editor to edit this file. For more information on using the J2SE policy tool, visit the following URL:

For more information about the permissions you can set in the client.policy file, visit the following URL:
http://java.sun.com/j2se/1.4/docs/guide/security/permissions.html

Running an Application Client Using the ACC

To run a client application that is packaged in an application jar file, you first need to launch the ACC. You can launch the application client container using appclient script.

appclient -client client_application_jar [-mainclass client_application_main_class_name|-name display_name][-xml sun-acc.xml] [-textauth] [-user user_name] [-password password]

The following example shows how to run the sample application client, rmiConverter:

appclient -client rmi-simpleClient.jar

Sample Client Application

You can find the sample client application that demonstrates the working of an RMI/IIOP client that uses an application client container at the following location:

install_dir/samples/rmi-iiop/simple



Previous      Contents      Index      Next     


Copyright 2004 Sun Microsystems, Inc. All rights reserved.