Archive for April, 2007

Java 3D Application in JavaScript (Irrlicht & Jirr)

Tuesday, April 24th, 2007

With the new features of Java 1.6 it is incredibly easy to add scripting capabilities to your programs. By using JavaScript you do not have to recompile your application every time you change something, also JavaScript is much easier especially for those new to Java.

Check out the way we implement an Irrlicht application in JavaScript. Of course, you have to download Jirr & have JDK 1.6 installed.

This is the Java program to load and execute the JavaScript code:

JAVA:

  1. package com.javazing.gameengine;
  2.  
  3. import java.io.BufferedInputStream;
  4. import java.io.File;
  5. import java.io.FileInputStream;
  6. import java.io.InputStream;
  7. import java.io.InputStreamReader;
  8. import java.io.Reader;
  9.  
  10. import javax.script.ScriptEngine;
  11. import javax.script.ScriptEngineManager;
  12.  
  13. /**
  14. *
  15. * This program loads and executes the JavaScript program
  16. *
  17. * @author Sergey Nechaev (snechaev@javazing.com)
  18. *
  19. */
  20. public class GameEngine {
  21.  
  22.     private static final String SCRIPT_ENGINE_NAME = "js";
  23.  
  24.     private static final String SCRIPT_FILE_NAME = "script/js.js";
  25.  
  26.     private ScriptEngine jsEngine;
  27.  
  28.     private ScriptEngineManager mgr;
  29.  
  30.     static {
  31.         System.loadLibrary("irrlicht_wrap");
  32.     }
  33.  
  34.     public static void main(String[] args) throws Exception {
  35.  
  36.         new GameEngine();
  37.  
  38.     }
  39.  
  40.     public GameEngine() throws Exception {
  41.  
  42.         mgr = new ScriptEngineManager();
  43.         jsEngine = mgr.getEngineByExtension(SCRIPT_ENGINE_NAME);
  44.  
  45.         // InputStream is = this.getClass().getResourceAsStream("js.js");
  46.         File file = new File(SCRIPT_FILE_NAME);
  47.         InputStream is = new BufferedInputStream(new FileInputStream(file));
  48.  
  49.         Reader reader = new InputStreamReader(is);
  50.         jsEngine.eval(reader);
  51.  
  52.     }
  53.  
  54. }

And the JavaScript with the 'HelloWorld' example from the Irrlicht distribution:

JavaScript:

  1. importPackage(net.sf.jirr);
  2. importPackage(java.lang);
  3.  
  4.  
  5. var device = Jirr.createDevice(E_DRIVER_TYPE.EDT_OPENGL,
  6. new dimension2di(640, 480), 16, false, false, false, null);
  7.  
  8. print("idevice = " + device);
  9.  
  10. var windowCaption = "Java@Hello World! - Irrlicht Engine Demo";
  11. device.setWindowCaption(windowCaption);
  12.  
  13. var driver = device.getVideoDriver();
  14. var smgr = device.getSceneManager();
  15. var guienv = device.getGUIEnvironment();
  16.  
  17. var text = "Hello World! This is the Irrlicht Software engine for Java!";
  18. var rect = new recti(10, 10, 280, 30);
  19. var staticText = guienv.addStaticText(text, rect, true, true, null, -1);
  20.  
  21. smgr.addCameraSceneNode(null, new vector3df(0,10,-60),
  22. new vector3df(0,0,0), -1);
  23.  
  24. var step = 100;
  25. var counter = 0;
  26. var diff /*= 0*/;
  27. var timer1 = System.currentTimeMillis();
  28. var timer2 /*= 0*/;
  29. while(device.run())
  30. {
  31.  
  32.  
  33.     var a = 0;
  34.     var r = 100;
  35.     var g = 100;
  36.     var b = 100;
  37.  
  38.     driver.beginScene(true, true, new SColor(a, r, g, b));
  39.  
  40.     smgr.drawAll();
  41.     guienv.drawAll();
  42.  
  43.     driver.endScene();
  44.  
  45.     counter++;
  46.     if (counter>= step)
  47.     {
  48.         timer2 = System.currentTimeMillis();
  49.         diff = 1000.0 / ((timer2 - timer1) / step);
  50.         counter = 0;
  51.         timer1 = System.currentTimeMillis();
  52.  
  53.         //text = Jirr.createWchar("This is the Irrlicht Software
  54.         //engine for Java! FPS: " + diff);
  55.         text = "This is the Irrlicht Software engine for Java! FPS: " + diff;
  56.         staticText.setText(text);
  57.     }
  58. }
  59.  
  60. device.closeDevice();

Protect Your Contact Form against Spammers

Friday, April 6th, 2007

‘Contact Us’ page

How a user can contact the administration of a web site? Usually every web site has a ‘contact us’ page with the contact details of people in charge. Moreover, this is not really convenient. A user has to start his mail client, to make sure the address of the recipient is correct, to make sure the mail account (if he/she has many) is correct, and to add the subject and so on.

Those people who have no mail client program installed (probably, millions including my mother and sister) have to log in to their HOTMAIL or YAHOO accounts and compose a letter. In addition, the spammers have those programs that scan the Internet to collect e-mail addresses. Very soon, the owners of the web site start receiving hundreds and thousands of spam letters. Moreover, the important letter from the customer can be deleted accidentally by the person in charge or by the sophisticated ‘anti-spam’ program.

As you can see a regular ‘contact us’ page with an e-mail specified is pain in the arse for everyone involved. What is the proper way to go? A custom form made specifically to serve the guests and the administration of a web site will handle that simple but important task for you.

All the user has to do is to write (or select) a proper subject, his name and e-mail, write his message and hit the ‘SEND’ button. Fast and furious.

Though the form on the screenshot requires user’s e-mail address and name it is sometimes better not to require them. Instead of performing unnecessary validations and getting fake names and emails anyway, you may want to let it go.

Stop Spammers

The form is simple for a web developer, what I would like to emphasize is the potential vulnerability of the form. The spammers may use your form to perform mass mailing campaigns on behalf of your server. The rule number one here is to make sure the user information is never set to the headers of the generated e-mail address. Your code MUST have hardcoded FROM, TO, SUBJ, CC fields. All the information from the contact form MUST be written to the body of the message. Additionally you may want to filter it against HTML and JavaScript tags, though some may see this is paranoid.

Stop Spam

Additionally you may want to stop people from spamming the mailbox that receives the contact form messages. Some web developers add CAPTCHA (a picture of random numbers) to the contact form. Personally I hate CAPTCHAs, it is such a pain to ‘guess’ what is written there. In addition, any advanced spammer will get around it: they use XXX sites with photos and your CAPTCHA in a frame. Moreover, in order to see the next photo, the XXX maniac deciphers your CAPTCHA. Nice approach.

I prefer filtering the user’s input on the server side against a list of well-known words such as ‘stock’ or ‘Viagra’ words. Just make sure your users do not need to submit this information for your site.

Conclusion

And there is a rule number two for every web developer when defending your web site: be quiet. It is so tempting sometimes to give an ironic feedback – do not do that. Silence is the secret weapon here. Let your code do nothing or react with a regular response.

Good luck!

Creating a Distribution Package of Your Java Application

Thursday, April 5th, 2007

Say, you have written a Java application and now it is time to create windows installer package to upload it to your site so that anybody could download it, run and enjoy your proggy. Of course, one can distribute a plain JAR file, but not all users will be able to start it successfully.

It is better to give them a normal plain installer package that they know how to run through the wizard. You may also want to bundle a JRE with your application so your program will run on every machine with no JRE installed. I would also advise obfuscate your code, thus, no evil hacker could get your code too easily. It also makes sense to wrap your Java application in a regular windows executable (EXE) file.

You will need the following tools and libraries that are distributed free of charge:

1. Ant tool.
2. NSIS: a scriptable win32 installer/uninstaller system.
3. ProGuard: java shrinker, optimizer, and obfuscator.
4. Launch4j: Cross-platform Java executable wrapper for creating lightweight Windows native EXEs.
5. NSIS Ant task: to compile NSIS scripts.

The goal is to create a single build.xml file that will compile (JAVAC), obfuscate, shrink, optimize (ProGuard) our code, create an EXE file (Launch4j) and pack it all including other files (like license text file) to an installer package (NSIS).

The ant build file consists of a number of targets that can depend upon other targets in the same build file. That means before the target does something useful it will run the targets it depends upon:

Initialization Target

First, let’s define a number of properties:

XML:

  1. <property name="src" location="d:\myproggy\src" />
  2.     <property name="lib" location="lib" />
  3.     <property name="images" location="images" />
  4.     <property name="nsis" location="nsis" />
  5.     <property name="dist" location="dist" />
  6.     <property name="html" location="html" />
  7.     <property name="build" location="build" />
  8.     <property name="launch4j.dir" location="../.." />
  9.     <property name="original.dir" location="d:\myproggy" />

You may want to justify the paths according to your system.

The target init will depend upon target ‘clean’ – we want to clean everything before the build starts:

XML:

  1. <target name="clean" description="clean up">
  2.         <delete dir="${build}"/>
  3.         <delete dir="${html}"/>
  4.         <delete dir="${images}"/>
  5.         <delete dir="${lib}"/>
  6.         <delete dir="${dist}"/>
  7.     </target>

After it is over, the target ‘init’ will run.

XML:

  1. <target name="init" depends="clean">
  2.         <tstamp />
  3.         <mkdir dir="${build}" />
  4.         <mkdir dir="${html}" />
  5.         <mkdir dir="${images}" />
  6.         <mkdir dir="${lib}" />
  7.         <mkdir dir="${dist}" />
  8.        
  9.         <copy todir="${html}">
  10.             <fileset dir="${original.dir}/html/"/>
  11.         </copy>
  12.        
  13.         <copy todir="${images}">
  14.             <fileset dir="${original.dir}/images/"/>
  15.         </copy>  
  16.  
  17.         <copy todir="${lib}">
  18.             <fileset dir="${original.dir}/lib"/>
  19.         </copy>  
  20.        
  21.     </target>

We create a number of folders, copy source code, libraries, html, and image files.

Compile Target

XML:

  1. <target name="compile" depends="init" description="compile the source">
  2.         <javac srcdir="${src}" destdir="${build}" classpathref="dist.classpath" source="1.5" debug="on" />
  3.        
  4.           <copy todir="${build}">
  5.             <fileset dir="${src}">
  6.               <include name="*.vm"/>
  7.               <include name="*.properties"/>
  8.             </fileset>
  9.           </copy>      
  10.           
  11.     </target>

Compile the classes and copy the required files, such as Velocity templates and property files to the folder with the freshly compiled classes.

JAR Target

Next step is to create a JAR file and feed it to ProGuard that will “obfuscate, shrink, optimize” our code. ProGuard task has a number of limitations and requirements, so while my example is pretty clear you may want to read the ProGuard documentation. In a few words you name the libraries that are used by your application, specify you jar file name, and the name of the jar that will be the result of ProGuard’s work. ProGuard modifies the names of classes, so you need to keep the name of your Main-Class untouched. Anyway, consult the docs or you may run into some issues here.

XML:

  1. <target name="jar" depends="compile" description="create the jar">
  2.    
  3.         <fileset dir="${lib}" id="lib.dist.fileset">
  4.             <include name="**/*.jar" />
  5.         </fileset>
  6.        
  7.         <pathconvert pathsep=" " property="dist.classpath" refid="lib.dist.fileset">
  8.             <map from="${lib}" to=".\lib" />
  9.         </pathconvert>
  10.        
  11.         <!-- Put everything in ${build} into a jar file -->
  12.         <jar jarfile="${ant.project.name}.jar">
  13.             <fileset dir="${build}" includes="**/*" />
  14.             <manifest>
  15.                 <!-- SET YOUR MAIN CLASS HERE -->
  16.                 <attribute name="Main-Class" value="com.javazing.MyProggyLauncher" />
  17.                 <attribute name="Class-Path" value=". ${dist.classpath}" />
  18.             </manifest>
  19.         </jar>
  20.        
  21.         <!-- obfuscate and optimize by ProGuard -->
  22.         <taskdef resource="proguard/ant/task.properties" classpath="${launch4j.dir}/lib/proguard.jar" />
  23.         <proguard>
  24.        
  25.             -libraryjars jre/lib/rt.jar
  26.             -libraryjars lib/commons-collections-3.1.jar
  27.             -libraryjars lib/commons-io-1.2.jar
  28.             -libraryjars lib/commons-lang-2.1.jar
  29.             -libraryjars lib/commons-logging.jar
  30.             -libraryjars lib/hsqldb.jar
  31.             -libraryjars lib/jdom-1.0.jar
  32.             -libraryjars lib/log4j.jar
  33.             -libraryjars lib/lucene-core-1.9.1.jar
  34.             -libraryjars lib/org.eclipse.core.commands_3.2.0.I20060511-0800a.jar
  35.             -libraryjars lib/org.eclipse.equinox.common_3.2.0.v20060512.jar
  36.             -libraryjars lib/org.eclipse.jface.text_3.2.0.v20060518-0800.jar
  37.             -libraryjars lib/org.eclipse.jface_3.2.0.I20060511-0800a.jar
  38.             -libraryjars lib/org.eclipse.osgi_3.2.0.v20060510.jar
  39.             -libraryjars lib/org.eclipse.swt.win32.win32.x86_3.2.0.v3224.jar
  40.             -libraryjars lib/org.eclipse.text_3.2.0.v20060518-0800.jar
  41.             -libraryjars lib/rome-0.8.jar
  42.             -libraryjars lib/velocity-1.4.jar         
  43.            
  44.             -injars      ${ant.project.name}.jar
  45.             -outjars     obfuscated_${ant.project.name}.jar
  46.  
  47.             -keepclasseswithmembers public class * {
  48.             public static void main(java.lang.String[]);
  49.             }
  50.  
  51.             -dontskipnonpubliclibraryclasses
  52.  
  53.             -keep public class com.javazing.MyProggyLauncher
  54.            
  55.             -keep class * implements java.sql.Driver
  56.            
  57.            
  58.         </proguard>
  59.        
  60.     </target>

EXE Target

After the JAR target, we have a jar file that needs to be wrapped to become a native Windows executable file. We use Launch4j tool here. Launch4j needs an xml file with the settings:

proggy.xml file:

XML:

  1. <launch4jConfig>
  2.   <dontWrapJar>false</dontWrapJar>
  3.   <headerType>0</headerType>
  4.   <jar>..\obfuscated_my_cool_proggy.jar</jar>
  5.   <outfile>..\my_cool_proggy.exe</outfile>
  6.   <errTitle>MyProggy</errTitle>
  7.   <jarArgs></jarArgs>
  8.   <chdir>.</chdir>
  9.   <customProcName>false</customProcName>
  10.   <stayAlive>false</stayAlive>
  11.   <icon>proggy.ico</icon>
  12.   <jre>
  13.     <path>jre</path>
  14.     <minVersion>1.5.0</minVersion>
  15.     <maxVersion></maxVersion>
  16.     <initialHeapSize>0</initialHeapSize>
  17.     <maxHeapSize>0</maxHeapSize>
  18.     <args></args>
  19.   </jre>
  20.   <splash>
  21.     <file>proggy.bmp</file>
  22.     <waitForWindow>true</waitForWindow>
  23.     <timeout>60</timeout>
  24.     <timeoutErr>true</timeoutErr>
  25.   </splash>
  26. </launch4jConfig>

You may want to get an ICO & BMP images for your application. The icon file is the image to be rendered at the left top corner of every Windows application. The BMP file will be displayed as a splash file when the proggy starts. Java 1.6 has built-in splash functionality, so you may want to use it along with some nice PNG image with shadows and other alpha tricks, and not the Launch4J’s ugly bmp file.

XML:

  1. <target name="exe" depends="jar">
  2.         <taskdef name="launch4j" classname="net.sf.launch4j.ant.Launch4jTask" classpath="${launch4j.dir}/launch4j.jar
  3.             :${launch4j.dir}/lib/xstream.jar" />
  4.         <launch4j configFile="./l4j/proggy.xml" />
  5.        
  6.     </target>

Distibution Target

NSIS comes with a number of templates, samples, some nice graphics and GUI application. Therefore, you will definitely want to see its samples. my_proggy.nsi is the name of the script that will guide you installation and deinstallation processes: create folders, copy files, create menu group, create desktop icons etc.

Sample NSIS script:

NSIS:

  1. !include "MUI.nsh"
  2.  
  3.   !define MUI_ICON "proggy.ico"
  4.   !define MUI_UNICON "proggy.ico"
  5.  
  6. Function .onInit
  7.     # the plugins dir is automatically deleted when the installer exits
  8.     InitPluginsDir
  9.     File /oname=$PLUGINSDIR\splash.bmp "D:\myproggy\splash.bmp"
  10.     #optional
  11.     #File /oname=$PLUGINSDIR\splash.wav "C:\myprog\sound.wav"
  12.  
  13.     splash::show 1000 $PLUGINSDIR\splash
  14.  
  15.     Pop $0 ; $0 has '1' if the user closed the splash screen early,
  16.             ; '0' if everything closed normally, and '-1' if some error occurred.
  17. FunctionEnd
  18.  
  19.  
  20. ;--------------------------------
  21. ;General
  22.  
  23.   ;Name and file
  24.   Name "${PRODUCT_NAME}"
  25.   OutFile "${EXE_NAME}"
  26.  
  27.   ;Default installation folder
  28.   InstallDir "$PROGRAMFILES\${PRODUCT_NAME}"
  29.  
  30.   ;Get installation folder from registry if available
  31.   InstallDirRegKey HKCU "Software\${PRODUCT_NAME}" ""
  32.  
  33. ;--------------------------------
  34. ;Interface Configuration
  35.  
  36.   !define MUI_HEADERIMAGE
  37.   !define MUI_HEADERIMAGE_BITMAP "proggy_header.bmp" ; optional
  38.  
  39. ;--------------------------------
  40. ;Variables
  41.  
  42.   Var MUI_TEMP
  43.   Var STARTMENU_FOLDER
  44.  
  45. ;--------------------------------
  46. ;Interface Settings
  47.  
  48.   !define MUI_ABORTWARNING
  49.  
  50. ;--------------------------------
  51. ;Pages
  52.  
  53.   !insertmacro MUI_PAGE_LICENSE "license.rtf"
  54.   !insertmacro MUI_PAGE_DIRECTORY
  55.  
  56.   ;Start Menu Folder Page Configuration
  57.   !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU"
  58.   !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\${PRODUCT_NAME}"
  59.   !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
  60.   !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
  61.   !insertmacro MUI_PAGE_INSTFILES
  62.   !insertmacro MUI_UNPAGE_CONFIRM
  63.   !insertmacro MUI_UNPAGE_INSTFILES
  64.  
  65. ;--------------------------------
  66. ;Languages
  67.  
  68.   !insertmacro MUI_LANGUAGE "English"
  69.