PrologEngine.java

00001 /* 
00002 ** Author(s): Miguel Calejo
00003 ** Contact:   interprolog@declarativa.com, http://www.declarativa.com
00004 ** Copyright (C) Declarativa, Portugal, 2000-2002
00005 ** Use and distribution, without any warranties, under the terms of the 
00006 ** GNU Library General Public License, readable in http://www.fsf.org/copyleft/lgpl.html
00007 */
00008 
00009 package com.declarativa.interprolog;
00010 import com.declarativa.interprolog.util.*;
00011 import java.io.*;
00012 import java.net.*;
00013 import java.util.Vector;
00014 import java.lang.reflect.*;
00015 
00019 public abstract class PrologEngine{
00020     protected static int numberOfInstances = 0;
00022     public final static String version = "2.0b1";
00024     public String startPrologCommand;
00025     protected long startTime;
00027     public final static String nl = System.getProperty("line.separator");
00029     protected File tempDirectory; 
00030     
00032     protected ObjectRegistry knownObjects;
00033     protected boolean shutingDown = false;
00035     public boolean interrupting = false;
00036     protected boolean debug=false;
00037     protected boolean topGoalHasStarted=false;
00039     protected int goalTimestamp;
00040     
00042     Vector goalsToExecute;
00044     Vector messagesExecuting;
00045     
00047         final Method getRealJavaObjectMethod;
00049         public final String firstJavaMessageName = "firstJavaMessage";
00051         /* unfortunately it is pointless to intercept writeInt
00052         in ObjectOutputStream, because (1) the method is onvoked in several situations, not just to serialize
00053         int values, and (2) some classes may serialize in very weird ways; so in general it is not possible 
00054         to detect int values beyond these boundaries */
00055         public static final int MAX_INT_VALUE = 134217727;
00057         public static final int MIN_INT_VALUE = -134217728;
00058 
00063         public PrologEngine(String startPrologCommand, boolean debug){      
00064                 startTime= System.currentTimeMillis();
00065                 if (startPrologCommand==null) 
00066                         throw new IPException("PrologEngine with null startPrologCommand");
00067                 setDebug(debug);
00068                 this.startPrologCommand = startPrologCommand;
00069                 numberOfInstances++;
00070                 makeTempDirectory();
00071                 knownObjects = new ObjectRegistry();
00072                 goalsToExecute = new Vector();
00073                 messagesExecuting = new Vector();
00074 
00075         try{ getRealJavaObjectMethod = findMethod (getClass(),"getRealJavaObject",new Class[]{Object.class});} 
00076         catch(Exception ex){throw new IPException("could not find special getRealJavaObject method:"+ex);}
00077         }
00078                 
00080         public abstract void shutdown();
00081 
00083         protected boolean isShutingDown(){
00084                 return false;
00085         }
00086         
00087         void makeTempDirectory(){
00088                 if (tempDirectory!=null)
00089                     throw new IPException("Inconsistency in makeTempDirectory");
00090                 try{
00091                         File dummyFile = File.createTempFile("IP_","");
00092                         if (!dummyFile.delete())
00093                             throw new IPException("Could not delete dummy file");
00094                         tempDirectory = new File(dummyFile.getAbsolutePath());
00095                         if (!tempDirectory.mkdir())
00096                             throw new IPException("Could not create temporary directory");
00097                         tempDirectory.deleteOnExit();
00098                 } catch (IOException e){
00099                         throw new IPException("Problems creating temporary directory:"+e);
00100                 }
00101         }
00102         
00104         public File getJarDirectory(){
00105                 return getJarDirectory(getClass());
00106         }
00107         
00109         public static File getJarDirectory(Class aClass){
00110             String classPath=aClass.getName().replace('.','/') + ".class";
00111                 URL u = aClass.getClassLoader().getResource(classPath);
00112                 if (!u.getProtocol().equals("jar")) return null;
00113                 String s = u.getFile();
00114             if (!s.startsWith("file:/"))
00115                 throw new IPException("Jar file is not in the local file system");
00116                 int end = s.indexOf("!");
00117                 if (end==-1) throw new IPException("Bad jar URL");
00118             // MK changed 6 to 5!!!
00119             String path = s.substring(5,end);
00120             if (!path.endsWith(".jar"))
00121                 throw new IPException("Jar file name does not end with .jar");
00122                 path=path.replace('/',File.separatorChar);
00123                 return new File(path).getParentFile();
00124         }
00125         
00126         File copyToTemp(String filename,Object requester){
00127                 File tempFile = null;
00128                 Class rc;
00129                 if (requester instanceof Class) rc = (Class)requester;
00130                 else rc = requester.getClass();
00131                 // rc.getPackage() null when using JUnit's class loader...
00132                 // String packageName = rc.getPackage().getName();
00133                 String className = rc.getName();
00134                 String packageName = className.substring(0,className.lastIndexOf('.'));
00135                 String path = packageName.replace('.','/' /*File.separatorChar*/);
00136 
00137                 if (filename.indexOf('.')==-1) throw new IPException("File name missing extension");
00138                 String suffix = filename.substring(filename.lastIndexOf('.'));
00139                 String rootName = filename.substring(0,filename.lastIndexOf('.'));
00140                 try {
00141                                     
00142                     String resourceName = path+/*File.separatorChar*/'/'+filename;
00143                     InputStream resourceStream =
00144                         rc.getClassLoader().getResourceAsStream(resourceName);
00145                     if (resourceStream==null) throw new IPException("Resource not found");
00146                     
00147                     //tempFile = File.createTempFile("IP_",suffix /*,directory*/);
00148                         tempFile = new File(tempDirectory,filename);
00149                         tempFile.deleteOnExit();
00150                         
00151                         FileOutputStream fos = new FileOutputStream(tempFile);
00152                         byte[] buffer = new byte[512]; int len;
00153                         while ((len = resourceStream.read(buffer, 0, buffer.length)) != -1) 
00154                             fos.write(buffer, 0, len);
00155                         fos.close(); resourceStream.close();
00156                 } catch (IOException e){
00157                     throw new IPException("I/O problem obtaining "+filename+": "+e);
00158                 }
00159                 return tempFile;
00160         }
00161         
00173         public void consultFromPackage(String filename,Object requester){
00174                 if (filename.indexOf('.')==-1) filename=filename+".P";
00175                 String path = copyToTemp(filename,requester).getPath();
00176                 progressMessage("consultFromPackage:"+path);
00177                 
00178                 if (!command("reconsult('"+path+"')"))
00179                 throw new IPException("Problem consulting from package archive");
00180         }
00181         
00187         public void consultRelative(String filename,Object requester){
00188                 operationRelative("reconsult", filename, requester);
00189         }
00190         
00191         public void load_dynRelative(String filename,Object requester){
00192                 operationRelative("load_dyn", filename, requester);
00193         }
00194         
00195         protected void operationRelative(String operation,String filename,Object requester){
00196                 Class rc;
00197                 if (requester instanceof Class) rc = (Class)requester;
00198                 else rc = requester.getClass();
00199                 String path = rc.getPackage().getName().replace('.',File.separatorChar);
00200                 path=getJarDirectory().getPath()+File.separatorChar+path; 
00201                 // make this insensitive to Prolog's current directory
00202                 //if (filename.indexOf('.')==-1) filename=filename+".P";
00203                 filename = path+File.separatorChar+filename;
00204                 String g = "((library_directory('"+path+"')->true;assert(library_directory('"+path+"'))), "+
00205                         operation+"('"+filename+"'))";
00206                 if (!command(g))
00207                 throw new IPException("Problem in operationRelative");
00208         }
00209                         
00210 
00211         
00214         public void interrupt(){
00215             interrupting = true;
00216             doInterrupt();
00217             waitUntilIdle();
00218             interrupting = false;
00219         }
00220         
00221         protected abstract void doInterrupt();
00222         
00224     public boolean command(String s){
00225         if (topGoalHasStarted) return deterministicGoal(s);
00226         else return realCommand(s);
00227     }
00228         
00231         protected abstract boolean realCommand(String s);
00232         
00234         public void progressMessage(String s){
00235                 if (debug) System.out.println(System.currentTimeMillis()-startTime+ "ms: "+s);
00236         }
00237 
00240         public boolean isDebug(){ return debug;}
00241         
00242         public void setDebug(boolean d){debug=d;}
00243         
00245         public static void printBindings(Object[] b){
00246                 if (b==null) System.out.println("Empty bindings");
00247                 else 
00248                         for (int i=0;i<b.length;i++) System.out.println("Binding "+i+":"+b[i]);
00249         }
00250                 
00251         protected final void teachIPobjects(ObjectOutputStream obs) throws IOException{
00252                 Object [] oa1 = {new Integer(13)};
00253                 obs.writeObject(
00254                         new ObjectExamplePair(
00255                                 "GoalFromJava",
00256                                 new GoalFromJava(1,"a","aa",new Object[0],"A"),
00257                                 new GoalFromJava(2,"b","bb",oa1,"B")
00258                         )); 
00259                 obs.writeObject(
00260                         new ObjectExamplePair(
00261                                 "ResultFromProlog",
00262                                 new ResultFromProlog(1,true,0,null),
00263                                 new ResultFromProlog(2,false,1,"some error")
00264                         )); 
00265                 MessageFromProlog mpA = new MessageFromProlog();
00266                 mpA.methodName="methodA";
00267                 mpA.arguments=new Object[0];
00268                 mpA.returnArguments=true;
00269                 MessageFromProlog mpB = new MessageFromProlog();
00270                 mpB.timestamp=2;
00271                 mpB.target = "target";
00272                 mpB.methodName="methodB";
00273                 mpB.arguments=new Object[1];
00274                 mpB.returnArguments=false;
00275                 obs.writeObject(
00276                         new ObjectExamplePair("MessageFromProlog",mpA,mpB)
00277                 ); 
00278                 /* crashed JRE 1.4 with new Exception():*/
00279                 obs.writeObject(
00280                         new ObjectExamplePair("ResultFromJava",
00281                                 new ResultFromJava(1,null,null,new Object[0]),
00282                                 new ResultFromJava(2,"result here","new Exception()...",new Object[1])
00283                         )
00284                 ); 
00285                 obs.writeObject(
00286                         new ObjectExamplePair("InvisibleObject",new InvisibleObject(1),new InvisibleObject(2))
00287                 ); 
00288                 obs.writeObject(
00289                         new ObjectExamplePair("IPClassObject",new IPClassObject("A"),new IPClassObject("B"))
00290                 ); 
00291                 obs.writeObject(
00292                         new ObjectExamplePair("IPClassVariable",
00293                                 new IPClassVariable("ClassA","VariableA"), new IPClassVariable("ClassB","VariableB")
00294                                 )
00295                 ); 
00296         }
00297 
00302         protected void teachBasicObjects(ObjectOutputStream obs) throws IOException{
00303                 obs.writeObject(
00304                         new ObjectExamplePair(
00305                                 "boolean",new BasicTypeWrapper(new Boolean(true)),new BasicTypeWrapper(new Boolean(false))
00306                         )); 
00307                 obs.writeObject(
00308                         new ObjectExamplePair(
00309                                 "byte",
00310                                 new BasicTypeWrapper(new Byte((new Integer(1)).byteValue())),
00311                                 new BasicTypeWrapper(new Byte((new Integer(2)).byteValue()))
00312                         )); 
00313                 obs.writeObject(
00314                         new ObjectExamplePair(
00315                                 "char",new BasicTypeWrapper(new Character('A')),new BasicTypeWrapper(new Character('B'))
00316                         )); 
00317                 obs.writeObject(
00318                         new ObjectExamplePair(
00319                                 "double",new BasicTypeWrapper(new Double(1)),new BasicTypeWrapper(new Double(2))
00320                         )); 
00321                 obs.writeObject(
00322                         new ObjectExamplePair(
00323                                 "float",new BasicTypeWrapper(new Float(1)),new BasicTypeWrapper(new Float(2))
00324                         )); 
00325                 obs.writeObject(
00326                         new ObjectExamplePair(
00327                                 "int",new BasicTypeWrapper(new Integer(1)),new BasicTypeWrapper(new Integer(2))
00328                         )); 
00329                 obs.writeObject(
00330                         new ObjectExamplePair(
00331                                 "long",new BasicTypeWrapper(new Long(1)),new BasicTypeWrapper(new Long(2))
00332                         )); 
00333                 obs.writeObject(
00334                         new ObjectExamplePair(
00335                                 "short",
00336                                 new BasicTypeWrapper(new Short( (new Integer(1)).shortValue() )),
00337                                 new BasicTypeWrapper(new Short( (new Integer(2)).shortValue() ))
00338                         )); 
00339                 obs.writeObject(new ObjectExamplePair(new Boolean(true),new Boolean(false)));
00340                 obs.writeObject(new ObjectExamplePair(new Integer(1),new Integer(2)));
00341                 obs.writeObject(new ObjectExamplePair(new Float(20.59375),new Float(2)));
00342                 obs.writeObject(TermModel.example());
00343                 obs.writeObject(VariableNode.example());
00344                 obs.writeObject(new ObjectExamplePair("ArrayOfTermModel",new TermModel[0],new TermModel[1]));
00345                 obs.writeObject(new ObjectExamplePair("ArrayOfString",new String[0]));
00346                 obs.writeObject(new ObjectExamplePair("ArrayOfObject",new Object[0]));
00347         }
00348 
00351         public boolean teachOneObject(Object example){
00352                 return teachMoreObjects(new Object[]{example});
00353         }
00354         
00357         public boolean teachMoreObjects(Object[] examples){
00358                 if (examples[0] instanceof ObjectExamplePair) 
00359                         throw new IPException("Bad method invocation in teachMoreObjects");
00360                 ObjectExamplePair[] pairs = new ObjectExamplePair[examples.length];
00361                 for (int i=0;i<pairs.length;i++)
00362                         pairs[i] = new ObjectExamplePair(examples[i]);
00363                 return teachMoreObjects(pairs);         
00364         }
00365         
00370         public boolean teachMoreObjects(ObjectExamplePair[] examples){
00371                 // simply call "dg" to teach examples...
00372                 Object[] temp = new Object[examples.length];
00373                 for (int i=0;i<examples.length;i++)
00374                         temp[i] = examples[i];
00375                 return deterministicGoal("ipProcessExamples(Examples)", "Examples", temp);
00376         }
00377         
00378         protected GoalFromJava makeDGoalObject(String G, String OVar, Object[] objectsP, String RVars,int timestamp){
00379                 // RVars can not be tested here, only at the Prolog side after the goal
00380         if (G==null)
00381             throw new IPException ("Null Goal in deterministicGoal");
00382         if (OVar==null)
00383             OVar="_";
00384         if (objectsP == null)
00385             objectsP = new Object[0];
00386         if (G.trim ().endsWith ("."))
00387             throw new IPException ("Goal argument should have no trailing '.', in deterministicGoal");
00388         return new GoalFromJava(timestamp,G,OVar,objectsP,RVars);
00389         }
00390         
00405         public Object[] deterministicGoal(String G, String OVar, Object[] objectsP, String RVars){
00406         //available=false;
00407                 int mytimestamp = incGoalTimestamp();
00408         GoalFromJava GO = makeDGoalObject(G, OVar, objectsP, RVars, mytimestamp);
00409         Object[] resultToReturn=null;
00410         try{
00411             progressMessage("Schedulling (in PrologEngine) goal "+G+", timestamp "+mytimestamp+" in thread "+Thread.currentThread().getName());
00412             GoalToExecute goalToDo = new GoalToExecute(GO);
00413             scheduleGoal(goalToDo);
00414             ResultFromProlog result = goalToDo.waitForResult();
00415             // goalToDo is forgotten by handleCallback
00416                        
00417             if (result==null) throw new IPException("Problems in goal result");
00418             if (goalToDo.wasAborted()) throw new IPAbortedException(G+" was aborted");
00419             if (goalToDo.wasInterrupted()) throw new IPInterruptedException(G+" was interrupted");
00420             if (result.error!=null) throw new IPException (result.error);
00421             if (result.timestamp!=mytimestamp)
00422                 throw new IPException ("bad timestamp in deterministicGoal, got "+result.timestamp+" instead of "+goalTimestamp);
00423             if (result.succeeded)
00424                 resultToReturn = result.rVars;
00425         } catch (IPException e) {
00426             throw e;
00427         } catch (Exception e) {
00428             throw new IPException ("Problem in deterministicGoal:"+e);
00429         }
00430         return resultToReturn;
00431     }
00432         
00434         public boolean deterministicGoal(String G){
00435                 return (deterministicGoal(G, null,null,"[]")!=null);
00436         }
00437         
00439         public Object[] deterministicGoal(String G,String RVars){        
00440                 return deterministicGoal(G,null,null,RVars);
00441         }
00442 
00444         public boolean deterministicGoal(String G, String OVar, Object[] objectsP){
00445                 return (deterministicGoal(G, OVar,objectsP,"[]")!=null);
00446         }
00447         
00448         // Increment the goal counter
00449         protected int incGoalTimestamp(){
00450                 goalTimestamp++; 
00451                 if (goalTimestamp<0) throw new IPException("goalTimestamp did wrap around, please improve it...");
00452                 return goalTimestamp;
00453         }
00454         
00456         protected synchronized void scheduleGoal(GoalToExecute g){
00457                 goalsToExecute.addElement(g);
00458         }       
00459         
00460         protected synchronized GoalToExecute moreRecentToExecute(){
00461                 for (int i=goalsToExecute.size()-1; i>=0; i--){
00462                         GoalToExecute gte = (GoalToExecute)goalsToExecute.elementAt(i);
00463                         if (!gte.hasStarted()) return gte;
00464                 }
00465                 return null;
00466         }
00467         
00470         protected synchronized GoalToExecute forgetGoal(int timestamp){
00471                 for (int i=0; i<goalsToExecute.size(); i++){
00472                         GoalToExecute gte = (GoalToExecute)goalsToExecute.elementAt(i);
00473                         if (gte.getTimestamp()==timestamp){
00474                                 goalsToExecute.removeElementAt(i);
00475                                 return gte;
00476                         }
00477                 }
00478                 return null;
00479         }
00480         
00482         protected synchronized void addMessage(MessageExecuting m){
00483                 messagesExecuting.addElement(m);
00484         }
00485         
00486         protected synchronized void forgetMessage(MessageExecuting m){
00487                 messagesExecuting.removeElement(m);
00488         }
00489         
00490         protected synchronized MessageExecuting lastMessageRequest(){
00491                 MessageExecuting last;
00492                 if (messagesExecuting.size()==0) last=null;
00493                 else last = (MessageExecuting)messagesExecuting.lastElement();
00494                 return last;
00495         }
00496         
00498         public synchronized boolean isIdle(){
00499                 return messagesExecuting.size()==0 && goalsToExecute.size()==0;
00500         }
00501         
00503         public synchronized void abortTasks(){
00504                 for (int i=0; i<goalsToExecute.size(); i++){
00505                         GoalToExecute gte = (GoalToExecute)goalsToExecute.elementAt(i);
00506                         gte.abort();
00507                 }
00508                 goalsToExecute.removeAllElements();
00509                 messagesExecuting.removeAllElements();
00510         }
00511         
00513         public synchronized void interruptTasks(){
00514                 for (int i=0; i<goalsToExecute.size(); i++){
00515                         GoalToExecute gte = (GoalToExecute)goalsToExecute.elementAt(i);
00516                         gte.interrupt();
00517                 }
00518                 goalsToExecute.removeAllElements();
00519                 messagesExecuting.removeAllElements();
00520         }
00521         
00523         public boolean isAvailable(){
00524                 return true;
00525         }
00526         
00527         public void waitUntilAvailable(){
00528                 try{
00529                         while(!isAvailable()) Thread.sleep(0,1);
00530                 } catch (InterruptedException e){
00531                         throw new IPException("Bad interrupt:"+e); 
00532                 }
00533         }
00534         
00536         public void waitUntilIdle(){
00537                 try{
00538                         while(!isIdle()) Thread.sleep(0,1);
00539                 } catch (InterruptedException e){
00540                         throw new IPException("Bad interrupt:"+e); 
00541                 }
00542         }
00543         
00546         public Object handleCallback(Object x){
00547                 progressMessage("Entering handleCallback");
00548                 if (x instanceof ClassNotFoundException) 
00549                         return new ResultFromJava(0,null,(ClassNotFoundException)x,null); 
00550                 else if (x instanceof MessageFromProlog){
00551                         MessageFromProlog mfp = (MessageFromProlog)x;
00552                         progressMessage("handling "+mfp);
00553                         // first message is a dummy just to get us here:
00554                         if (!isFirstJavaMessage(mfp)){
00555                                 MessageExecuting me = new MessageExecuting(mfp,this);
00556                                 me.start();
00557                                 addMessage(me);
00558                         } else progressMessage("received first (dummy) javaMessage");
00559                 } else if (x instanceof ResultFromProlog){
00560                         ResultFromProlog rfp = (ResultFromProlog)x;
00561                         progressMessage("handling "+rfp);
00562                         GoalToExecute gte = forgetGoal(rfp.timestamp);
00563                         progressMessage("forgot goal "+gte+"; isIdle()=="+isIdle());
00564                         if (gte==null) throw new IPException("Could not find goal "+rfp.timestamp);
00565                         gte.setResult(rfp);
00566                 } else throw new IPException("bad object in handleCallback:"+x);
00567                 // no errors so far
00568                 return doSomething();
00569         }
00571         protected Object doSomething(){
00572                 while(true){
00573                         // let some work proceed elsewhere; this seems light enough, if not use wait/notify around here too:
00574                         if (isIdle())
00575                                 try { Thread.sleep(0,100); }
00576                                 catch (InterruptedException e){throw new IPException("Bad interrupt");}
00577                         else Thread.yield();
00578                         MessageExecuting last = lastMessageRequest();
00579                         if (last!=null && last.hasEnded()) {
00580                                 forgetMessage(last);
00581                                 return last.getResult();
00582                         }
00583                         GoalToExecute gte = moreRecentToExecute();
00584                         if (gte!=null){
00585                                 gte.prologWasCalled();
00586                                 return gte.getGoal();
00587                         }
00588                 }
00589         }
00590         
00591         private boolean isFirstJavaMessage(MessageFromProlog mfp){
00592                 if (!mfp.methodName.equals(firstJavaMessageName)) return false;
00593                 if ((mfp.target instanceof InvisibleObject)&& getRealJavaObject((InvisibleObject)mfp.target)==this)
00594                         return true;
00595                 else return false;
00596         }
00597         
00599         public final void firstJavaMessage(){
00600                 throw new IPException("This should never be called, bad javaMessage handling");
00601         }
00602         
00604     public ResultFromJava doCallback(Object x){
00605         progressMessage ("Starting handling of XSB->Java callback:"+PrologEngine.nl+x);
00606         if (x==null | ! (x instanceof MessageFromProlog) )
00607             return new ResultFromJava (0,null,null,null);
00608         MessageFromProlog callback = (MessageFromProlog)x;
00609         Class formalArguments[] = new Class[callback.arguments.length];
00610         Object[] localArguments = new Object[callback.arguments.length];
00611         
00612         Object target=null;
00613         Object result = null; Exception exception=null;
00614         
00615         try {
00616             if (callback.target instanceof InvisibleObject){
00617                 target = getRealJavaObject ((InvisibleObject)callback.target);
00618             } else if(callback.target instanceof IPClassObject){
00619                 target = Class.forName (((IPClassObject)(callback.target)).classname);
00620             } else if (callback.target instanceof IPClassVariable) {
00621                 IPClassVariable tempTarget = (IPClassVariable)(callback.target);
00622                 Class tempClass = Class.forName (tempTarget.className);
00623                 target = tempClass.getField (tempTarget.variableName).get (tempClass);
00624             } else
00625                 target = callback.target;
00626             
00627             for(int a=0;a<formalArguments.length;a++){
00628                 localArguments[a] = callback.arguments[a];
00629                 if (localArguments[a]!=null){
00630                     if(localArguments[a] instanceof BasicTypeWrapper) {
00631                         BasicTypeWrapper btw = (BasicTypeWrapper)(localArguments[a]);
00632                         formalArguments[a] = btw.basicTypeClass ();
00633                         localArguments[a] = btw.wrapper; // Integer instead of int ???
00634                     } else if (localArguments[a] instanceof InvisibleObject) {
00635                         localArguments[a] = getRealJavaObject ((InvisibleObject)localArguments[a]);
00636                         formalArguments[a] = localArguments[a].getClass ();
00637                     } else if (localArguments[a] instanceof IPClassObject) {
00638                         localArguments[a] = Class.forName (((IPClassObject)(localArguments[a])).classname);
00639                         formalArguments[a] = Class.class;
00640                     } else if (localArguments[a] instanceof IPClassVariable) {
00641                         IPClassVariable IPCV = (IPClassVariable)(localArguments[a]);
00642                         Class tempClass = Class.forName (IPCV.className);
00643                         localArguments[a] = tempClass.getField (IPCV.variableName).get (null);
00644                         formalArguments[a] = localArguments[a].getClass ();
00645                     } else formalArguments[a] = localArguments[a].getClass ();
00646                 }
00647             }
00648             Method method=null;
00649             if (target instanceof Class){
00650                 if (shortClassName ((Class)target).equals (callback.methodName)) {
00651                     // It's a (public...) constructor invocation
00652                     //Constructor constructor = ((Class)target).getConstructor(formalArguments);
00653                     Constructor constructor = findConstructor ((Class)target,formalArguments);
00654                     result = constructor.newInstance (localArguments);
00655                 } else {
00656                     // It's a class (static) method invocation
00657                     // Method method = ((Class)target).getMethod(callback.methodName,formalArguments);
00658                     method = findMethod ((Class)target,callback.methodName,formalArguments);
00659                     //result = method.invoke(target,localArguments);
00660                     result = method.invoke (target,localArguments);
00661                 }
00662             } else {
00663                 // An instance method invocation
00664                 // Method method = target.getClass().getMethod(callback.methodName,formalArguments);
00665                 //result = findMethod(target.getClass(),callback.methodName,formalArguments).invoke(target,localArguments);
00666                 method = findMethod (target.getClass (),callback.methodName,formalArguments);
00667                 result = method.invoke (target,localArguments);
00668             }
00669             // The result will be an invisible object, except if a String or a wrapper or a TermModel...
00670             // ...or if this is a getRealJavaObject message sent to the PrologEngine
00671             if (result!=null && !(target==this && method.equals(getRealJavaObjectMethod)) && !(result instanceof InvisibleObject) 
00672             && !(result instanceof String) && !(result instanceof TermModel)
00673             && ! BasicTypeWrapper.instanceOfWrapper (result))
00674                 result = makeInvisible (result);
00675         } catch (Exception e) {
00676             exception=e;
00677         }
00678         if (exception!=null) {
00679             System.out.println ("Courtesy of CallbackHandler:");
00680             exception.printStackTrace ();
00681         }
00682         if (callback.returnArguments)
00683             return new ResultFromJava (callback.timestamp,result,exception,callback.arguments);
00684         else
00685             return new ResultFromJava (callback.timestamp,result,exception,null);
00686     }
00687 
00692     public static Method findMethod (Class targetClass,String name,Class[] formalArguments) throws NoSuchMethodException{
00693         Method m = null;
00694         try{
00695             m = targetClass.getMethod (name,formalArguments);
00696             return m;
00697         }
00698         catch(NoSuchMethodException e) {
00699             // Let's try to find "by hand" an acceptable method
00700             Method[] allMethods = targetClass.getMethods ();
00701             for (int i=0; i<allMethods.length;i++){
00702                 if (allMethods[i].getName ().equals (name) && allMethods[i].getParameterTypes ().length == formalArguments.length){
00703                     boolean compatible = true;
00704                     for (int j=0; j<formalArguments.length; j++) {
00705                         if (!assignableType (allMethods[i].getParameterTypes ()[j],formalArguments[j])) {
00706                             compatible = false;
00707                             break;
00708                         }
00709                     }
00710                     if (compatible){
00711                         m = allMethods[i];
00712                         break;
00713                     }
00714                 }
00715             }
00716             if (m==null) {
00717                 
00718                 System.err.println ("Could not find "+name+" in "+targetClass);
00719                 System.err.println ("Argument types:");
00720                 for (int i=0; i<formalArguments.length;i++)
00721                     System.out.println (i+":"+formalArguments[i]);
00722                 
00723                 throw e;
00724             }else return m;
00725         }
00726     }
00727     
00729     public static Constructor findConstructor (Class targetClass,Class[] formalArguments) throws NoSuchMethodException{
00730         Constructor m = null;
00731         try{
00732             m = targetClass.getConstructor (formalArguments);
00733             return m;
00734         }
00735         catch(NoSuchMethodException e) {
00736             // Let's try to find "by hand" an acceptable constructor
00737             Constructor[] allConstructors = targetClass.getConstructors ();
00738             for (int i=0; i<allConstructors.length;i++){
00739                 if (allConstructors[i].getParameterTypes ().length == formalArguments.length){
00740                     boolean compatible = true;
00741                     for (int j=0; j<formalArguments.length; j++) {
00742                         if (!assignableType (allConstructors[i].getParameterTypes ()[j],formalArguments[j])) {
00743                             compatible = false;
00744                             break;
00745                         }
00746                     }
00747                     if (compatible){
00748                         m = allConstructors[i];
00749                         break;
00750                     }
00751                 }
00752             }
00753             if (m==null) throw e;
00754             else return m;
00755         }
00756     }
00757     
00759     public static boolean assignableType (Class left,Class right){
00760         if (right==null) return true;
00761         else return left.isAssignableFrom (right);
00762     }
00763     
00764     public static String shortClassName (Class c){
00765         String s = c.getName ();
00766         int dot = s.lastIndexOf (".");
00767         int dollar = s.lastIndexOf ("$");
00768         if (dot==-1 && dollar==-1) return s;
00769         else return s.substring (Math.max (dot,dollar)+1,s.length ());
00770     }
00771 
00777         public int registerJavaObject(Object x){
00778                 return knownObjects.registerJavaObject(x);
00779         }
00780         
00787         public Object makeInvisible(Object x){
00788                 return new InvisibleObject(knownObjects.registerJavaObject(x));
00789         }
00790         
00796         public Object getRealJavaObject(InvisibleObject o){
00797                 return knownObjects.getRealJavaObject(o);
00798         }
00800         public Object getRealJavaObject(int ID){
00801                 return knownObjects.getRealJavaObject(ID);
00802         }
00803 
00810         public Object getRealJavaObject(Object o){
00811                 return o;
00812         }
00813 
00814 }
00815 
00816 
00817 
00818 
00819 
00820 
00821 

Generated on Wed Jul 26 13:30:44 2006 for XSB by  doxygen 1.4.5