Home arrow Java arrow Page 8 - 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 - MultiApplet
(Page 8 of 9 )

MultiApplet

package com.croftsoft.core.gui.multi;

[...]

import com.croftsoft.core.CroftSoftConstants;
import com.croftsoft.core.awt.image.ImageLib;
import com.croftsoft.core.gui.FullScreenToggler;
import com.croftsoft.core.gui.LifecycleWindowListener;
import com.croftsoft.core.lang.NullArgumentException;
import com.croftsoft.core.lang.Pair;
import com.croftsoft.core.lang.lifecycle.Lifecycle;

public class  MultiApplet
  extends JApplet
  implements Lifecycle

/////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
{

The main class, MultiApplet, extends the Swing version of the Applet class, JApplet. It imports a number of other classes from the CroftSoft reusable code library. It implements the Lifecycle interface with its init(), start(), stop(), and destroy() methods so that it can be integrated into a generic Lifecycle framework container.

public static final String DEFAULT_NEWS_NAME = "News";

//

private final String    appletInfo;

private final Pair [ ]  appletPairs;

private final String    newsName;

private final String    newsHTML;

private final String    newsPage;

The instance variable appletInfo is returned when the getAppletInfo() method is called. Variables DEFAULT_NEWS_NAME, newsName, newsHTML, and newsPage are used to create an instance of MultiAppletNews.

A Pair is a convenience class from package com.croftsoft.core.lang that I use to hold together a related pair of String objects, usually a name-value pair. I like to use an array of Pair instead of two separate String arrays because then I do not have to worry about the String arrays accidentally being of unequal length. In the MultiApplet class, I use the name to store the short name of a game applet to be displayed on a tab at the top of a JTabbedPane. The value is the class name of the corresponding game applet.

private JTabbedPane       jTabbedPane;

private Component         appletComponent;

private boolean           isStarted;

private int               index;

private MultiAppletStub multiAppletStub;

This JApplet subclass maintains an instance reference to a JTabbedPane Swing component. The JTabbedPane is used to contain your game applets. When the user clicks a tab, a different game is loaded.

The appletComponent is a reference to the game currently loaded. Note that it is an instance of Component, not Applet. The boolean flag isStarted provides life-cycle state information. The index variable indicates which tab is currently selected. The MultiAppletStub instance is used to propagate the AppletContext to the game applets.

public static void main ( String [ ] args )
//////////////////////////////////////////////////////////
{
 launch (
  CroftSoftConstants.DEFAULT_APPLET_INFO,
  new Pair [ ] {
    new Pair ( "Applet1", "javax.swing.JApplet" ),
    new Pair ( "Applet2", "javax.swing.JApplet" ) }, 
 DEFAULT_NEWS_NAME,
 ( String ) null,
 CroftSoftConstants.HOME_PAGE,
 "CroftSoft MultiApplet",
 CroftSoftConstants.FRAME_ICON_FILENAME, 
 MultiApplet.class.getClassLoader ( ),
 ( Dimension ) null,
 "Close CroftSoft MultiApplet?" );
}

You use static method main() to test the MultiApplet from the command line. It passes test data to the following launch() method.

  public static  void          launch (
    String                 appletInfo,
    Pair [ ]               appletPairs,
    String                 newsName,
    String                 newsHTML,
    String                 newsPage,
    String                 frameTitle,
    String                 frameIconFilename,
    ClassLoader            frameIconClassLoader,
    Dimension              frameSize,
    String                 shutdownConfirmationPrompt )
  ///////////////////////////////////////////////////////
  {
    JFrame jFrame = new JFrame ( frameTitle );

    try
    {
      Image iconImage = ImageLib.loadBufferedImage (
        frameIconFilename, frameIconClassLoader );
      if ( iconImage != null )
      {
        jFrame.setIconImage ( iconImage );
      }
  }
  catch ( Exception ex )
  {
  }

The static launch() method launches the program when it is not embedded in a web page as an applet. This allows it to be run as an executable JAR desktop application or as a Java Web Start application. It starts by creating a new frame and setting the frame icon image, that little picture at the top left corner of the frame. If it cannot find the image, it ignores it and moves on.

 MultiApplet multiApplet = new MultiApplet (
   appletInfo, appletPairs, newsName, newsHTML, 
        newsPage );

 jFrame.setContentPane ( multiApplet );

 FullScreenToggler.monitor ( jFrame );

 LifecycleWindowListener.launchFrameAsDesktopApp (
   jFrame,
   new Lifecycle [ ] { multiApplet },
   frameSize,
   shutdownConfirmationPrompt );
}

It then creates an instance of the MultiApplet and sets it as the content page for the frame. Method FullScreenToggler.monitor(), described in Chapter 5, is used to allow the user to toggle between windowed and full screen mode. The static convenience method launchFrameAsDesktopApp in class LifecycleWindowListener shows the frame and calls the appropriate lifecycle methods on the MultiApplet instance when the user activates, deactivates, or closes the window.

 public  MultiApplet (
   String     appletInfo,
   Pair [ ]   appletPairs,
   String     newsName,
   String     newsHTML,
   String     newsPage )
///////////////////////////////////////////////////////
{
   NullArgumentException.check ( this.appletInfo = 
            appletInfo );

   NullArgumentException.check ( this.appletPairs = 
            appletPairs );

   NullArgumentException.check ( this.newsName =
            newsName );

   this.newsHTML = newsHTML;

   this.newsPage = newsPage;
}

The constructor method simply saves references to the constructor arguments for later use in the init() method.

  public String getAppletInfo ( )
  /////////////////////////////////////////////////////     {
    return appletInfo;
}

public void init ( )
 ////////////////////////////////////////////////////////// {
 
Container contentPane = getContentPane ( );

 
contentPane.setLayout ( new BorderLayout ( ) );

 
jTabbedPane = new JTabbedPane (
   JTabbedPane.TOP, JTabbedPane.SCROLL_TAB_LAYOUT );

 
contentPane.add ( jTabbedPane, BorderLayout.CENTER );

The init() code makes the JTabbedPane fill the frame. The tabs run along the top and can be scrolled left and right when there are too many to fit in the width of the window. By using the scroll tab layout, you can have a large number of tabs, one for each game, without using up additional screen real estate.

 jTabbedPane.add (
  new MultiAppletNews ( newsHTML, newsPage, this ),
                   newsName );

On the first tab, I put the special component called MultiAppletNews. I treat this component differently from the others because it downloads a web page from my web site. I do not want it to be destroyed when a user clicks another tab because it would then have to download the web page again when the user comes back to it. For this reason, as documented in the following code, the code treats this particular panel differently from the others.

for ( int i = 0; i < appletPairs.length; i++ )
{
jTabbedPane.add ( new JPanel ( ), appletPairs [ i ].name );
}

I then create all the other tabs as labeled with the short names of the games.

 jTabbedPane.addChangeListener (
  new ChangeListener ( )
  {
    public void stateChanged ( ChangeEvent changeEvent )
    {
    handleStateChange ( );
  }
 });

multiAppletStub = new MultiAppletStub ( this );
}

I add a ChangeListener to the JTabbedPane so that I can tell when a user clicks a different tab. I end the initialization method by creating a MultiAppletStub instance.

 public void start ( )
 /////////////////////////////////////////////////////////
 {
   multiAppletStub.setActive ( true );

   try
   {
     if ( appletComponent instanceof Applet )
     {
      ( ( Applet ) appletComponent ).start ( );
     }
     else if ( appletComponent instanceof Lifecycle )
     {
      ( ( Lifecycle ) appletComponent ).start ( );
     }
  }
  catch ( Exception ex )
  {
    ex.printStackTrace ( );
  }

  isStarted = true;
}

The start() method of MultiApplet delegates to the start() method of the current appletComponent if it can determine that it is an instance of Applet or Lifecycle. Note that to be included within MultiApplet, a game must extend Component but it does not have to extend Applet or implement Lifecycle. An example of this might be a game where the updates are driven exclusively by user-input events such as mouse clicks instead of a continuously running animation thread.

 public void stop ( )
 /////////////////////////////////////////////////////////
 {

   multiAppletStub.setActive ( false );

   try
   {
     if ( appletComponent instanceof Applet )
     {
      ( ( Applet ) appletComponent ).stop ( );
     }
     else if ( appletComponent instanceof Lifecycle )
     {
      ( ( Lifecycle ) appletComponent ).stop ( );
     }
  }
  catch ( Exception ex )
  {
   ex.printStackTrace ( );
  }

  isStarted = false;
 }

 public synchronized void destroy ( )
 ////////////////////////////////////////////////////////
{
   try
   {
    if ( appletComponent instanceof Applet )
    {
        ( ( Applet ) appletComponent ).destroy ( );
    }
    else if ( appletComponent instanceof Lifecycle )
    {
        ( ( Lifecycle ) appletComponent ).destroy ( );
    }
  }
  catch ( Exception ex )
  {
    ex.printStackTrace ( );
  }
}

The stop() and destroy() methods are similar. The start() and stop() methods mutate the active state of the MultiAppletStub. These methods are usually called in response to windowing events such as window activated or deactivated, window minimized or maximized, or window closed.

 private void handleStateChange ( )
 ////////////////////////////////////////////////////////
 {
   if ( isStarted )
   {
     stop ( );
   }

If the user clicks a different tab and the currently selected game is running, the handleStateChange() method stops it.

 if ( index > 0 )
 {
   jTabbedPane.setComponentAt ( index, new JPanel ( ) );

   destroy ( );

   appletComponent = null;

   System.gc ( );
 }

 index = jTabbedPane.getSelectedIndex ( );

An index position of zero indicates that the tab panel containing Multi-AppletNews is being displayed. Unless the current index position is zero, the current appletComponent is destroyed and all references to it are removed. A garbage collection of system memory is forced at this point to reduce the chances that it will automatically run later and interrupt the animation of the newly selected game. The index position is updated to point to the newly selected tab panel.

 if ( index > 0 )
 {
   try
   {
    appletComponent = ( Component ) Class.forName (
      appletPairs [ index - 1 ].value ).newInstance ( );

If the new index position is not zero, the game is loaded into memory using dynamic linking.

if ( appletComponent instanceof Applet )
{
( ( Applet ) appletComponent ).setStub ( multiAppletStub );
}

if ( appletComponent instanceof JComponent )
{
FullScreenToggler.monitor ( ( JComponent ) appletComponent );
}

jTabbedPane.setComponentAt ( index, appletComponent );

If the appletComponent is an instance of Applet, the AppletStub is set. If it is an instance of JComponent, we can monitor it for keyboard events that toggle full screen mode. All the dynamically loaded classes must at least extend Component so that they can be added to the JTabbedPane.

  try
  {
   if ( appletComponent instanceof Applet )
   {
     ( ( Applet ) appletComponent ).init ( );
   }
   else if ( appletComponent instanceof Lifecycle )
   {
     ( ( Lifecycle ) appletComponent ).init ( );
   }
  }
  catch ( Exception ex )
  {
   ex.printStackTrace ( );
  }

  start ( );
 }
catch ( Exception ex )
 {
    ex.printStackTrace ( );
  }
 }
}

The init() method of the new appletComponent instance is followed by a call to the start() method of the MultiApplet. Note that the init() method of the MultiApplet initializes the MultiApplet but its start() method initializes the appletComponent.

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