source: trunk/org.modelica.mdt.omc/src/org/modelica/mdt/omc/OMCProxy.java @ 405

Last change on this file since 405 was 405, checked in by remar, 19 years ago
  • search for omc binary in Compiler instead of compiler
File size: 25.5 KB
Line 
1/*
2 * This file is part of Modelica Development Tooling.
3 *
4 * Copyright (c) 2005, Link�pings universitet, Department of
5 * Computer and Information Science, PELAB
6 *
7 * All rights reserved.
8 *
9 * (The new BSD license, see also
10 * http://www.opensource.org/licenses/bsd-license.php)
11 *
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are
15 * met:
16 *
17 * * Redistributions of source code must retain the above copyright
18 *   notice, this list of conditions and the following disclaimer.
19 *
20 * * Redistributions in binary form must reproduce the above copyright
21 *   notice, this list of conditions and the following disclaimer in
22 *   the documentation and/or other materials provided with the
23 *   distribution.
24 *
25 * * Neither the name of Link�pings universitet nor the names of its
26 *   contributors may be used to endorse or promote products derived from
27 *   this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41
42package org.modelica.mdt.omc;
43
44import java.io.BufferedReader;
45import java.io.File;
46import java.io.FileReader;
47import java.io.IOException;
48import java.util.Collection;
49import java.util.LinkedList;
50import java.util.StringTokenizer;
51
52import org.eclipse.core.resources.IFile;
53import org.eclipse.core.runtime.Platform;
54import org.modelica.mdt.core.IModelicaClass;
55import org.modelica.mdt.core.IllegalTypeException;
56import org.modelica.mdt.core.List;
57import org.modelica.mdt.core.ListElement;
58import org.modelica.mdt.core.compiler.ConnectException;
59import org.modelica.mdt.core.compiler.ElementsInfo;
60import org.modelica.mdt.core.compiler.IModelicaCompiler;
61import org.modelica.mdt.core.compiler.InvocationError;
62import org.modelica.mdt.core.compiler.ModelicaParser;
63import org.modelica.mdt.core.compiler.UnexpectedReplyException;
64import org.modelica.mdt.core.preferences.PreferenceManager;
65import org.modelica.mdt.internal.core.ElementLocation;
66import org.modelica.mdt.internal.core.ErrorManager;
67import org.modelica.mdt.omc.internal.ParseResults;
68import org.modelica.mdt.omc.internal.OMCParser;
69import org.modelica.mdt.omc.internal.corba.OmcCommunication;
70import org.modelica.mdt.omc.internal.corba.OmcCommunicationHelper;
71import org.omg.CORBA.ORB;
72
73/**
74 * The OMCProxy is the glue between the OpenModelica Compiler and MDT.
75 * It uses the interactive API of OMC to get information about classes
76 * and to load classes into OMC.
77 *
78 * @author Andreas Remar
79 */
80public class OMCProxy implements IModelicaCompiler
81{
82    /* the CORBA object */
83    private static OmcCommunication omcc;
84   
85   
86    enum osType { WINDOWS, UNIX };
87   
88    /* what Operating System we're running on */
89    private static osType os;
90   
91    /* indicates if we've setup the communication with OMC */
92    private boolean hasInitialized = false;
93   
94    /* indicates if the Modelica System Library has been loaded */
95    private boolean systemLibraryLoaded = false;
96
97    private String[] standardLibraryPackages = { "Modelica" };
98
99    /* should we trace the calls to sendExpression? */
100    private static boolean traceOMCCalls = false;
101    private static boolean traceOMCStatus = false;
102    static
103    {
104        /* load debug options and set debug flag variables accordingly */
105       
106       
107        String value = Platform.getDebugOption  /*load trace/omcCalls flag */
108            ("org.modelica.mdt.omc/trace/omcCalls");
109        if (value != null && value.equalsIgnoreCase("true"))
110        {
111            traceOMCCalls = true;
112        }
113       
114        value = Platform.getDebugOption
115        ("org.modelica.mdt.omc/trace/omcStatus");
116        if (value != null && value.equalsIgnoreCase("true"))
117        {
118            traceOMCStatus = true;
119        }
120    }
121   
122    public OMCProxy()
123    {
124       
125    }
126
127    /**
128     * Reads in the OMC CORBA object reference from a file on disk.
129     * @return the object reference as a <code>String</code>
130     */
131    private static String readObjectFromFile() throws ConnectException
132    {
133        File f = new File(getPathToObject());
134        String stringifiedObjectReference = null;
135
136        BufferedReader br = null;
137        FileReader fr = null;
138        try
139        {
140            fr = new FileReader(f);
141        }
142        catch(IOException e)
143        {
144            throw new ConnectException
145                ("Unable to read OpenModelica Compiler CORBA object from "
146                        + f.toString());
147        }
148
149        br = new BufferedReader(fr);
150           
151        try
152        {
153            stringifiedObjectReference = br.readLine();
154        }
155        catch(IOException e)
156        {
157            throw new ConnectException("Unable to read OpenModelica Compiler"
158                    + " CORBA object from " + getPathToObject());
159        }
160        return stringifiedObjectReference;
161    }
162   
163    /**
164     * @return Returns the path to the OMC CORBA object that is stored on disk.
165     */
166    private static String getPathToObject()
167    {
168        String fileName = null;
169
170        /* This mirrors the way OMC creates the object file. */     
171        switch (os)
172        {
173        case UNIX:
174            String username = System.getenv("USER");
175            if(username == null)
176            {
177                username = "nobody";
178            }
179            fileName = "/tmp/openmodelica." + username + ".objid";
180            break;
181        case WINDOWS:
182            String temp = System.getenv("TMP");         
183            fileName = temp + "\\openmodelica.objid";
184            break;
185        default:
186            ErrorManager.logBug("org.modelica.mdt.omc",
187                    "os variable set to unexpected os-type");
188        }
189       
190        logOMCStatus("Will look for OMC object reference in '" 
191                + fileName + "'.");
192       
193        return fileName;
194    }
195   
196    /**
197     * With the help of voodoo magic determines the path to the
198     * omc binary that user (probably) wants to use and the working
199     * direcoty of where that binary (most likely) should be started in
200     *
201     * This will returns for example 'c:\openmodelica132\omc.exe'
202     * or '/usr/local/share/openmodelica/omc' depending on
203     * such factors as: OS type, environment variables settings,
204     * plugin user preferences, where the first matching
205     * binary found and the weather outside.
206     *
207     * @return full path to the omc binary 
208     * @throws ConnectException if the path could not be determined
209     */
210    private static File[] getOmcBinaryPaths() throws ConnectException
211    {
212        String binaryName = "omc";
213       
214        if (os == osType.WINDOWS)
215        {
216            binaryName += ".exe";
217        }
218       
219        File omcBinary = null;
220        File omcWorkingDirectory = null;
221        if (PreferenceManager.getUseStandardOmcPath())
222        {
223            /*
224             * user specified that standard path to omc should be used,
225             * try to determine the omc path via the OPENMODELICAHOME and
226             * by checking in it's varius subdirectory for the omc binary file
227             */
228            logOMCStatus("Using OPENMODELICAHOME environment variable to find omc-binary");
229           
230            /*
231             * Standard path to omc (or omc.exe) binary is encoded in OPENMODELICAHOME
232             * variable.
233             */
234            String openModelicaHome = System.getenv("OPENMODELICAHOME");
235            if(openModelicaHome == null)
236            {
237                final String m = "Environment variable OPENMODELICAHOME not set";
238                logOMCStatus("Environment variable OPENMODELICAHOME not set,"+
239                        " don't know how to start OMC from standard path.");
240                throw new ConnectException(m);
241            }
242           
243            omcWorkingDirectory = new File(openModelicaHome);
244           
245            /* the subdirectories where omc binary may be located, hurray for standards! */
246            String[] subdirs = { "", "bin", "Compiler" };
247           
248            for (String subdir : subdirs)
249            {
250           
251                String path = omcWorkingDirectory.getAbsolutePath() + File.separator;
252                path += subdir.equals("") ? binaryName :  subdir + File.separator + binaryName;
253
254                File file = new File(path); 
255
256                if (file.exists())
257                {
258                    omcBinary = file;
259                    logOMCStatus("Using omc-binary at '" + omcBinary.getAbsolutePath() + "'");
260                    break;
261                }
262                else
263                {
264                    logOMCStatus("No omc binary at: [" + path + "]");
265                }
266            }
267           
268            if (omcBinary == null)
269            {
270                logOMCStatus("Could not fine omc-binary on the OPENMODELICAHOME path");
271                throw new ConnectException("Unable to start the OpenModelica Compiler, binary not found");
272            }
273        }
274        else
275        {
276            omcBinary = new File(PreferenceManager.getCustomOmcPath());
277           
278            logOMCStatus("Using userspecified omc-binary at '" +
279                    omcBinary.getAbsolutePath() + "'");
280           
281            if (!omcBinary.exists())
282            {
283                logOMCStatus("file '" + omcBinary.getAbsolutePath() + "' does not exist");
284                throw new ConnectException("Specified omc-binary '" + omcBinary.getAbsolutePath() +
285                    "' does not exist");
286            }
287           
288            /*
289             * take an educated guess at where the user wants the binary to be
290             * started. The guessing heuristics are as follows:
291             *
292             * If binary is inside the 'bin' or 'compiler' directory, use the
293             * above directory as working directory.
294             *
295             * Otherwise use the directory where binary is located as working
296             * directory.
297             *
298             * e.g. binary path /foo/bar/bin/omc      => working directory /foo/bar
299             *      binary path /foo/bar/compiler/omc => working directory /foo/bar
300             *      binary path /foo/bar/omc          => working directory /foo/bar
301             */
302            File parent = omcBinary.getParentFile();
303           
304            if (parent.getName().equalsIgnoreCase("bin") || 
305                parent.getName().equalsIgnoreCase("compiler"))
306            {
307                omcWorkingDirectory = parent.getParentFile();
308            }
309            else
310            {
311                omcWorkingDirectory = parent;
312            }
313           
314        }
315
316        return new File[] {omcBinary, omcWorkingDirectory};
317    }
318   
319    /**
320     * Start a new OMC server.
321     */
322    private static void startServer() throws ConnectException
323    {
324        File tmp[] = getOmcBinaryPaths();
325
326        File omcBinary = tmp[0];
327        File workingDirectory = tmp[1];
328
329       
330        /*
331         * Delete old object reference file. We need to do this because we're
332         * checking if the file exists to determine if the server has started
333         * or not (further down).
334         */
335        File f = new File(getPathToObject());
336        if(f.exists())
337        {
338            logOMCStatus("Removing old OMC object reference file.");
339            f.delete();
340        }
341       
342        String command[] = { omcBinary.getAbsolutePath(), "+d=interactiveCorba" };
343        try
344        {
345            logOMCStatus("Running command " + command[0] + " " + command[1]);
346            logOMCStatus("Setting working directory to " + workingDirectory.getAbsolutePath());
347            Runtime.getRuntime().exec(command, null, workingDirectory);
348            logOMCStatus("Command run successfully.");
349        }
350        catch(IOException e)
351        {
352            logOMCStatus("Error running command " + e.getMessage());
353            logOMCStatus("Unable to start OMC, giving up."); 
354            throw new ConnectException
355                ("Unable to start the OpenModelica Compiler. ");
356        }           
357
358        logOMCStatus("Waiting for OMC CORBA object reference to appear on disk.");
359       
360        /*
361         * Wait until the object exists on disk, but if it takes longer than
362         * 5 seconds, abort. (Very arbitrary 5 seconds..)
363         */
364        int ticks = 0;
365        while(!f.exists())
366        {
367            try
368            {
369                Thread.sleep(100);
370            }
371            catch(InterruptedException e)
372            {
373                /* ignore */
374            }
375            ticks++;
376           
377            /* If we've waited for around 5 seconds, abort the wait for OMC */
378            if(ticks > 50)
379            {
380                logOMCStatus("No OMC object reference file created after " + 
381                        "approximately 5 seconds.");
382                logOMCStatus("It seems OMC does not want to come up, giving " +
383                        "up.");
384                throw new ConnectException
385                    ("Unable to start the Open Modelica Compiler. Waited for 5"
386                            +" seconds, but it didn't respond.");
387            }
388        }
389        logOMCStatus("OMC object reference found.");
390    }
391   
392    /**
393     * Initializes an ORB, converts the stringified OMC object to a real
394     * CORBA object, and then narrows that object to an OmcCommunication
395     * object.
396     */
397    private static void setupOmcc(String stringifiedObjectReference)
398    {
399        /* Can't remember why this is needed. But it is. */
400        String args[] = {null};
401       
402        ORB orb;
403        orb = ORB.init(args, null);
404       
405        /* Convert string to object. */
406        org.omg.CORBA.Object obj
407            = orb.string_to_object(stringifiedObjectReference);
408       
409        /* Convert object to OmcCommunication object. */
410        omcc = OmcCommunicationHelper.narrow(obj);
411    }
412   
413    /**
414     * @return the name of the operating system. If an unknown os is found,
415     * the default is Unix.
416     */
417    private static osType getOs()
418    {
419        String osName = System.getProperty("os.name");
420        if(osName.contains("Linux"))
421        {
422            return osType.UNIX;
423        }
424        else if(osName.contains("Windows"))
425        {
426            return osType.WINDOWS;
427        }
428        else
429        {
430            ErrorManager.logWarning("'" + osName + "' not officialy supported OS");
431            /* If the OS is not GNU/Linux or Windows, default to Unix */
432            return osType.UNIX;
433        }
434    }
435
436    /**
437     * Initialize the communication with OMC
438     * @throws ConnectException if we're unable to start communicating with
439     * the server
440     */
441    private void init() throws ConnectException
442    {
443        /*
444         * Get type of operating system, used for finding object
445         * reference and starting OMC if the reference is faulty
446         */
447        os = getOs();
448       
449        /* See if an OMC server is already running */
450        File f = new File(getPathToObject());
451        String stringifiedObjectReference = null;
452        if(!f.exists())
453        {
454            /* If a server isn't running, start it */
455            logOMCStatus("No OMC object reference found, starting server.");
456            startServer();
457        }
458        else
459        {
460            logOMCStatus("Old OMC CORBA object reference present," +
461                    " assuming OMC is running.");
462        }
463       
464        /* Read in the CORBA OMC object from a file on disk */
465        stringifiedObjectReference = readObjectFromFile();
466
467        /*
468         * Setup up OMC object reference by initializing ORB and then
469         * converting the string object to a real CORBA object.
470         */
471        setupOmcc(stringifiedObjectReference);
472
473        try
474        {
475            /*
476             * Test the server by trying to send an expression to it.
477             * This might fail if the object reference found on disk didn't
478             * have a corresponding server running. If a server is missing,
479             * catch an exception and try starting a server.
480             */
481            logOMCStatus("Trying to send expression to OMC.");
482            omcc.sendExpression("1+1");
483            logOMCStatus("Expression sent successfully.");
484        }
485        catch(org.omg.CORBA.COMM_FAILURE e)
486        {
487            /* Start server and set up omcc */
488            logOMCStatus("Failed sending expression, will try to start OMC.");
489            startServer();
490            stringifiedObjectReference = readObjectFromFile();
491            setupOmcc(stringifiedObjectReference);
492
493            try
494            {
495                /* Once again try to send an expression to OMC. If it fails this
496                 * time it's time to send back an exception to the caller of
497                 * this function. */
498                logOMCStatus("Trying to send expression to OMC.");
499                omcc.sendExpression("1+1");
500                logOMCStatus("Expression sent successfully.");
501            }
502            catch(org.omg.CORBA.COMM_FAILURE x)
503            {
504                logOMCStatus("Failed sending expression, giving up.");
505                throw new ConnectException("Unable to start the OpenModelica"
506                        +" Compiler.");
507            }
508        }
509
510        hasInitialized = true;
511    }
512   
513    /**
514     * Send expression to OMC. If communication is not initialized, it
515     * is initialized here.
516     * @param exp the expression to send to OMC
517     * @throws ConnectException if we're unable to start communicating with
518     * the server
519     */
520    // TODO add synchronization so that two threads don't fudge up each others
521    // communication with OMC
522    // old synchronization aka 'private synchronized String sendExpression(String exp)'
523    // doesnt work when there is possibility of multiple instances of OMCProxy objects
524    private String sendExpression(String exp)
525        throws ConnectException
526    {
527        String retval = null;
528       
529        if(hasInitialized == false)
530        {
531            init();
532        }
533       
534        try
535        {
536            logOMCCall(exp);
537            retval = omcc.sendExpression(exp);
538            logOMCReply(retval);
539        }
540        catch(org.omg.CORBA.COMM_FAILURE x)
541        {
542            logOMCCallError("Error while sending expression " + exp + " ["+x+"]");
543            /* lost connection to OMC or something */
544            throw new ConnectException("Couldn't send expression to the "+
545                    "OpenModelica Compiler. Tried sending: " + exp);
546        }
547       
548        return retval;
549    }
550   
551    /**
552     * Logs the expression sent to OMC if the
553     * tracing flag (traceOMCCalls) is set
554     *
555     * @param expression the expression that is about to be sent to OMC
556     */
557    private static void logOMCCall(String expression)
558    {
559        if (!traceOMCCalls)
560        {
561            return;
562        }
563        System.out.println(">> " + expression);
564    }
565   
566    /**
567     * outputs the message about a call error that occured
568     * when communicating with omc
569     * @param message the message to log
570     */
571    private static void logOMCCallError(String message)
572    {
573        if(!traceOMCCalls)
574        {
575            return;
576        }
577        System.out.println(message);
578    }
579   
580    /**
581     * loggs the message conserning OMC status if the
582     * tracing flag traceOMCStatus is set
583     * @param message the message to log
584     */
585    private static void logOMCStatus(String message)
586    {
587        if (!traceOMCStatus)
588        {
589            return;
590        }
591        System.out.println("OMCSTATUS: " + message);
592    }
593
594    /**
595     * Logs the reply received from OMC if
596     * the tracing flag (traceOMCCalls) is set
597     *
598     * @param reply the reply recieved from the OMC
599     */
600    private static void logOMCReply(String reply)
601    {
602        if (!traceOMCCalls)
603        {
604            return;
605        }
606
607        StringTokenizer tokenizer = new StringTokenizer(reply, "\n");
608       
609        while (tokenizer.hasMoreTokens())
610        {
611            System.out.println("<< " + tokenizer.nextToken());
612        }
613    }
614   
615    /**
616     * Get the classes contained in a class (a package is a class..)
617     *
618     *
619     * @param className full class name where to look for packages
620     * @return a <code>List</code> of subclasses defined (and loaded into OMC)
621     * inside the class named className.
622     *
623     * @throws ConnectException
624     * @throws UnexpectedReplyException
625     * @throws InitializationException
626     */ 
627    public List getClassNames(String className)
628        throws ConnectException, UnexpectedReplyException
629    {
630        String retval = sendExpression("getClassNames("+className+")");
631       
632        /* fetch error string but ignore it */
633        getErrorString();
634       
635        return ModelicaParser.parseList(retval);
636    }
637
638    /**
639     * Gets the restriction type of a class.
640     *
641     * @param className fully qualified class name
642     * @return the restriction type of the class or Type.CLASS if
643     *         type can't be determined
644     * @throws ConnectException
645     * @throws UnexpectedReplyException
646     */
647    public IModelicaClass.Type getRestrictionType(String className)
648        throws ConnectException, UnexpectedReplyException
649    {
650        String reply = 
651            sendExpression("getClassRestriction(" + className + ")");
652
653        /* remove " around the reply */
654        reply = reply.trim();
655       
656        if(reply.equals(""))
657        {
658            throw new UnexpectedReplyException("getClassRestriction("+className
659                    +") returned an empty result");
660        }
661       
662        reply = reply.substring(1, reply.length()-1);
663       
664        /* fetch error string but ignore it */
665        getErrorString();
666       
667        IModelicaClass.Type type = null;
668        try
669        {
670            type = IModelicaClass.Type.parse(reply);
671        }
672        catch(IllegalTypeException e)
673        {
674            throw new UnexpectedReplyException("Illegal type: "
675                    + e.getMessage());
676        }
677       
678        return type;
679    }
680   
681    /**
682     * Fetches the error string from OMC. This should be called after an "Error"
683     * is received. (Or whenever the queue of errors should be emptied.)
684     * @return the <code>String</code> of errors
685     * @throws ConnectException
686     */
687    private String getErrorString()
688        throws ConnectException
689    {
690        String res = sendExpression("getErrorString()");
691       
692        /* Make sure the error string isn't empty */
693        if(res != null && res.length() > 2)
694        {
695            res = res.trim();
696            return res.substring(1, res.length() - 1);
697        }
698        else
699            return "";
700    }
701   
702
703    /**
704     * Tries to load file into OMC which causes it to be parsed and the syntax
705     * checked.
706     * @param file the file we want to load
707     * @return a <code>ParseResult</code> containing the classes found in the
708     * file and the error messages from OMC
709     * @throws ConnectException
710     * @throws UnexpectedReplyException
711     * @throws InitializationException
712     */
713    public ParseResults loadSourceFile(IFile file)
714        throws ConnectException, UnexpectedReplyException
715    {
716        ParseResults res = new ParseResults();
717
718        String fullName = file.getLocation().toString();
719        String retval = 
720            sendExpression("loadFileInteractiveQualified(\"" + fullName + "\")");
721       
722        /* Always keep your stuff nice and tidy! */
723        retval = retval.trim();
724       
725        String errorString = getErrorString();
726
727        /*
728         * See if there were parse errors, an empty list {} also denotes error
729         */
730        if(retval.toLowerCase().contains("error") || retval.equals("{}"))
731        {           
732            res.setClassNames(new List());
733            if(errorString.equals("") == false)
734            {
735                res.setCompileErrors(OMCParser.parseErrorString(errorString));
736            }
737        }
738        /*
739         * File loaded and parsed successfully
740         */
741        else
742        {
743            res.setClassNames(ModelicaParser.parseList(retval));
744
745            /*
746             * If there were errors, but the compilation went through,
747             * collect the error messages. (Test if errorString != "")
748             */
749            if(errorString.equals("") == false)
750            {
751                res.setCompileErrors(OMCParser.parseErrorString(errorString));             
752            }
753        }
754
755        return res;
756    }
757
758    /**
759     * Gets the location (file, starting and ending line number and column
760     * number) of a Modelica element.
761     * @param className the element we want to get location of
762     * @return an <code>ElementLocation</code> containing the file, starting and
763     * ending line number and column number of the given class
764     * @throws ConnectException
765     * @throws UnexpectedReplyException
766     * @throws InvocationError
767     */
768    public ElementLocation getClassLocation(String className)
769        throws ConnectException, UnexpectedReplyException, InvocationError
770    {
771        String retval = sendExpression("getCrefInfo(" + className + ")");
772       
773        /* fetch error string but ignore it */
774        getErrorString();
775       
776        if(retval.contains("Error") || retval.contains("error"))
777        {
778            throw new 
779                InvocationError("Fetching file position of " + className,
780                        "getCrefInfo(" + className + ")");
781        }
782       
783       
784        /*
785         * The getCrefInfo reply has the following format:
786         *
787         * <file path>,<something>,<start line>,<start column>,<end line>,<end column>
788         *
789         * for example:
790         * /foo/Modelica/package.mo,writable,1,1,1029,13
791         */
792
793        /* For some reason, the list returned doesn't contain curly braces. */
794        retval = retval.trim();
795        retval = "{" + retval + "}"; 
796
797        List tokens = ModelicaParser.parseList(retval);
798       
799        String filePath = tokens.elementAt(0).toString();
800        int startLine;
801        int startColumn;
802        int endLine;
803        int endColumn;
804
805        try
806        {
807            startLine = Integer.parseInt(tokens.elementAt(2).toString());
808            startColumn = Integer.parseInt(tokens.elementAt(3).toString());
809            endLine = Integer.parseInt(tokens.elementAt(4).toString());
810            endColumn = Integer.parseInt(tokens.elementAt(5).toString());
811        }
812        catch (NumberFormatException e)
813        {
814            throw new 
815                UnexpectedReplyException("Can't parse getCrefInfo() reply, "+
816                                         "unexpected format");
817        }
818       
819        return new ElementLocation(filePath, 
820                    startLine, startColumn, endLine, endColumn);
821    }
822   
823    /**
824     * Queries the compiler if a particular modelica class/package is a package.
825     *
826     * @param className fully qualified name of the class/package
827     * @return true if className is a package, false otherwise
828     * @throws ConnectException
829     */
830    public boolean isPackage(String className)
831        throws ConnectException
832    {
833        String retval = sendExpression("isPackage(" + className + ")");
834
835        /* fetch error string but ignore it */
836        getErrorString();
837       
838        return retval.contains("true");
839    }
840   
841    /**
842     * Uses the OMC API call getElementsInfo to fetch lots of information
843     * about a class definition. See interactive_api.txt in the OMC
844     * source tree.
845     * @param className the fully qualified name of a class
846     * @return a <code>Collection</code> (of <code>ElementsInfo</code>)
847     * containing the information about className
848     */
849    public Collection<ElementsInfo> getElementsInfo(String className)
850        throws ConnectException, InvocationError, UnexpectedReplyException
851    {
852        String retval = sendExpression("getElementsInfo("+ className +")");
853       
854        /* fetch error string but ignore it */
855        getErrorString();
856       
857        /*
858         * we need a efficient way to check if the result is
859         * humongosly huge list or 'Error' or maybe 'error'
860         */
861        for (int i = 0; i < retval.length(); i++)
862        {
863            if (retval.charAt(i) == '{')
864            {
865                /*
866                 * we found the begining of the list, send it to parser and
867                 * hope for the best
868                 */
869                List parsedList = ModelicaParser.parseList(retval);
870               
871                /* convert the parsedList to a collection of ElementsInfo:s */
872                LinkedList<ElementsInfo> elementsInfo = 
873                    new LinkedList<ElementsInfo>();
874
875                for (ListElement element : parsedList)
876                {
877                    elementsInfo.add(new ElementsInfo((List)element));
878                }
879               
880                return elementsInfo;
881            }
882            else if (retval.charAt(i) == 'E' || retval.charAt(i) == 'e')
883            {
884                /*
885                 * this is the unreadable way to check if the retval
886                 * equals 'Error' or 'error'
887                 */
888                if (retval.substring(i+1,i+5).equals("rror"))
889                {
890                    throw new 
891                        InvocationError("fetching contents of " + className,
892                                "getElementsInfo("+ className +")");
893                }
894                else
895                {
896                    /* OMC returned someting wierd, panic mode ! */
897                    break;
898                }
899            }
900        }
901        /* we have no idea what OMC returned */
902        throw new UnexpectedReplyException("getElementsInfo("+ className +")" + 
903                        "replies:'" + retval + "'");
904    }
905
906    /**
907     * @return the name of the compiler that this plugin tries to communicate
908     * with (at least it tries...)
909     */
910    public String getCompilerName()
911    {
912        return "OpenModelica Compiler";
913    }
914
915    /**
916     * Loads in the Modelica System Library and returns names of the top-level
917     * packages.
918     * 
919     * @throws ConnectException if we're unable to start communicating with
920     * the server
921     */ 
922    public String[] getStandardLibrary() throws ConnectException
923    {
924        if (!systemLibraryLoaded)
925        {
926            sendExpression("loadModel(Modelica)");
927           
928            /* fetch error string but ignore it */
929            getErrorString();
930           
931            systemLibraryLoaded = true;
932        }
933
934        return standardLibraryPackages;
935    }
936}
Note: See TracBrowser for help on using the repository browser.