D:\DEV\PROJECTS\SpaceInvaders_Ship\src\spaceinvaders_ship\CDUnit.java
/*
 * CDUnit.java
 */

package spaceinvaders_ship;
import java.util.ArrayList;
import kewlstuff.lwjgl.examples.spaceinvaders.interfaces.*;
import kewlstuff.harbor.client.Vessel; //Added

/**
 *
 * @author Johnny Kewl
 *
 * CDUnits control the application, please refer to the documentation and
 * other samples to understand CDUnits...
 *
 * What I want to talk about here is a trick we using.
 * Harbor is a Java application server, however games often use
 * JNI (C++) libraries.
 * So now what??? How does one get JNI libraries to work on a remote machine?
 *
 * The trick is to use the characteristics of Java and understand a little
 * more about how Harbor works.
 * A Java resource normally sits inside a Jar file, things like Icons, images
 * sounds, property files etc etc.
 * Harbor naturally has the ability to use these resources remotely.
 * If a remote client say accesses an Icon, in a function like getResourceAsStream,
 * what Harbor actually does is move that resource to the clients machine.
 * Thus a user need not worry about an Icon used in many places being downloaded
 * over and over again, Harbor makes sure it only moves over the wire once.
 * Now when one uses something like a url = getResource function in Harbor,
 * what Harbor again does is move the resource to the clients machine and thus
 * that URL is local to the remote client.
 * In other words the client application is completely un-aware that its on the
 * wire and internal functions that use that resource do not have to be internet
 * enabled, and not only can one write normal applications, optimization is
 * also taken care of by Harbor.
 * 
 * So there you have it, its that easy... all we have to do is place the
 * JNI libs in a Java Package and we know they will end up on the remote client.
 * So we put them in a package called kewlstuff.spaceinvader.native_libs
 * and simply by doing this: url = getResource("/kewlstuff/spaceinvader/native_libs/filename
 * in the software, we know that the URL on the remote machine will point at that
 * JNI library local *to* the remote client.
 *
 * This game library wants the local property 
 *  System.setProperty("org.lwjgl.librarypath",pathToLibrary);  
 * set for the JNI libraries and all the code below does is map the
 * URL back to a file path, and url = getResource for every library.
 *
 * Harbor for efficiency reasons does not work with full Jars remotely, it just
 * gets and stores the actual resource, so we know that the mapping is to
 * a JNI library file.
 *
 * Note that this is not true for the stand alone application....
 * This will work in the stand-alone application *only* in the dev environment
 * but not in a standalone package, because the url reference will
 * be to the resource inside a Jar file... thus if you want to use this
 * standalone, you will have to add some code that gets the JNI resource and
 * copies it out of the jar to another location. However when used in
 * Harbor on remote machines... the resource is not stored in a Jar, so
 * the game software will see a normal file.
 *
 * This is more than just a clever way to use JNI libraries in Harbor,
 * its also a great way to package JNI in any application, so one doesnt
 * have stray files hanging around outside the Java package.
 */
public class CDUnit implements I_CDUnit{
   private I_Welcome w = null; 
   private Vessel vessel = null; //Added
    
    
    /** Creates a new instance of CDUnit */
    public CDUnit() {
        String harborUrl = "http://localhost:8080/harbor/service"; //Added
        vessel = new Vessel(harborUrl); //Added 
        //vessel.verboseVessel(true); // for debugging
        vessel.enableProgressDisplay(true); //for internet apps        
    }
    
    //Trick to load up JNI libs remotely
    //Note if you want to package this standalone as well, add code that
    // moves the resource out of the Jar file.
    public boolean prepareJniLibs(){
        ArrayList theLibs = new ArrayList();
        String JniFolder = null;
        String os = System.getProperty("os.name");
        os = os.toUpperCase();
        
        //Please note... I could not test this logic on all systems, guessed ;)
        if(os.indexOf("WINDOWS") >= 0){
            JniFolder = "win32";
            theLibs.add("OpenAL32.dll");
            theLibs.add("jinput-dx8.dll");
            theLibs.add("jinput-raw.dll");
            theLibs.add("lwjgl.dll");
        }else if(os.indexOf("LINUX") >= 0){
            JniFolder = "linux";
            theLibs.add("libjinput-linux.so");
            theLibs.add("liblwjgl.so");
            theLibs.add("liblwjgl64.so");
            theLibs.add("libopenal.so");            
        }else if(os.indexOf("MAC") >= 0){
            JniFolder = "macosx";
            theLibs.add("libjinput-osx.jnilib");
            theLibs.add("liblwjgl.jnilib");
            theLibs.add("openal.dylib");
        }else{
            System.out.println("ERROR: Could not detect operating system");
            return false;
        }
        
        //Note the class we working with... the remote Welcome dialog.
        java.net.URL url = w.getClass().getResource("/kewlstuff/spaceinvader/native_libs/" + JniFolder + "/" + theLibs.get(0));
        if(url == null){
            System.out.println("ERROR: Libraries are not in a resource");
            return false;        
        }
        
        //We got the url to the resource, this just converts it back to a normal folder path
        String pathToLibrary = url.getPath();
        int idx = pathToLibrary.indexOf("/" + (String)theLibs.get(0));
        pathToLibrary = pathToLibrary.substring(0,idx);
        java.io.File f = new java.io.File(pathToLibrary);
        try{pathToLibrary = f.getCanonicalPath();}catch(Exception e){}
        
        //The libraries use JNI native libraries and need this system property to find them
        System.setProperty("org.lwjgl.librarypath",pathToLibrary);    
        
        //Check all libraries present
        //On Harbor this will also cause the resource to be loaded remotely
        //The idea is while the user is looking at the first dialog, we bring down these
        //resources...
        //Here we bringing down the JNI libs but one could use the same trick to
        // preload sound files... any resource.
        for(int i = 0; i < theLibs.size(); i++){
            java.net.URL urlTest = w.getClass().getResource("/kewlstuff/spaceinvader/native_libs/" + JniFolder + "/" + theLibs.get(i));
            if(urlTest == null){
                System.out.println("ERROR: Library missing: " + urlTest.toString());
                return false;            
            }            
        }
        
        return true;
        
    }
    
    public void startGame() {
        //I_Game i_game = new Game(true); //FullScreen;
        Class uiApp = vessel.getRemoteClass("kewlstuff.lwjgl.examples.spaceinvaders.Game");//Added
        if(uiApp != null){
            Object[] contructorArgs = new Object[] {false}; //Game has a constructor   
            Class[] contructorTypes = new Class[] {boolean.class};
            I_Game i_game = (I_Game)vessel.newInst(uiApp,contructorArgs,contructorTypes);//Added
            try{
             i_game.execute();
            }catch(Exception e){System.out.println("ERROR: " + e.getMessage()); e.printStackTrace();} 
        }        
        
        //Possible bug in game software... will not start twice
        // which probably means it doesnt dispose of resources properly?
        //Before you put this on line, fix that...
        // because its forcing the user to hit the server everytime they want to play
        // and all the good stuff that Harbor does for you like cache resources, store
        // classses in remote classloaders etc ... is thrown away because of this.
        //The ideal is to leave the Welcome screen open and just let the user start it
        // again and again... it will not come back to the server then.
        
        //KILL IT  Shouldnt have to do this... but if you dont, machine gets sluggish
        // and one can see java process working on something.
        //Apologies but I dont have time to fix the 3rd party game sample.
        System.exit(0); 
    }     
    
    public void start() {
        //I_Welcome w = new Welcome(this);
        Class uiApp = vessel.getRemoteClass("spaceinvaders.Welcome");//Added
        if(uiApp != null){
            w = (I_Welcome)vessel.newInst(uiApp);//Added
            w.start(this);
        }         
    }    
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new CDUnit().start();
    }
    
}