001    package nl.cwi.sen1.visbase.rstorecontainer;
002    
003    import java.io.File;
004    import java.io.FileInputStream;
005    import java.io.FileNotFoundException;
006    import java.io.InputStream;
007    import java.util.LinkedHashMap;
008    import java.util.List;
009    import java.util.Map;
010    
011    import nl.cwi.sen1.gui.Studio;
012    import nl.cwi.sen1.gui.plugin.DefaultStudioPlugin;
013    import nl.cwi.sen1.relationstores.Factory;
014    import nl.cwi.sen1.relationstores.types.RElem;
015    import nl.cwi.sen1.relationstores.types.RStore;
016    import nl.cwi.sen1.relationstores.types.RTuple;
017    import nl.cwi.sen1.relationstores.types.relem.Tuple;
018    import nl.cwi.sen1.visbase.rstorecontainer.datatypes.FactInfoList;
019    
020    import org.apache.commons.logging.Log;
021    import org.apache.commons.logging.LogFactory;
022    
023    import aterm.ATerm;
024    import aterm.ATermList;
025    import aterm.pure.PureFactory;
026    
027    /**
028     * Contains the logic needed to communicate RStore data with other
029     * ToolBus-tools.
030     * 
031     * @note Hidden methods are
032     * @c protected instead of
033     * @c private so they can be easily unit-tested from tests in the same package.
034     * 
035     * @author Ricardo Lindooren
036     * @author Arend van Beelen (reviewer)
037     * @date 12-02-2007
038     */
039    public class RStoreContainer extends DefaultStudioPlugin implements
040                    RStoreContainerTif {
041    
042            private RStoreContainerBridge m_bridge;
043    
044            private Studio m_metaStudio;
045    
046            /**
047             * Holds the loaded/parsed RStores
048             */
049            // private Map<Integer, RStore> m_loadedRStoresMap;
050            private Map<Integer, RStoreTracker> m_loadedRStoresMap;
051    
052            /**
053             * Used to track which RStore File's where loaded earlier
054             */
055            private Map<File, Integer> m_earlierLoadedRStoreFilesMap;
056    
057            private static PureFactory m_pureFactory;
058    
059            private static final Log m_log = LogFactory.getLog(RStoreContainer.class);
060    
061            /**
062             * The main method is called by the ToolBus to start the RStoreContainer.
063             * 
064             * @param args
065             *            The arguments passed by the ToolBus.
066             * 
067             * @author Ricardo Lindooren
068             * @author Arend van Beelen (reviewer)
069             * @date 16-02-2007
070             */
071            public static void main(String[] args) {
072                    if (m_log.isDebugEnabled()) {
073                            if (args != null) {
074                                    StringBuilder debugMessage = new StringBuilder();
075                                    debugMessage
076                                                    .append("Starting new RStoreContainer tool with args: ");
077    
078                                    int numArgs = args.length;
079                                    for (int argNum = 0; argNum < numArgs; argNum++) {
080                                            debugMessage.append(args[argNum]);
081    
082                                            if (argNum < numArgs - 1) {
083                                                    debugMessage.append(", ");
084                                            }
085                                    }
086    
087                                    m_log.debug(debugMessage.toString());
088                            } else {
089                                    m_log.debug("Starting new RStoreContainer tool without args.");
090                            }
091                    }
092    
093                    new RStoreContainer(args);
094            }
095    
096            /**
097             * Default constructor.
098             * 
099             * Does not make a connection with the ToolBus.
100             * 
101             * @author Ricardo Lindooren
102             * @author Arend van Beelen (reviewer)
103             * @date 12-02-2007
104             */
105            public RStoreContainer() {
106                    super();
107    
108                    m_log.debug("Default " + RStoreContainer.class.getName()
109                                    + " constructor called");
110    
111                    m_loadedRStoresMap = new LinkedHashMap<Integer, RStoreTracker>();
112                    m_earlierLoadedRStoreFilesMap = new LinkedHashMap<File, Integer>();
113            }
114    
115            /**
116             * Constructor used when started by the ToolBus.
117             * 
118             * Initializes connection to the ToolBus with the RStoreContainerBridge.
119             * 
120             * @param args
121             *            The arguments passed by the ToolBus.
122             * 
123             * @author Ricardo Lindooren
124             * @author Arend van Beelen (reviewer)
125             * @date 17-02-2007
126             */
127            protected RStoreContainer(String[] args) {
128                    super();
129    
130                    m_loadedRStoresMap = new LinkedHashMap<Integer, RStoreTracker>();
131                    m_earlierLoadedRStoreFilesMap = new LinkedHashMap<File, Integer>();
132    
133                    m_log.debug("Running " + RStoreContainer.class.getSimpleName());
134    
135                    try {
136                            m_bridge = new RStoreContainerBridge(getPureFactory(), this);
137                            m_bridge.init(args);
138                            m_bridge.connect();
139                            m_bridge.run();
140                    } catch (Exception exception) {
141                            m_log
142                                            .fatal("Exception during the initialization of the RStoreContainerBridge, see attached cause (can be ignored during JUnit test when there is no ToolBus process present at the moment): "
143                                                            + exception);
144                    }
145            }
146    
147            /**
148             * Returns the name to indentify this tool.
149             * 
150             * @return The string "rStoreContainer".
151             * 
152             * @author Ricardo Lindooren
153             * @author Arend van Beelen (reviewer)
154             * @date 21-02-2007
155             */
156            public String getName() {
157                    return "rStoreContainer";
158            }
159    
160            /**
161             * Initializes and connects this tool when started from the
162             * Meta-Environment.
163             * 
164             * @param metaStudio
165             *            Reference to the Meta-Studio to connect to.
166             * 
167             * @author Ricardo Lindooren
168             * @author Arend van Beelen (reviewer)
169             * @date 21-02-2007
170             */
171            public void initStudioPlugin(Studio metaStudio) {
172                    m_metaStudio = metaStudio;
173    
174                    m_bridge = new RStoreContainerBridge(m_metaStudio.getATermFactory(),
175                                    this);
176    
177                    if (m_metaStudio.getATermFactory() instanceof PureFactory) {
178                            m_log
179                                            .debug("metaStudio.getATermFactory() is an instance of PureFactory. Using this one for the static pureFactory variable.");
180    
181                            m_pureFactory = (PureFactory) m_metaStudio.getATermFactory();
182                    } else {
183                            m_log
184                                            .debug("metaStudio.getATermFactory() isn't an instance of PureFactory");
185                    }
186    
187                    m_metaStudio.connect(getName(), m_bridge);
188            }
189    
190            /**
191             * Called by the RStoreContainerInterface ToolBus process to load an RStore
192             * directly from an ATerm
193             * 
194             * @param filename
195             *            Filename of the RStore file, if it would be written to disk.
196             * @return ATerm containing the generated ID for the RStore in the format
197             * @c snd-value(rc-rstore-loaded(&lt;str filename&gt;,&lt;int ID&gt;)). The
198             *    ID is set to -1 if loading fails.
199             * 
200             * @author Jurgen Vinju
201             */
202            public ATerm rcLoadRstore(String filename, ATerm rstoreData) {
203                    File rStoreFile = new File(filename);
204    
205                    // try to parse the input file to a RStore
206                    RStore parsedRStore = null;
207                    try {
208                            Factory factory = Factory.getInstance(getPureFactory());
209                            parsedRStore = factory.RStoreFromTerm(rstoreData);
210                    } catch (Exception exception) {
211                            m_log
212                                            .error(
213                                                            "Unexpected exception while trying to parse the RStore file (see cause): ",
214                                                            exception);
215                    }
216    
217                    int rStoreId = -1;
218                    if (parsedRStore != null) {
219                            // add parsed RStore to loaded RStores so it can be retrieved later
220                            // on
221                            rStoreId = registerRStore(rStoreFile, parsedRStore);
222    
223                            m_log.debug("Registered RStore with id: " + rStoreId);
224    
225                    } else {
226                            m_log.warn("Could not register RStore, returning id: " + rStoreId);
227                    }
228    
229                    ATerm result = getPureFactory().make(
230                                    "snd-value(rc-rstore-loaded(<str>,<int>))", filename,
231                                    new Integer(rStoreId));
232                    return result;
233    
234            }
235    
236            /**
237             * Called by the RStoreContainerInterface ToolBus process to load an RStore
238             * file.
239             * 
240             * @param filename
241             *            Filename of the RStore file to load.
242             * @return ATerm containing the generated ID for the RStore in the format
243             * @c snd-value(rc-rstore-loaded(&lt;str filename&gt;,&lt;int ID&gt;)). The
244             *    ID is set to -1 if loading fails.
245             * 
246             * @author Ricardo Lindooren
247             * @author Arend van Beelen (reviewer)
248             * @date 2007-02-16
249             */
250            public ATerm rcLoadRstore(String filename) {
251                    if (m_log.isDebugEnabled()) {
252                            m_log.debug("argument: " + filename);
253                    }
254    
255                    File rStoreFile = new File(filename);
256    
257                    // try to parse the input file to a RStore
258                    RStore parsedRStore = null;
259                    try {
260                            InputStream inputStream = inputStreamFromFile(rStoreFile);
261                            parsedRStore = parseRStore(inputStream);
262                    } catch (FileNotFoundException exception) {
263                            m_log.error("File not found!");
264                    } catch (Exception exception) {
265                            m_log
266                                            .error(
267                                                            "Unexpected exception while trying to parse the RStore file (see cause): ",
268                                                            exception);
269                    }
270    
271                    // check parsed RStore result again for safety
272                    int rStoreId = -1;
273                    if (parsedRStore != null) {
274    
275                            // add parsed RStore to loaded RStores so it can be retrieved later
276                            // on
277                            rStoreId = registerRStore(rStoreFile, parsedRStore);
278    
279                            m_log.debug("Registered RStore with id: " + rStoreId);
280    
281                    } else {
282                            m_log.warn("Could not register RStore, returning id: " + rStoreId);
283                    }
284    
285                    ATerm result = getPureFactory().make(
286                                    "snd-value(rc-rstore-loaded(<str>,<int>))", filename,
287                                    new Integer(rStoreId));
288                    return result;
289            }
290    
291            /**
292             * Called by the RStoreContainerInterface ToolBus process to load the facts
293             * from an earlier loaded RStore file.
294             * 
295             * @param id
296             *            ID of the loaded RStore file.
297             * @return ATermList containing the ID's of the facts in the loaded RStore
298             *         in the format
299             * @c snd-value(rc-rstore-facts(&lt;list ID's&gt;)). The list will be empty
300             *    if the RStore was not loaded.
301             * 
302             * @author Ricardo Lindooren
303             * @author Arend van Beelen (reviewer)
304             * @date 2007-02-16
305             */
306            public ATerm rcGetRstoreFacts(int id) {
307                    m_log.debug("argument: " + id);
308    
309                    RStoreTracker earlierLoadedRStoreTracker = m_loadedRStoresMap
310                                    .get(new Integer(id));
311    
312                    ATermList factIds = null;
313                    if (earlierLoadedRStoreTracker != null) {
314    
315                            FactInfoList factsList = earlierLoadedRStoreTracker
316                                            .getFactInfoFromRStore();
317    
318                            factIds = factsList.toATermList();
319                    } else {
320                            m_log.warn("RStore didn't exist for ID: " + id
321                                            + " (returning empty facts list)");
322    
323                            // create empty list
324                            factIds = getPureFactory().makeList();
325                    }
326    
327                    ATerm resultList = getPureFactory().make(
328                                    "snd-value(rc-rstore-facts(<list>))", factIds);
329                    return resultList;
330            }
331    
332            /**
333             * Called by the RStoreContainerInterface ToolBus process to load the data
334             * belonging to a fact from an earlier loaded RStore file.
335             * 
336             * @param rStoreId
337             *            ID of the loaded RStore file.
338             * @param factId
339             *            ID of the fact to load.
340             * @return ATerm containing the fact data in the format
341             * @c snd-value(rc-fact-data(&lt;term fact-data&gt;)). A fake empty data set
342             *    is returned if the fact does not exist.
343             * 
344             * @author Ricardo Lindooren
345             * @author Arend van Beelen (reviewer)
346             * @date 2007-02-20
347             */
348            public ATerm rcGetFactData(int rStoreId, int factId) {
349                    m_log.debug("arguments: " + rStoreId + ", " + factId);
350    
351                    RStoreTracker earlierLoadedRStoreTracker = m_loadedRStoresMap
352                                    .get(new Integer(rStoreId));
353    
354                    ATerm factData = null;
355                    if (earlierLoadedRStoreTracker != null) {
356    
357                            RTuple factTuple = earlierLoadedRStoreTracker.getRTuple(factId);
358    
359                            if (factTuple != null) {
360                                    factData = factTuple.toTerm();
361                            } else {
362                                    m_log.warn("Fact (RTuple) didn't exist for ID: " + factId);
363                            }
364                    } else {
365                            m_log.warn("RStore didn't exist for ID: " + rStoreId
366                                            + ". Valid ID's are: " + m_loadedRStoresMap.keySet());
367                    }
368    
369                    if (factData == null) {
370                            factData = createDummyFactData();
371                    }
372    
373                    ATerm result = getPureFactory().make("snd-value(rc-fact-data(<term>))",
374                                    factData);
375                    return result;
376            }
377    
378            /**
379             * Called by the RStoreContainerInterface ToolBus process to unload an
380             * earlier loaded RStore
381             * 
382             * @param id
383             *            the ID of the earlier loaded RStore
384             * 
385             * @return the message <code>snd-value(rc-rstore-unloaded(<int>))</code>
386             * 
387             * @author Ricardo Lindooren
388             * @Date 2007-03-14
389             */
390            public ATerm rcUnloadRstore(int id) {
391                    m_log.debug("argument: " + id);
392    
393                    Integer nrIdentifier = new Integer(id);
394    
395                    if (m_loadedRStoresMap.containsKey(nrIdentifier)) {
396    
397                            // Delete corresponding entry from earlier loader RStoreTrackers map
398                            m_loadedRStoresMap.remove(nrIdentifier);
399    
400                            /* Delete corresponding entry from earlier loaded files map */
401    
402                            Integer storedIdentifier = null;
403                            File storedFileReference = null;
404    
405                            // search for entry
406                            for (File file : m_earlierLoadedRStoreFilesMap.keySet()) {
407                                    storedIdentifier = m_earlierLoadedRStoreFilesMap.get(file);
408    
409                                    // check if we got a RStore(Tracker) and this is the
410                                    // RStore(Tracker) we are looking for
411                                    if (storedIdentifier != null
412                                                    && storedIdentifier.equals(nrIdentifier)) {
413                                            storedFileReference = file;
414                                            break;
415                                    }
416                            }
417    
418                            // remove the file reference (do this outside the for-loop)
419                            if (storedFileReference != null) {
420    
421                                    m_log.debug("Unloading RStore with identifier, id: "
422                                                    + storedIdentifier + ", file: " + storedFileReference);
423    
424                                    m_earlierLoadedRStoreFilesMap.remove(storedFileReference);
425                            }
426                    } else {
427                            nrIdentifier = new Integer(-1);
428    
429                            m_log.warn("No earlier loaded RStore for identifier: "
430                                            + nrIdentifier + ". *Returning -1*");
431                    }
432    
433                    ATerm resultList = getPureFactory().make(
434                                    "snd-value(rc-rstore-unloaded(<int>))", nrIdentifier);
435    
436                    return resultList;
437            }
438    
439            /**
440             * Called by the RStoreContainerInterface ToolBus process when the
441             * fact-update event is received
442             * 
443             * @author Ricardo Lindooren
444             * @Date 2007-03-14
445             */
446            public void recAckEvent(ATerm t0) {
447                    m_log.debug("argument: " + t0);
448            }
449    
450            /**
451             * Creates dummy fact data which is used when no data can be loaded.
452             * 
453             * @return An ATerm containing a tuple with two empty strings.
454             * 
455             * @author Arend van Beelen
456             * @date 06-03-2007
457             */
458            public static ATerm createDummyFactData() {
459                    Factory factory = Factory.getInstance(getPureFactory());
460    
461                    RElem emptyString = factory.makeRElem_Str("");
462                    Tuple tuple = factory.makeRElem_Tuple(factory.makeRElemElements(
463                                    emptyString, emptyString));
464                    RElem rElem = factory.makeRElem_Set(factory.makeRElemElements(tuple));
465                    ATerm factData = rElem.toTerm();
466    
467                    return factData;
468            }
469    
470            /**
471             * Handles terminate message.
472             * 
473             * @param message
474             *            The received message.
475             * 
476             * @author Ricardo Lindooren
477             * @author Arend van Beelen (reviewer)
478             * @date 20-02-2007
479             */
480            public void recTerminate(ATerm message) {
481                    m_log.debug("Received terminate message: " + message + ".");
482    
483                    fireStudioPluginClosed();
484    
485                    m_bridge = null;
486                    m_metaStudio = null;
487            }
488    
489            /**
490             * Returns the PureFactory object used by this class.
491             * 
492             * This class uses a single static instance of the PureFactory.
493             * 
494             * Reason for doing this is the Factory stays alive independently from this
495             * class. The Factory doesn't like it when a new instance is created with a
496             * new PureFactory.
497             * 
498             * @return The static PureFactory instance for this class.
499             * 
500             * @author Ricardo Lindooren
501             * @author Arend van Beelen (reviewer)
502             * @date 14-02-2007
503             */
504            public static synchronized PureFactory getPureFactory() {
505                    if (m_pureFactory == null) {
506                            m_log.debug("Created the static PureFactory.");
507    
508                            m_pureFactory = new PureFactory();
509                    }
510                    return m_pureFactory;
511            }
512    
513            /**
514             * Returns the mapping from ID's to the loaded RStoreTrackers.
515             * 
516             * @return The map containing all loaded RStores.
517             * 
518             * @author Ricardo Lindooren
519             * @author Arend van Beelen (reviewer)
520             * @date 14-02-2007
521             */
522            public Map<Integer, RStoreTracker> getLoadedRStoreTrackersMap() {
523                    return m_loadedRStoresMap;
524            }
525    
526            /**
527             * Returns the mapping from RStore filenames to ID's (belonging to the
528             * loaded RStoreTrackers).
529             * 
530             * @see #getLoadedRStoreTrackersMap()
531             * 
532             * @return The map containing all loaded RStores.
533             * 
534             * @author Ricardo Lindooren
535             * @date 2007-03-14
536             */
537            public Map<File, Integer> getLoadedRStoreFilesMap() {
538                    return m_earlierLoadedRStoreFilesMap;
539            }
540    
541            /**
542             * Creates an InputStream object for the given file.
543             * 
544             * This is very generic code, not limited to be used by this class only. It
545             * could be promoted to a static method (in a Helper/Util kind of class for
546             * example).
547             * 
548             * @param file
549             *            File to create an input stream for.
550             * @return A new FileInputStream object for the input File.
551             * 
552             * @throws RuntimeException
553             *             if the input stream is null.
554             * @throws FileNotFoundException
555             *             if the input File cannot be found.
556             * 
557             * @author Ricardo Lindooren
558             * @author Arend van Beelen (reviewer)
559             * @date 12-02-2007
560             */
561            protected InputStream inputStreamFromFile(File file)
562                            throws FileNotFoundException {
563                    if (file == null) {
564                            throw new RuntimeException("Input file should not be null.");
565                    }
566    
567                    InputStream inputStream = new FileInputStream(file);
568                    return inputStream;
569            }
570    
571            /**
572             * Parses RStore data from an input stream.
573             * 
574             * @param inputStream
575             *            The input stream to parse.
576             * @return The parsed RStore.
577             * 
578             * @throws RuntimeException
579             *             if the input stream is null.
580             * @throws RStoreParseException
581             *             if parsing of RStore input fails.
582             * 
583             * @author Ricardo Lindooren
584             * @author Arend van Beelen (reviewer)
585             * @date 12-02-2007
586             */
587            protected RStore parseRStore(InputStream inputStream)
588                            throws RStoreParseException {
589                    if (inputStream == null) {
590                            throw new RuntimeException("Input stream should not be null.");
591                    }
592    
593                    RStore parsedRStore = null;
594    
595                    try {
596                            Factory factory = Factory.getInstance(getPureFactory());
597    
598                            parsedRStore = factory.RStoreFromFile(inputStream);
599                    } catch (Exception exception) {
600                            throw new RStoreParseException(
601                                            "Parsing of RStore data failed (see cause)", exception);
602                    }
603    
604                    return parsedRStore;
605            }
606    
607            /**
608             * Registers a loaded RStore in the RStores map.
609             * 
610             * @param rStoreFileReference
611             *            the reference to the File that was used to create the RStore
612             * @param rStore
613             *            The RStore to register.
614             * 
615             * @return The ID assigned to the RStore in the map.
616             * 
617             * @throws RuntimeException
618             *             if File and/or RStore input is null.
619             * 
620             * @author Ricardo Lindooren
621             * @author Arend van Beelen (reviewer)
622             * @date 14-02-2007
623             */
624            protected int registerRStore(File rStoreFileReference, RStore rStore) {
625                    if (rStoreFileReference == null) {
626                            throw new RuntimeException("File input should not be null");
627                    }
628                    if (rStore == null) {
629                            throw new RuntimeException("RStore input should not be null");
630                    }
631    
632                    // Default is a fake value
633                    int result_id = -1;
634    
635                    // Check if the File was loaded earlier
636                    if (m_earlierLoadedRStoreFilesMap.containsKey(rStoreFileReference)) {
637                            m_log.debug("RStore file has been loaded earlier: "
638                                            + rStoreFileReference + ". *Updating if needed*");
639                            
640                            // Get the identifier for this earlier loaded RStore
641                            Integer idOfEarlierLoadedRStore = m_earlierLoadedRStoreFilesMap
642                                            .get(rStoreFileReference);
643    
644                            // Get the RStore Tracker
645                            RStoreTracker rStoreTrackerForEarlierLoadedRStore = m_loadedRStoresMap
646                                            .get(idOfEarlierLoadedRStore);
647    
648                            // Update the Tracker with the newly parsed RStore data
649                            List<Integer> updatedFactIdsList = rStoreTrackerForEarlierLoadedRStore
650                                            .update(rStore);
651                            
652                            // Send updates for changed facts (if any)
653                            sendFactUpdatedEvents(idOfEarlierLoadedRStore, updatedFactIdsList);
654                            
655                            result_id = idOfEarlierLoadedRStore.intValue();
656                    } else {
657                            // find a unique ID for the RStore in the map
658                            int id = m_loadedRStoresMap.size() + 1;
659                            while (m_loadedRStoresMap.get(new Integer(id)) != null) {
660                                    m_log
661                                                    .warn("Suggested ID for RStore already existed in loadedRStoresMap: "
662                                                                    + id);
663                                    id++;
664                            }
665    
666                            // Create a new RStoreTracker
667                            RStoreTracker newRStoreTracker = new RStoreTracker(rStore);
668    
669                            Integer newNrIdentifier = new Integer(id);
670    
671                            m_earlierLoadedRStoreFilesMap.put(rStoreFileReference,
672                                            newNrIdentifier);
673                            m_loadedRStoresMap.put(newNrIdentifier, newRStoreTracker);
674    
675                            result_id = id;
676                    }
677    
678                    return result_id;
679            }
680    
681            /**
682             * Sends <code>snd-event(rc-fact-updated(<int>,<int>))</code> messages
683             * (RStore,FactId) over the toolbus
684             * 
685             * @param rStoreId
686             *            the ID of the RStore to which the updated facts belong
687             * @param updatedFactIds
688             *            a list of ID's of updated facts
689             * 
690             * @throws RuntimeException
691             *             if input is null.
692             * 
693             * @author Ricardo Lindooren
694             * @date 2007-03-13
695             */
696            protected void sendFactUpdatedEvents(Integer rStoreId,
697                            List<Integer> updatedFactIds) {
698                    if (rStoreId == null) {
699                            throw new RuntimeException("rStoreId input should not be null");
700                    }
701                    if (updatedFactIds == null) {
702                            throw new RuntimeException(
703                                            "updatedFactIds input should not be null");
704                    }
705    
706                    for (Integer updatedFactId : updatedFactIds) {
707    
708                            ATerm updatedFactEvent = getPureFactory().make(
709                                            "rc-fact-updated(<int>,<int>)", rStoreId, updatedFactId);
710    
711                            if (m_bridge != null) {
712                                    m_log.debug("Sending this updatedFact-event as term: "
713                                                    + updatedFactEvent);
714    
715                                    m_bridge.postEvent(updatedFactEvent);
716    
717                            } else {
718                                    m_log
719                                                    .warn("There is no bridge, cannot send this updatedFact-event: "
720                                                                    + updatedFactEvent);
721                            }
722                    }
723            }
724    
725            /**
726             * Returns the RStore for RStoreId
727             * 
728             * @param rStoreId
729             *            the ID of the RStore to retrieve
730             * 
731             * @author Taeke Kooiker
732             * @date 2007-08-14
733             */
734            public ATerm rcGetRstore(int rStoreId) {
735                    RStoreTracker tracker = m_loadedRStoresMap.get(rStoreId);
736                    ATerm term = m_metaStudio.getATermFactory().make(
737                                    "snd-value(rc-rstore(<term>))", tracker.getRStore().toTerm());
738                    return term;
739            }
740    
741    }