### JESS-ON-ANDROID-HOWTO ### Author: Rossano Pablo Pinto (rossano at gmail dot com) ### Date: Tue Mar 27 16:06:17 BRT 2012 ### ### Description: ### Enable JESS on Android. ### The method used is the most lazy one: ### Put everything you need in the project you are developing! ### In other words, every new project that uses JESS owns all the ### needed JARS. ### Todo: ### Put JESS and all the dependencies in global usable classpath. ### ### WARNING: This HOW TO is not aimed at the WEAK!!! You really must ### know what your doing!!! ### This is for the BRAVE!!! ##################################################################### -2. Install Android SDK into /opt/android-sdk-linux/ -1. Create a directory (any directory) to organize this HUGE TASK: mkdir ~/port-to-android/ cd ~/port-to-android/ ============================================== ON A DEBIAN 6.0.7: ============================================== -------------------------------------------------------------------- 0. Install some libs and tools: sudo apt-get install subversion sudo apt-get install libjpeg62-dev sudo apt-get install liblcms1-dev sudo apt-get install libpng12-dev sudo apt-get install g++ sudo apt-get install libxrender-dev sudo apt-get install libxext-dev sudo apt-get install libxtst-dev sudo apt-get install libxft-dev -------------------------------------------------------------------- 1. DOWNLOAD APACHE HARMONY FILES and untar it: mkdir ~/port-to-android/ cd ~/port-to-android/ wget http://ftp.unicamp.br/pub/apache//harmony/milestones/5.0/M15/apache-harmony-5.0-src-r991518-snapshot.tar.gz -------------------------------------------------------------------- 2. cd to apache harmony directory and download some other files: cd ~/port-to-android/apache-harmony-5.0-src-r991518 wget http://zh.sourceforge.jp/projects/sfnet_freefoam/downloads/ThirdParty/zlib/zlib-1.2.5.tar.gz wget archive.apache.org/dist/xerces/j/Xerces-J-bin.2.10.0.zip wget http://archive.eclipse.org/eclipse/downloads/drops/R-3.5.1-200909170800/ecj-3.5.1.jar mv zlib-1.2.5.tar.gz classlib/depends/oss/zlib-1.2.5/ mv Xerces-J-bin.2.10.0.zip classlib/depends/jars/xerces_2.10.0/xerces.zip mv ecj-3.5.1.jar common_resources/depends/jars/ecj_3.5.1/ -------------------------------------------------------------------- 3. Make the Eclipse compiler class visible: cd /usr/share/ant/lib/ sudo ln -s common_resources/depends/jars/ecj_3.5.1/ecj-3.5.1.jar /usr/share/ant/lib/ecj-3.5.1.jar -------------------------------------------------------------------- 4.Ask ant to fetch some dependencies (and check if everything is ok): ant fetch-depends -------------------------------------------------------------------- 5. Before compiling, change the VM ClassLoader to avoid this error: I/dalvikvm( 617): Could not find method org.apache.harmony.kernel.vm.VM.bootCallerClassLoader, referenced from method org.apache.harmony.beans.internal.nls.Messages.setLocale W/dalvikvm( 617): VFY: unable to resolve static method 34373: Lorg/apache/harmony/kernel/vm/VM;.bootCallerClassLoader ()Ljava/lang/ClassLoader; So, let's correct this: Open file apache-harmony-5.0-src-r991518/classlib/modules/beans/src/main/java/org/apache/harmony/beans/internal/nls/Messages.java Change FROM: static public ResourceBundle setLocale(final Locale locale, final String resource) { try { final ClassLoader loader = VM.bootCallerClassLoader(); TO: static public ResourceBundle setLocale(final Locale locale, final String resource) { try { final ClassLoader loader = null; // VM.bootCallerClassLoader(); -------------------------------------------------------------------- 6. Build apache-harmony cd ~/port-to-android/apache-harmony-5.0-src-r991518/classlib ant build -------------------------------------------------------------------- 7. Create a project (used for this lazy porting method!!): /opt/android-sdk-linux/tools/android create project \ --target 1 \ --name MyAndroidTestApp \ --path ./MyAndroidTestAppProject \ --activity MyAndroidTestAppActivity \ --package rpp.android -------------------------------------------------------------------- 8. Put all the necessary JARS to make JESS work in Android into your project libs dir. The jars are: accessibility.jar applet.jar awt.jar beans.jar jess.jar swing.jar. The jess.jar must be obtained from SANDIA (Get it from them...!!!). All the other jars were generated from the apache harmony compilation as described before. sudo cp ~/port-to-android/apache-harmony-5.0-src-r991518/classlib/deploy/jdk/jre/lib/boot/beans.jar ~/port-to-android/android-project/MyAndroidTestAppProject/libs/ sudo cp ~/port-to-android/apache-harmony-5.0-src-r991518/classlib/deploy/jdk/jre/lib/boot/applet.jar ~/port-to-android/android-project/MyAndroidTestAppProject/libs/ sudo cp ~/port-to-android/apache-harmony-5.0-src-r991518/classlib/deploy/jdk/jre/lib/boot/awt.jar ~/port-to-android/android-project/MyAndroidTestAppProject/libs/ sudo cp ~/port-to-android/apache-harmony-5.0-src-r991518/classlib/deploy/jdk/jre/lib/boot/swing.jar ~/port-to-android/android-project/MyAndroidTestAppProject/libs/ sudo cp ~/port-to-android/apache-harmony-5.0-src-r991518/classlib/deploy/jdk/jre/lib/boot/accessibility.jar ~/port-to-android/android-project/MyAndroidTestAppProject/libs/ -------------------------------------------------------------------- 9. Some libs are considered core-libraries. So enable dx command to work with this: Edit /opt/android-sdk-linux/platform-tools/dx and change the last line from: exec java $javaOpts -jar "$jarpath" "$@" to: exec java $javaOpts -jar "$jarpath" --core-library "$@" -------------------------------------------------------------------- 10. Now, let's use shadow facts in JESS: -------------------------------------------------------------------- 10.1. Create the file PChangeInterface.java like this (I actually copied it from my framework ACORD-CS - it was originally from package acords.core) and put it into ~/port-to-android/android-project/MyAndroidTestAppProject/src/rpp/android/: package rpp.android; import java.beans.PropertyChangeListener; public interface PChangeInterface { // Jess register interest in some attributes public abstract void addPropertyChangeListener(PropertyChangeListener p); // Jess unregister interest in some attributes public abstract void removePropertyChangeListener(PropertyChangeListener p); } -------------------------------------------------------------------- 10.2 Write a code like this and put it into ~/port-to-android/android-project/MyAndroidTestAppProject/src/rpp/android/: package rpp.android; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; import jess.*; import java.io.*; // Used for JESS SHADOW FACT import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; // implements PChangeInterface - Used for JESS SHADOW FACT public class MyAndroidTestAppActivity extends Activity implements PChangeInterface { // Used for JESS SHADOW FACT protected PropertyChangeSupport pcs = new PropertyChangeSupport(this); TextView tvo = null; // Used for JESS SHADOW FACT public void addPropertyChangeListener(PropertyChangeListener p) { pcs.addPropertyChangeListener(p); } public void removePropertyChangeListener(PropertyChangeListener p) { pcs.removePropertyChangeListener(p); } public void setDisplayText(String text) { tvo.setText(text); } /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); tvo = tv; tv.setText("Hello, Android hehehehe ! ! ! xxxxx"); setContentView(tv); // JESS ON ANDROID !!!! Rete engine = new Rete(); try { byte[] initialfilebytes = new byte[8192]; new BufferedInputStream(this.getResources().openRawResource(R.raw.initialfacts)).read(initialfilebytes,0,8192); String initial_string = new String(initialfilebytes); engine.executeCommand(initial_string); // INSERT THIS AS A SHADOW FACT INTO JESS engine.defclass("rpp.android.MyAndroidTestAppActivity","rpp.android.MyAndroidTestAppActivity",null); engine.definstance("rpp.android.MyAndroidTestAppActivity", this, true); // true means dynamic shadow fact byte[] antfilebytes = new byte[8192]; new BufferedInputStream(this.getResources().openRawResource(R.raw.ant)).read(antfilebytes,0,8192); String ant_string = new String(antfilebytes); engine.executeCommand(ant_string); } catch (Exception e) { e.printStackTrace(); } } } -------------------------------------------------------------------- 11 Create jess files and put it into ~/port-to-android/android-project/MyAndroidTestAppProject/res/raw -------------------------------------------------------------------- 11.1 Create the file initialfacts.jess: ;;;;;;; ; clears EVERETHING (clear) ;; SOME JESS CONFIGURATIONS ;; BEGIN JESS Conf ; don't reset globals to original values (set-reset-globals nil) ;; END JESS Conf ; put working memory into a known state (reset) (watch facts) ;(watch activations) (printout t "DEBUG: JESS INITIALIZED" crlf) ;; RPP ;; JAVA/ANDROID STUFF import android.widget.TextView; (defclass android.widget.TextView android.widget.TextView) -------------------------------------------------------------------- 11.2 Create the file ant.jess: ;; Salient Ant Simulator ;; by Jason Morris ;; Modified by Rossano Pablo Pinto - rossano at dca fee unicamp br ;;(clear) (watch all) (printout t "DEBUG: ANT SCRIPT" crlf) (printout t " ======= Rossano Pablo Pinto =====" crlf) ;; RPP ;; JAVA/ANDROID STUFF ;;import android.widget.TextView; ;;(defclass android.widget.TextView android.widget.TextView) import rpp.android.*; ;; An ant's priorities (defglobal ?*threat* = 10000) (defglobal ?*survival* = 100) (defglobal ?*chore* = -10) ;; Effect of nature (defglobal ?*nature* = 0) ;; Useful variables (defglobal ?*max* = 65536) (defglobal ?*enemy-total* = 0) (defglobal ?*survival-probability* = 0.5) (defglobal ?*survival-limit* = 0.75) (deffunction sendmsg (?msg) ((?*hello* getSlotValue OBJECT) setDisplayText ?msg)) ;; Next, let's give our ant some behaviors (deffunction gather-food (?food) (retract ?food) (printout t "Food item gathered OK" crlf) (sendmsg "Food item gathered OK")) (deffunction take-out-garbage (?item) (retract ?item) (printout t "Garbage emptied OK" crlf) (sendmsg "Garbage emptied OK")) ;; If he gets killed, then see if he was a hero to the colony (deffunction check-hero-ant() (if (>= ?*enemy-total* 5) then (printout t "This ant was a hero! It killed " ?*enemy-total* " enemies!" crlf) (bind ?s (str-cat "This ant was a hero! It killed " ?*enemy-total* " enemies!") (sendmsg ?s)))) (deffunction attack-ant (?ant) (printout t "Attacking enemy ant..." crlf) (bind ?survival-ratio (/ (random) ?*max*)) (if (>= ?*survival-probability* ?survival-ratio) then (printout t "Enemy ant killed :-D" crlf) (sendmsg "Enemy ant killed :-D") ;; Give credit for surviving (bind ?*enemy-total* (+ ?*enemy-total* 1)) ;; Account for increased experience up to a point (if (< ?*survival-probability* ?*survival-limit*) then (bind ?*survival-probability* (+ ?*survival-probability* 0.05))) (retract ?ant) else (printout t "Ant killed by enemy :-(" crlf) (sendmsg "Ant killed by enemy :-(") (check-hero-ant) (halt))) ;; Have nature disturb the environment in a few ways (deffunction change-ant-environment() (if (>= (/ (random) ?*max*) 0.25) then (assert (food-source (gensym*)))) (if (>= (/ (random) ?*max*) 0.9) then (assert (enemy-ant (gensym*))))) ;; We'll give a 50% chance of a predator appearing (deffunction get-predator() (if (>= (/ (random) ?*max*) 0.5) then (assert (predator (gensym*)))) (printout t "A predator has appeared!" crlf) (sendmsg "A predator has appeared!") ;; Unfortunately, predators stir up food items, so (assert (food-source (gensym*)))) ;; We'll give a 50% chance of existing predator leaving (deffunction remove-predator(?predator) (if (>= (/ (random) ?*max*) 0.5) then (retract ?predator) (printout t "Predator has gone away." crlf)) (sendmsg "Predator has gone away.")) ;; And 75% chance of being eaten (deffunction is-ant-eaten() (if (>= (/ (random) ?*max*) 0.25) then (printout t "Arrg! Ant got eaten!" crlf) (halt) else (printout t "Ant avoided predator OK" crlf))) ;; A header (deffunction print-banner() (printout t "Salient Ant Simulator" crlf) (printout t "---------------------" crlf)) ;; Now we define what causes those behaviors to happen. ;; We can hypothesize that everything the ant does ;; influences its environment in some way. (defrule attack-enemy-ant (declare (salience ?*threat*)) ?ant <-(enemy-ant ?) => (change-ant-environment) (attack-ant ?ant)) (defrule gather-food (declare (salience ?*survival*)) ?food <- (food-source ?) => (change-ant-environment) (gather-food ?food)) (defrule take-out-garbage (declare (salience ?*chore*)) ?item <-(garbage-source ?) => (change-ant-environment) (take-out-garbage ?item)) (defrule food-attracts-ants (declare (salience ?*nature*)) (exists (food-source ?)) => (assert(ant (gensym*)))) (defrule ant-attracts-other-ants (declare (salience ?*nature*)) (exists (ant ?)) => ; twice as many (assert(enemy-ant (gensym*))) (assert(ant (gensym*))) (assert(ant (gensym*)))) (defrule add-a-predator (declare (salience ?*nature*)) (not (predator ?)) => (get-predator)) (defrule remove-a-predator (declare (salience ?*nature*)) ?p<- (predator ?) => (remove-predator ?p)) (defrule ant-got-eaten (declare (salience ?*nature*)) (predator ?) => (is-ant-eaten)) (defrule nothing-to-do (declare (salience ?*nature*)) (not (food-source ?)) ; Nothing to eat (not (garbage-source ?)) ; Nothing to clean (not (enemy-ant ?)) ; Nothing to fight ;;?tv <- (TextView) ?tv <- (rpp.android.MyAndroidTestAppActivity) => (printout t "Ant survived simulation!" crlf) ((?tv getSlotValue OBJECT) setDisplayText "Ant survived simulation!") (halt)) (defrule hello ?hello <- (rpp.android.MyAndroidTestAppActivity) => (printout t "CALLING SHADOW FACT METHOD!" crlf) ((?hello getSlotValue OBJECT) setDisplayText "CALLING FROM JESS!") ) ;; Finally, let's give the ant some things to do (deffacts ant-environment (food-source 1) (garbage-source 1) (food-source 2) (garbage-source 2) (food-source 3) (food-source 4) (food-source 5) ) ;; Run our little ant world (reset) (print-banner) (run-until-halt) -------------------------------------------------------------------- 12. run the ant tool: cd ~/port-to-android/android-project/MyAndroidTestAppProject/ ant debug install Voilá. You can see the app installed into the Android Emulator. Just click that to run the App. -------------------------------------------------------------------- 13. ENABLING SCROLLING Put these atributes into ~/port-to-android/android-project/MyAndroidTestAppProject/res/layout/main.xml: android:maxLines = "500" android:scrollbars = "vertical" It was like this: ... ... Make it like this: -------------------------------------------------------------------- 13. Change your code to put this line: ... import android.text.method.ScrollingMovementMethod; ... ... tv.setMovementMethod(new ScrollingMovementMethod()); ... It was like this: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //RPP TextView tv = new TextView(this); tvo = tv; Make it like this: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //RPP TextView tv = new TextView(this); tv.setMovementMethod(new ScrollingMovementMethod()); tvo = tv; .... Compile and install A feedback would be nice !!!