Home arrow Java arrow Page 5 - Deployment Frameworks
JAVA

Deployment Frameworks


Once you have learned how to program games in Java, you will want to be able to deploy them on different types of deployment frameworks. This article will cover browser applets, executable JARs, and Java Web Start. It is excerpted from the book Advanced Java Game Programming written by David Wallace Croft (Apress, 2004; ISBN 1590591232).

Author Info:
By: Apress Publishing
Rating: 4 stars4 stars4 stars4 stars4 stars / 11
April 12, 2005
TABLE OF CONTENTS:
  1. · Deployment Frameworks
  2. · Reading from a JAR File
  3. · Signing Applets
  4. · Deploying with Java Web Start
  5. · Isolating Optional Packages
  6. · Deploying Multiple Applets as One
  7. · Lifecycle
  8. · MultiApplet
  9. · CroftSoftCollection

print this article
SEARCH DEVARTICLES

Deployment Frameworks - Isolating Optional Packages
(Page 5 of 9 )

Isolating Optional Packages

Assuming a JNLP API implementation is available on the client platform, the showDocument() method of class BasicService automatically launches the default web browser on the client platform using platform-independent code. However, you will often want to write your game code in such a way that it can still run in an environment where the JNLP libraries are not installed. Ideally, your compiled game code should be able to run as a browser applet, an executable JAR, and as a JNLP Java Web Start application without modification. You can do this by including code that loads the JNLP class libraries, if available on the client machine, or gracefully continue on if not.

  private static JnlpServices createJnlpServices ( )
  /////////////////////////////////////////////////       
{
  try
   {
    return ( JnlpServices )
      Class.forName 
      ( JnlpServices.IMPL_CLASS_NAME ).newInstance ( );
  }
catch ( Exception ex )
  {
   return null;
  }
catch ( NoClassDefFoundError er )
  {
return null;
 }
}

The trick to this is to use dynamic class loading. You could also use reflection to accomplish this feat, but I find that as a general rule it is better to use custom interfaces and dynamic class loading. You start by first separating out the code that statically links to the optional package library javax.jnlp. You then attempt to dynamically load that code using Class.forName().newInstance(). If JNLP is not installed, the attempt generates a NoClassDefFoundError which you can then catch and handle gracefully. The preceding code from class JnlpLib in package com.croftsoft.core.jnlp does just that.

packagecom.croftsoft.core.jnlp;

import java.io.*;
import java.net.*;

public interface JnlpServices
/////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
{

public static final String IMPL_CLASS_NAME
= "com.croftsoft.core.jnlp.JnlpServicesImpl";

[...]

public boolean showDocument ( URL url )
  throws UnsupportedOperationException;

In this case, JnlpServices is an interface in package com.croftsoft.core.jnlp with no static links to package javax.jnlp. IMPL_CLASS_NAME is the name of a class, JnlpServicesImpl. This class provides a concrete implementation of the JnlpServices interface that does require static links to the optional package. A custom interface reference allows your code to handle optional package libraries without static linking and without using reflection.


CAUTION In teaching a course on Java game programming, I noted that forgetting to explicitly name dynamically linked classes in the Ant build file was one of the most common causes of grief for my students. This can be difficult to debug as it will not generate a compile-time error and might not generate a runtime error. The calling code might silently ignore a runtime error and carry on under the assumption that JnlpServicesImpl could not load dynamically because the game is not running within a JNLP client container. The truth of the matter, however, might be that JnlpServiceImpl could not be loaded because it was not compiled and included in the JAR file.

  public static final JnlpServices JNLP_SERVICES
     = createJnlpServices ( );

  [...]

  public static boolean showDocument ( URL url )
     throws UnsupportedOperationException
/////////////////////////////////////////////////////////
{
check ( );

return JNLP_SERVICES.showDocument ( url );
}

[...]

private static void check ( )
  throws UnsupportedOperationException
////////////////////////////////////////////////////////
{
  if ( JNLP_SERVICES == null )
  {
   throw new UnsupportedOperationException ( );
  }
}

Static method showDocument() in class JnlpLib uses the implementation class if it can be dynamically loaded. If not, it throws an UnsupportedOperation-Exception that the calling game code can catch and handle gracefully.

  package com.croftsoft.core.jnlp;

  import java.io.*;
  import java.net.*;

  import javax.jnlp.*;

  [...]

  public final class JnlpServicesImpl
    implements JnlpServices
  ///////////////////////////////////////////////////////
  //////////////////////////////////////////////////////
  {

 [...]

  public boolean showDocument ( URL url )
    throws UnsupportedOperationException
  /////////////////////////////////////////////////////
  {
    try
    {

     BasicService basicService = ( BasicService )
       ServiceManager.lookup ( "javax.jnlp.BasicService" );
     return basicService.showDocument ( url );
  }
  catch ( UnavailableServiceException ex )
  {
   throw ( UnsupportedOperationException )
    new UnsupportedOperationException ( ).initCause ( ex );
  }
 }

When using the showDocument() method in AppletContext, an instance of AppletContext is retrieved using the applet instance’s own getAppletContext() method. An instance of interface BasicService, however, is retrieved using the static method lookup() of class javax.jnlp.ServiceManager.

public static Object lookup ( String name )
  throws UnavailableServiceException;

If an implementation of BasicService is not available from the JNLP client, the ServiceManager throws an UnavailableServiceException. JnlpServicesImpl converts this exception from the optional package javax.jnlp to an Unsupported-OperationException from the core package java.lang if it is thrown. Note that the Throwable.initCause() method is used to attach the original exception to the new exception for examination by the calling code.

Dynamic Linking Using Reflection

As an alternative, you can also dynamically load the JNLP classes using reflection as shown in this code excerpt from class JnlpProxy in package com.croftsoft.core.jnlp.

  private static Object getBasicServiceObject ( )
  /////////////////////////////////////////////////////
{
  try
 
{
  
Class serviceManagerClass
    
= Class.forName ( "javax.jnlp.ServiceManager" );
  
Method lookupMethod = serviceManagerClass.getMethod 
     "lookup", new Class [ ] { String.class } );
  
return lookupMethod.invoke (
    
null, new Object [ ] { "javax.jnlp.BasicService" } );
 
}
 
catch ( Exception ex )
 
{
  
return null;
  }
}
Class Method is from core package java.lang.reflect.
 public static boolean showDocument ( URL url )
 /////////////////////////////////////////////////////////  {
  if ( basicServiceObject == null )
       {
         return false;
       }
       try
       {
        Method method=basicServiceClass.getMethod (
          "showDocument", new Class [ ] { URL.class } );
       Boolean resultBoolean = ( Boolean ) method.invoke (
        basicServiceObject, new Object [ ] { url } );
       return resultBoolean.booleanValue ( );
       }
       catch ( Exception ex )
       {
       
ex.printStackTrace ( );
        
throw new RuntimeException ( ex.getMessage ( ) );
       }
    }

By saving a singleton static reference to the BasicService instance retrieved, we can then use it within our own static showDocument() method. The example method returns false if the client platform does not support JNLP, allowing the calling code to respond with a substitute behavior.

In my opinion, dynamic linking using custom interfaces instead of reflection makes for more comprehensible code. I have found that you almost never need reflection techniques if you keep this in mind.

This article is excerpted from Advanced Java Game Programming by David Wallace Croft (Apress, 2004; ISBN 1590591232). Check it out at your favorite bookstore today. Buy this book now.


blog comments powered by Disqus
JAVA ARTICLES

- Java Too Insecure, Says Microsoft Researcher
- Google Beats Oracle in Java Ruling
- Deploying Multiple Java Applets as One
- Deploying Java Applets
- Understanding Deployment Frameworks
- Database Programming in Java Using JDBC
- Extension Interfaces and SAX
- Entities, Handlers and SAX
- Advanced SAX
- Conversions and Java Print Streams
- Formatters and Java Print Streams
- Java Print Streams
- Wildcards, Arrays, and Generics in Java
- Wildcards and Generic Methods in Java
- Finishing the Project: Java Web Development ...

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials