source: trunk/modelicaml/org.openmodelica.modelicaml.simulation/src/org/modelica/OMCProxy.java @ 947

Last change on this file since 947 was 947, checked in by wschamai, 13 years ago
File size: 22.8 KB
Line 
1/*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL).
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
13 * OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
14 *
15 * The OpenModelica software and the Open Source Modelica
16 * Consortium (OSMC) Public License (OSMC-PL) are obtained
17 * from OSMC, either from the above address,
18 * from the URLs: http://www.ida.liu.se/projects/OpenModelica or 
19 * http://www.openmodelica.org, and in the OpenModelica distribution.
20 * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html.
21 *
22 * This program is distributed WITHOUT ANY WARRANTY; without
23 * even the implied warranty of  MERCHANTABILITY or FITNESS
24 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
25 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
26 *
27 * See the full OSMC Public License conditions for more details.
28 *
29 * Main author: Wladimir Schamai, EADS Innovation Works / Linköping University, 2009-now
30 *
31 * Contributors:
32 *   Uwe Pohlmann, University of Paderborn 2009-2010, contribution to the Modelica code generation for state machine behavior, contribution to Papyrus GUI adoptations
33 *   Parham Vasaiely, EADS Innovation Works / Hamburg University of Applied Sciences 2009-2011, implementation of simulation plugins
34 */
35
36package org.modelica;
37
38import java.io.BufferedReader;
39import java.io.File;
40import java.io.FileReader;
41import java.io.IOException;
42import java.util.StringTokenizer;
43
44import org.omg.CORBA.ORB;
45
46// TODO: Auto-generated Javadoc
47/**
48 * The OMCProxy is the glue between the OpenModelica Compiler and MDT.
49 * It uses the interactive API of OMC to get information about classes
50 * and to load classes into OMC.
51 *
52 * @author Andreas Remar
53 * @author Adrian Pop
54 */
55public class OMCProxy 
56{
57   
58    /* the CORBA object */
59    /** The omcc. */
60    private static OmcCommunication omcc;
61   
62    /** The corba session name. */
63    private static String corbaSessionName = "ECLIPSE";
64       
65    /**
66     * The Enum osType.
67     */
68    enum osType { /** The WINDOWS. */
69 WINDOWS, /** The UNIX. */
70 UNIX };
71   
72    /* what Operating System we're running on */
73    /** The os. */
74    private static osType os;
75   
76    /* indicates if we've setup the communication with OMC */
77    /** The has initialized. */
78    private static boolean hasInitialized = false;
79   
80    /* indicates if the Modelica System Library has been loaded */
81    /** The system library loaded. */
82    private boolean systemLibraryLoaded = false;
83
84    /** The standard library packages. */
85    private String[] standardLibraryPackages = { "Modelica" };
86
87    /* debug options  */
88    /* should we trace the calls to sendExpression? */
89    /** The trace omc calls. */
90    private static boolean traceOMCCalls = true;
91   
92    /** The trace omc status. */
93    private static boolean traceOMCStatus = true;
94
95    /** The existing corba file is new. */
96    private static boolean existingCorbaFileIsNew = false;
97   
98    /**
99     * Instantiates a new oMC proxy.
100     */
101    public OMCProxy()
102    {
103       
104    }
105
106    /**
107     * Reads in the OMC CORBA object reference from a file on disk.
108     *
109     * @return the object reference as a <code>String</code>
110     * @throws ConnectException
111     *             the connect exception
112     */
113    private static String readObjectFromFile() throws ConnectException
114    {
115        File f = new File(getPathToObject());
116        String stringifiedObjectReference = null;
117
118        BufferedReader br = null;
119        FileReader fr = null;
120        try
121        {
122            fr = new FileReader(f);
123        }
124        catch(IOException e)
125        {
126            throw new ConnectException("Unable to read OpenModelica Compiler CORBA object from " + f.toString());
127        }
128
129        br = new BufferedReader(fr);
130           
131        try
132        {
133            stringifiedObjectReference = br.readLine();
134        }
135        catch(IOException e)
136        {
137            throw new ConnectException("Unable to read OpenModelica Compiler"
138                    + " CORBA object from " + getPathToObject());
139        }
140        return stringifiedObjectReference;
141    }
142   
143    /**
144     * Checks if is checks for initialized.
145     *
146     * @return true, if is checks for initialized
147     */
148    public static boolean isHasInitialized() {
149        return hasInitialized;
150    }
151
152    /**
153     * Sets the checks for initialized.
154     *
155     * @param has
156     *            the new checks for initialized
157     */
158    public static void setHasInitialized(boolean has) {
159        hasInitialized = has;
160    }
161   
162    /**
163     * Checks if is existing corba file is new.
164     *
165     * @return true, if is existing corba file is new
166     */
167    public static boolean isExistingCorbaFileIsNew() {
168        return existingCorbaFileIsNew;
169    }
170
171    /**
172     * Sets the existing corba file is new.
173     *
174     * @param existingCorbaFileIsNew
175     *            the new existing corba file is new
176     */
177    public static void setExistingCorbaFileIsNew(boolean existingCorbaFileIsNew) {
178        OMCProxy.existingCorbaFileIsNew = existingCorbaFileIsNew;
179    }
180
181    /**
182     * Gets the path to object.
183     *
184     * @return Returns the path to the OMC CORBA object that is stored on disk.
185     */
186    private static String getPathToObject()
187    {
188        String fileName = null;
189
190        /* This mirrors the way OMC creates the object file. */     
191        switch (os)
192        {
193        case UNIX:
194            String username = System.getenv("USER");
195            if(username == null)
196            {
197                username = "nobody";
198            }
199            fileName = "/tmp/openmodelica." + username + ".objid." + corbaSessionName;
200            break;
201        case WINDOWS:
202            String temp = System.getenv("TMP");         
203            fileName = temp + "\\openmodelica.objid." + corbaSessionName;
204            break;
205        default:
206            logBug("org.modelica", "os variable set to unexpected os-type");
207        }
208       
209        logOMCStatus("Will look for OMC object reference in '" 
210                + fileName + "'.");
211       
212        return fileName;
213    }
214   
215    /**
216     * With the help of voodoo magic determines the path to the
217     * omc binary that user (probably) wants to use and the working
218     * direcoty of where that binary (most likely) should be started in
219     *
220     * This will returns for example 'c:\openmodelica132\omc.exe'
221     * or '/usr/local/share/openmodelica/omc' depending on
222     * such factors as: OS type, environment variables settings,
223     * plugin user preferences, where the first matching
224     * binary found and the weather outside.
225     *
226     * @return full path to the omc binary 
227     * @throws ConnectException if the path could not be determined
228     */
229    private static File[] getOmcBinaryPaths() throws ConnectException
230    {
231        String binaryName = "omc";
232       
233        if (os == osType.WINDOWS)
234        {
235            binaryName += ".exe";
236        }
237       
238        File omcBinary = null;
239        File omcWorkingDirectory = null;
240        /*
241         * user specified that standard path to omc should be used,
242         * try to determine the omc path via the OPENMODELICAHOME and
243         * by checking in it's varius subdirectory for the omc binary file
244         */
245        logOMCStatus("Using OPENMODELICAHOME environment variable to find omc-binary");
246       
247        /*
248         * Standard path to omc (or omc.exe) binary is encoded in OPENMODELICAHOME
249         * variable.
250         */
251        String openModelicaHome = System.getenv("OPENMODELICAHOME");
252        if(openModelicaHome == null)
253        {
254            final String m = "Environment variable OPENMODELICAHOME not set";
255            logOMCStatus("Environment variable OPENMODELICAHOME not set,"+
256                    " don't know how to start OMC from standard path.");
257            throw new ConnectException(m);
258        }
259       
260        omcWorkingDirectory = new File(openModelicaHome);
261       
262        /* the subdirectories where omc binary may be located, hurray for standards! */
263        String[] subdirs = { "", "bin", "Compiler" };
264       
265        for (String subdir : subdirs)
266        {
267       
268            String path = omcWorkingDirectory.getAbsolutePath() + File.separator;
269            path += subdir.equals("") ? binaryName :  subdir + File.separator + binaryName;
270
271            File file = new File(path); 
272
273            if (file.exists())
274            {
275                omcBinary = file;
276                logOMCStatus("Using omc-binary at '" + omcBinary.getAbsolutePath() + "'");
277                break;
278            }
279            else
280            {
281                logOMCStatus("No omc binary at: [" + path + "]");
282            }
283        }
284       
285        if (omcBinary == null)
286        {
287            logOMCStatus("Could not fine omc-binary on the OPENMODELICAHOME path");
288            throw new ConnectException("Unable to start the OpenModelica Compiler, binary not found");
289        }
290
291        return new File[] {omcBinary, omcWorkingDirectory};
292    }
293   
294    /**
295     * Start a new OMC server.
296     *
297     * @throws ConnectException
298     *             the connect exception
299     */
300    private static void startServer() throws ConnectException
301    {
302        File tmp[] = getOmcBinaryPaths();
303
304        File omcBinary = tmp[0];
305        File workingDirectory = new File(".");
306
307       
308        /*
309         * Delete old object reference file. We need to do this because we're
310         * checking if the file exists to determine if the server has started
311         * or not (further down).
312         */
313        File f = new File(getPathToObject());
314        long lastModified = 0;     
315        if(f.exists())
316        {
317            lastModified = f.lastModified();
318            logOMCStatus("OMC object reference file is already on disk, we try to use it.");
319            if (existingCorbaFileIsNew) return;
320            logOMCStatus("OMC object reference file is already on disk, but is old, start a new server.");
321        }
322       
323        String command[] = { omcBinary.getAbsolutePath(), "+c=" + corbaSessionName, "+d=interactiveCorba" };
324        try
325        {
326            logOMCStatus("Running command " + command[0] + " " + command[1] + " " + command[2]);
327            logOMCStatus("Setting working directory to " + workingDirectory.getAbsolutePath());
328            ProcessStartThread pt = new ProcessStartThread(command, workingDirectory);
329            pt.start();
330        }
331        catch(Exception e)
332        {
333            e.printStackTrace();
334            logOMCStatus("Error running command " + e.getMessage());
335            logOMCStatus("Unable to start OMC, giving up."); 
336            throw new ConnectException("Unable to start the OpenModelica Compiler. ");
337        }           
338
339        logOMCStatus("Waiting for OMC CORBA object reference to appear on disk.");
340        existingCorbaFileIsNew = true;
341       
342        /*
343         * Wait until the object exists on disk, but if it takes longer than
344         * 5 seconds, abort. (Very arbitrary 5 seconds..)
345         */
346        int ticks = 0;
347        while(!f.exists() || (f.exists() && lastModified == f.lastModified()) )
348        {
349            try
350            {
351                logOMCStatus("Waiting for OMC CORBA object reference to appear on disk ... for "+ (ticks+1) + " seconds");
352                Thread.sleep(100);
353            }
354            catch(InterruptedException e)
355            {
356                /* ignore */
357            }
358            ticks++;
359           
360            /* If we've waited for around 5 seconds, abort the wait for OMC */
361            if(ticks > 50)
362            {
363                logOMCStatus("No OMC object reference file created after approximately 50 seconds.");
364                logOMCStatus("It seems OMC does not want to start, giving up.");
365                throw new ConnectException("Unable to start the Open Modelica Compiler. Waited for 5 seconds, but it didn't respond.");
366            }
367        }
368        logOMCStatus("The new OMC object reference found.");
369    }
370   
371    /**
372     * Initializes an ORB, converts the stringified OMC object to a real CORBA
373     * object, and then narrows that object to an OmcCommunication object.
374     *
375     * @param stringifiedObjectReference
376     *            the new up omcc
377     */
378    private static void setupOmcc(String stringifiedObjectReference)
379    {
380        /* Can't remember why this is needed. But it is. */
381        String args[] = {null};
382
383        /* set the CORBA read timeout to a larger value as we send huge
384ammounts of data
385         * from OMC to MDT
386         */
387        System.setProperty("com.sun.CORBA.transport.ORBTCPReadTimeouts", "1:60000:300:1");
388       
389        ORB orb;
390        orb = ORB.init(args, null);     
391
392        /* Convert string to object. */
393        org.omg.CORBA.Object obj = 
394orb.string_to_object(stringifiedObjectReference);       
395
396        /* Convert object to OmcCommunication object. */
397        omcc = OmcCommunicationHelper.narrow(obj);
398
399    }
400   
401    /**
402     * Gets the os.
403     *
404     * @return the name of the operating system. If an unknown os is found, the
405     *         default is Unix.
406     */
407    private static osType getOs()
408    {
409        String osName = System.getProperty("os.name");
410        if(osName.contains("Linux"))
411        {
412            return osType.UNIX;
413        }
414        else if(osName.contains("Windows"))
415        {
416            return osType.WINDOWS;
417        }
418        else
419        {
420            logWarning("'" + osName + "' not officialy supported OS");
421            /* If the OS is not GNU/Linux or Windows, default to Unix */
422            return osType.UNIX;
423        }
424    }
425
426    /**
427     * Initialize the communication with OMC.
428     *
429     * @throws ConnectException
430     *             if we're unable to start communicating with the server
431     */
432    private void init() throws ConnectException
433    {
434        /*
435         * Get type of operating system, used for finding object
436         * reference and starting OMC if the reference is faulty
437         */
438        os = getOs();
439       
440        /* See if an OMC server is already running */
441        File f = new File(getPathToObject());
442        String stringifiedObjectReference = null;
443        if(!f.exists())
444        {
445            /* If a server isn't running, start it */
446            logOMCStatus("No OMC object reference found, starting server.");
447            startServer();
448        }
449        else
450        {
451            logOMCStatus("Old OMC CORBA object reference present," + " assuming OMC is running.");
452        }
453       
454        /* Read in the CORBA OMC object from a file on disk */
455        stringifiedObjectReference = readObjectFromFile();
456
457        /*
458         * Setup up OMC object reference by initializing ORB and then
459         * converting the string object to a real CORBA object.
460         */
461        setupOmcc(stringifiedObjectReference);
462
463        try
464        {
465            /*
466             * Test the server by trying to send an expression to it.
467             * This might fail if the object reference found on disk didn't
468             * have a corresponding server running. If a server is missing,
469             * catch an exception and try starting a server.
470             */
471            logOMCStatus("Trying to send expression to OMC.");
472            omcc.sendExpression("1+1");
473            logOMCStatus("Expression sent successfully.");
474        }
475        catch(org.omg.CORBA.COMM_FAILURE e)
476        {
477            /* Start server and set up omcc */
478            logOMCStatus("Failed sending expression, will try to start OMC.");
479            existingCorbaFileIsNew = false;
480            startServer();
481            stringifiedObjectReference = readObjectFromFile();
482            setupOmcc(stringifiedObjectReference);
483
484            try
485            {
486                /* Once again try to send an expression to OMC. If it fails this
487                 * time it's time to send back an exception to the caller of
488                 * this function. */
489                logOMCStatus("Trying to send expression to OMC.");
490                omcc.sendExpression("1+1");
491                logOMCStatus("Expression sent successfully.");
492            }
493            catch(org.omg.CORBA.COMM_FAILURE x)
494            {
495                logOMCStatus("Failed sending expression, giving up.");
496                throw new ConnectException("Unable to start the OpenModelica Compiler.");
497            }
498        }
499
500        hasInitialized = true;
501    }
502   
503    /**
504     * Send expression to OMC. If communication is not initialized, it is
505     * initialized here.
506     *
507     * @param exp
508     *            the expression to send to OMC
509     * @return the string
510     * @throws ConnectException
511     *             if we're unable to start communicating with the server
512     */
513    // TODO add synchronization so that two threads don't fudge up each others
514    // communication with OMC
515    // old synchronization aka 'private synchronized String sendExpression(String exp)'
516    // doesnt work when there is possibility of multiple instances of OMCProxy objects
517    public String sendExpression(String exp)
518        throws ConnectException
519    {
520        String retval = null;
521       
522        if(hasInitialized == false)
523        {
524            init();
525        }
526       
527        try
528        {
529            logOMCCall(exp);
530            retval = omcc.sendExpression(exp);
531            logOMCReply(retval);
532        }
533        catch(org.omg.CORBA.COMM_FAILURE x)
534        {
535            logOMCCallError("Error while sending expression " + exp + " ["+x+"]");
536            /* lost connection to OMC or something */
537            throw new ConnectException("Couldn't send expression to the "+
538                    "OpenModelica Compiler. Tried sending: " + exp);
539        }
540       
541        return retval;
542    }
543   
544    /**
545     * Logs the expression sent to OMC if the tracing flag (traceOMCCalls) is
546     * set.
547     *
548     * @param expression
549     *            the expression that is about to be sent to OMC
550     */
551    public static void logOMCCall(String expression)
552    {
553        if (!traceOMCCalls)
554        {
555            return;
556        }
557        System.out.println(">> " + expression);
558    }
559   
560    /**
561     * outputs the message about a call error that occured when communicating
562     * with omc.
563     *
564     * @param message
565     *            the message to log
566     */
567    public static void logOMCCallError(String message)
568    {
569        if(!traceOMCCalls)
570        {
571            return;
572        }
573        System.out.println(message);
574    }
575   
576    /**
577     * loggs the message conserning OMC status if the tracing flag
578     * traceOMCStatus is set.
579     *
580     * @param message
581     *            the message to log
582     */
583    public static void logOMCStatus(String message)
584    {
585        if (!traceOMCStatus)
586        {
587            return;
588        }
589        System.out.println("OMCSTATUS: " + message);
590    }
591
592    /**
593     * Logs the reply received from OMC if the tracing flag (traceOMCCalls) is
594     * set.
595     *
596     * @param reply
597     *            the reply recieved from the OMC
598     */
599    public static void logOMCReply(String reply)
600    {
601        if (!traceOMCCalls)
602        {
603            return;
604        }
605
606        StringTokenizer tokenizer = new StringTokenizer(reply, "\n");
607       
608        while (tokenizer.hasMoreTokens())
609        {
610            System.out.println("<< " + tokenizer.nextToken());
611        }
612    }
613   
614    /**
615     * Get the classes contained in a class (a package is a class..)
616     *
617     * @param className
618     *            full class name where to look for packages
619     * @return a <code>List</code> of subclasses defined (and loaded into OMC)
620     *         inside the class named className.
621     * @throws ConnectException
622     *             the connect exception
623     */ 
624    public String getClassNames(String className) throws ConnectException
625    {
626        String retval = sendExpression("getClassNames("+className+")");
627       
628        /* fetch error string but ignore it */
629        getErrorString();
630               
631        return retval;
632    }
633
634    /**
635     * Gets the type of restriction of a class.
636     *
637     * @param className
638     *            fully qualified class name
639     * @return the type of restriction of the class
640     * @throws ConnectException
641     *             the connect exception
642     */
643    public String getRestriction(String className) throws ConnectException
644    {
645        String reply = sendExpression("getClassRestriction(" + className + ")");
646
647        /* remove " around the reply */
648        reply = reply.trim();
649               
650        return reply;
651    }
652   
653    /**
654     * Fetches the error string from OMC. This should be called after an "Error"
655     * is received. (Or whenever the queue of errors should be emptied.)
656     *
657     * @return the <code>String</code> of errors
658     * @throws ConnectException
659     *             the connect exception
660     */
661    private String getErrorString() throws ConnectException
662    {
663        String res = sendExpression("getErrorString()");
664       
665        /* Make sure the error string isn't empty */
666        if(res != null && res.length() > 2)
667        {
668            res = res.trim();
669            return res.substring(1, res.length() - 1);
670        }
671        else
672            return "";
673    }
674   
675
676    /**
677     * Tries to load file into OMC which causes it to be parsed and the syntax
678     * checked.
679     *
680     * @param file
681     *            the file we want to load
682     * @return a <code>ParseResult</code> containing the classes found in the
683     *         file and the error messages from OMC
684     * @throws ConnectException
685     *             the connect exception
686     */
687    public String loadSourceFile(String file) throws ConnectException
688    {
689        String retval = sendExpression("loadFileInteractiveQualified(\"" + file + "\")");
690        retval = retval.trim();
691        // String errorString = getErrorString();
692        /*
693         * See if there were parse errors, an empty list {} also denotes error
694         */
695        return retval;
696    }
697
698    /**
699     * Gets the location (file, starting and ending line number and column
700     * number) of a Modelica element.
701     *
702     * @param className
703     *            the element we want to get location of
704     * @return an <code>ElementLocation</code> containing the file, starting and
705     *         ending line number and column number of the given class
706     * @throws ConnectException
707     *             the connect exception
708     * @throws InvocationError
709     *             the invocation error
710     */
711    public String getClassLocation(String className) throws ConnectException, InvocationError
712    {
713        String retval = sendExpression("getCrefInfo(" + className + ")");
714       
715        /* fetch error string but ignore it */
716        getErrorString();
717       
718        if(retval.contains("Error") || retval.contains("error"))
719        {
720            throw new 
721                InvocationError("Fetching file position of " + className, "getCrefInfo(" + className + ")");
722        }
723       
724       
725        /*
726         * The getCrefInfo reply has the following format:
727         *
728         * <file path>,<something>,<start line>,<start column>,<end line>,<end column>
729         *
730         * for example:
731         * /foo/Modelica/package.mo,writable,1,1,1029,13
732         */
733
734        /* For some reason, the list returned doesn't contain curly braces. */
735        retval = retval.trim();
736        retval = "{" + retval + "}"; 
737               
738        return retval;
739    }
740   
741    /**
742     * Queries the compiler if a particular modelica class/package is a package.
743     *
744     * @param className
745     *            fully qualified name of the class/package
746     * @return true if className is a package, false otherwise
747     * @throws ConnectException
748     *             the connect exception
749     */
750    public boolean isPackage(String className) throws ConnectException
751    {
752        String retval = sendExpression("isPackage(" + className + ")");
753
754        /* fetch error string but ignore it */
755        getErrorString();
756       
757        return retval.contains("true");
758    }
759   
760    /**
761     * Uses the OMC API call getElementsInfo to fetch lots of information about
762     * a class definition. See interactive_api.txt in the OMC source tree.
763     *
764     * @param className
765     *            the fully qualified name of a class
766     * @return a <code>Collection</code> (of <code>ElementsInfo</code>)
767     *         containing the information about className
768     * @throws ConnectException
769     *             the connect exception
770     * @throws InvocationError
771     *             the invocation error
772     */
773    public String getElements(String className) throws ConnectException, InvocationError
774    {
775        String retval = sendExpression("getElementsInfo("+ className +")");
776       
777        /* fetch error string */
778        getErrorString();
779       
780        return retval;
781    }
782
783    /**
784     * Gets the class info.
785     *
786     * @param className
787     *            the class name
788     * @return the class info
789     * @throws ConnectException
790     *             the connect exception
791     */
792    public String getClassInfo(String className) throws ConnectException
793    {
794        String retval = sendExpression("getClassInformation("+ className +")");
795       
796        /* fetch error string but ignore it */
797        getErrorString();
798               
799        return  retval;
800    }
801
802   
803    /**
804     * Gets the compiler name.
805     *
806     * @return the name of the compiler that this plugin tries to communicate
807     *         with (at least it tries...)
808     */
809    public String getCompilerName()
810    {
811        return "OpenModelica Compiler";
812    }
813
814    /**
815     * Loads in the Modelica System Library and returns names of the top-level
816     * packages.
817     *
818     * @return the standard library
819     * @throws ConnectException
820     *             if we're unable to start communicating with the server
821     */ 
822    public String[] getStandardLibrary() throws ConnectException
823    {
824        if (!systemLibraryLoaded)
825        {
826            sendExpression("loadModel(Modelica)");
827           
828            /* fetch error string but ignore it */
829            getErrorString();
830           
831            systemLibraryLoaded = true;
832        }
833
834        return standardLibraryPackages;
835    }
836   
837    /**
838     * Log bug.
839     *
840     * @param where
841     *            the where
842     * @param message
843     *            the message
844     */
845    public static void logBug(String where, String message)
846    {
847        System.out.println("Error: " + where + " Message: "+ message);
848    }
849
850    /**
851     * Log warning.
852     *
853     * @param message
854     *            the message
855     */
856    public static void logWarning(String message)
857    {
858        System.out.println("Warning: " + message);
859    }
860
861}
Note: See TracBrowser for help on using the repository browser.