001    package toolbus;
002    
003    import toolbus.logging.ILogger;
004    import toolbus.logging.IToolBusLoggerConstants;
005    import toolbus.logging.LoggerFactory;
006    import toolbus.tool.ToolInstance;
007    import toolbus.util.collections.ConcurrentHashMap;
008    import toolbus.util.collections.ConcurrentHashSet;
009    import toolbus.util.collections.EntryHandlerConstants;
010    import toolbus.util.collections.ConcurrentHashMap.HashMapEntryHandler;
011    import toolbus.util.collections.ConcurrentHashMap.ReadOnlyHashMapEntryHandler;
012    import toolbus.util.collections.ConcurrentHashSet.HashSetEntryHandler;
013    import toolbus.util.collections.ConcurrentHashSet.ReadOnlyHashSetEntryHandler;
014    import aterm.ATerm;
015    
016    /**
017     * This class manages all the tool instances.
018     * 
019     * @author Arnold Lankamp
020     */
021    public class ToolInstanceManager{
022            private final ConcurrentHashMap<ATerm, ToolInstance> activeTools;
023            private final ConcurrentHashMap<ATerm, ToolInstance> pendingTools;
024            private final ConcurrentHashSet<ToolInstance> dynamiclyConnectedTools;
025            
026            /**
027             * Default constructor.
028             */
029            public ToolInstanceManager(){
030                    super();
031    
032                    activeTools = new ConcurrentHashMap<ATerm, ToolInstance>();
033                    pendingTools = new ConcurrentHashMap<ATerm, ToolInstance>();
034                    dynamiclyConnectedTools = new ConcurrentHashSet<ToolInstance>();
035            }
036            
037            /**
038             * Returns the tool with the given id, if it's present in the collection.
039             * 
040             * @param toolKey
041             *            The key of the tool we want to retrieve.
042             * @return The tool instance associated with the given id.
043             */
044            public ToolInstance get(ATerm toolKey){
045                    return activeTools.get(toolKey);
046            }
047            
048            /**
049             * Removes the tool instance that is associated with the given id from the collection.
050             * 
051             * @param toolKey
052             *            The key of the tool instance that we want to remove.
053             */
054            public void remove(ATerm toolKey){
055                    activeTools.remove(toolKey);
056            }
057            
058            /**
059             * Adds a connect tool instance to the collection. Connected tools are tools that are connected
060             * but are not being used by any process yet.
061             * 
062             * @param toolInstance
063             *            The pending tool instance we want to add.
064             */
065            public void addDynamiclyConnectedTool(ToolInstance toolInstance){
066                    dynamiclyConnectedTools.put(toolInstance);
067            }
068            
069            /**
070             * Activates and returns a tool instance of the given type. This method moves the found tool
071             * instance from the dynamicly connected collection to the active collection.
072             * 
073             * @param toolName
074             *            The name identifying the type of the tool instance.
075             * @return The tool instance that was activated; if none is found NULL will be returned.
076             */
077            public ToolInstance activateDynamiclyConnectedTool(String toolName){
078                    // Find a dynamicly connected tool that's ready for use.
079                    ToolInstance toolInstance = getReadyDynamiclyConnectedTool(toolName);
080                    
081                    // Move the tool to the active tool collection (if the correct dyncamicly connected tool
082                    // was found).
083                    if(toolInstance != null){
084                            activeTools.put(toolInstance.getToolKey(), toolInstance);
085                    }
086                    
087                    return toolInstance;
088            }
089            
090            /**
091             * Attempts to locate a dynamicly connected tool instance that is ready to be processed by the
092             * 'connect atom'.
093             * 
094             * @param toolName
095             *            The name of the tool.
096             * @return The located tool instance (if present); if none is found NULL will be returned.
097             */
098            private ToolInstance getReadyDynamiclyConnectedTool(final String toolName){
099                    class DynamicToolsIterationHandler extends HashSetEntryHandler<ToolInstance>{
100                            public ToolInstance toolInstance = null;
101                            
102                            public int handle(ToolInstance ti){
103                                    if(ti.isConnected() && ti.getToolKey().getAFun().getName().equals(toolName)){
104                                            toolInstance = ti;
105                                            return EntryHandlerConstants.BREAK | EntryHandlerConstants.REMOVE;
106                                    }
107                                    
108                                    return EntryHandlerConstants.CONTINUE;
109                            }
110                    }
111                    DynamicToolsIterationHandler dynamicToolsIterationHandler = new DynamicToolsIterationHandler();
112                    dynamiclyConnectedTools.iterate(dynamicToolsIterationHandler);
113                    
114                    return dynamicToolsIterationHandler.toolInstance;
115            }
116            
117            /**
118             * Removes the given tool instance from the dynamicly connected tools list (if present).
119             * 
120             * @param toolInstance
121             *            The tool instance that needs to be removed.
122             */
123            public void removeDynamiclyConnectedTool(ToolInstance toolInstance){
124                    dynamiclyConnectedTools.remove(toolInstance);
125            }
126            
127            /**
128             * Adds a tool instance to the list of which the tool application is currently being started.
129             * 
130             * @param toolInstance
131             *            The tool instance we want to add.
132             */
133            public void addPendingTool(ToolInstance toolInstance){
134                    pendingTools.put(toolInstance.getToolKey(), toolInstance);
135            }
136            
137            /**
138             * Returns the tool with the given key, if it's present in the pending tool collection.
139             * 
140             * @param toolKey
141             *            The key of the tool we want to retrieve.
142             * @return The tool instance associated with the given id.
143             */
144            public ToolInstance getPendingTool(ATerm toolKey){
145                    return pendingTools.get(toolKey);
146            }
147            
148            /**
149             * Attempts to activate the tool instance associated with the given key. If the tool instance
150             * associated with the given key is ready / connected, it will moved it to the activated
151             * collection.
152             * 
153             * @param toolKey
154             *            The key of the tool that has connected.
155             * @return The tool instance that was activated; if the tool instance associated with the given
156             *         key is not connected / ready, NULL will be returned.
157             */
158            public ToolInstance activatePendingTool(ATerm toolKey){
159                    ToolInstance toolInstance = pendingTools.get(toolKey);
160                    
161                    if(toolInstance == null){
162                            LoggerFactory.log("Unable to locate pending tool with id: "+toolKey+".", ILogger.ERROR, IToolBusLoggerConstants.TOOLINSTANCE);
163                            return null;
164                    }
165                    
166                    if(!toolInstance.isConnected()) return null;
167                    
168                    toolInstance = pendingTools.remove(toolKey);
169                    if(toolInstance == null){
170                            LoggerFactory.log("Pending tool with id: "+toolKey+" disappeared; huh where did it go, it was here a moment ago....", ILogger.ERROR, IToolBusLoggerConstants.TOOLINSTANCE);
171                            return null;
172                    }
173                    
174                    activeTools.put(toolKey, toolInstance);
175                    
176                    return toolInstance;
177            }
178            
179            /**
180             * Removes the given tool instance from the pending tools list (if present).
181             * 
182             * @param toolKey
183             *            The key that is associated with the tool instance that needs to be removed.
184             */
185            public void removePendingTool(ATerm toolKey){
186                    pendingTools.remove(toolKey);
187            }
188            
189            /**
190             * Notifies all tools that the ToolBus was shut down, by sending a terminate(\<term\>) message.
191             * 
192             * @param message
193             *            The message that will be encapsulated in the terminate message.
194             */
195            public void shutDown(final ATerm message){
196                    // Shut down the active tools.
197                    HashMapEntryHandler<ATerm, ToolInstance> activeToolsIterationHandler = new ReadOnlyHashMapEntryHandler<ATerm, ToolInstance>(){
198                            public int handle(ATerm toolKey, ToolInstance toolInstance){
199                                    toolInstance.sendTerminate(message);
200                                    
201                                    return EntryHandlerConstants.CONTINUE;
202                            }
203                    };
204                    activeTools.iterate(activeToolsIterationHandler);
205                    
206                    // Don't attempt to terminate the pending tools, since they are not connected.
207                    
208                    // Shut down the dynamicly connected tools.
209                    HashSetEntryHandler<ToolInstance> dynamicToolsIterationHandler = new ReadOnlyHashSetEntryHandler<ToolInstance>(){
210                            public int handle(ToolInstance toolInstance){
211                                    toolInstance.sendTerminate(message);
212                                    
213                                    return EntryHandlerConstants.CONTINUE;
214                            }
215                    };
216                    dynamiclyConnectedTools.iterate(dynamicToolsIterationHandler);
217            }
218            
219            /**
220             * Kills all known executed tools immidiately.
221             */
222            public void killExecutedToolsNow(){
223                    HashMapEntryHandler<ATerm, ToolInstance> toolsIterationHandler = new ReadOnlyHashMapEntryHandler<ATerm, ToolInstance>(){
224                            public int handle(ATerm toolKey, ToolInstance toolInstance){
225                                    toolInstance.kill();
226                                    
227                                    return EntryHandlerConstants.CONTINUE;
228                            }
229                    };
230                    
231                    // Kill the active tools.
232                    activeTools.iterate(toolsIterationHandler);
233                    
234                    // Kill the pending tools.
235                    pendingTools.iterate(toolsIterationHandler);
236                    
237                    // We can't kill dynamicly connected tools.
238                    // The ToolBus adapter will terminate the tool as soon as it finds out the connection with the ToolBus is lost.
239            }
240            
241            /**
242             * Counts the number of connected tools that are registered with this tool instance manager.
243             * 
244             * @return The number of connected tools that are registered with this tool instance manager.
245             */
246            public int numberOfConnectedTools(){
247                    return (activeTools.size() + dynamiclyConnectedTools.size());
248            }
249            
250            /**
251             * Prints all currently queued values, events and requests.
252             */
253            public void printQueueTerms(){
254                    HashMapEntryHandler<ATerm, ToolInstance> activeToolsIterationHandler = new ReadOnlyHashMapEntryHandler<ATerm, ToolInstance>(){
255                            public int handle(ATerm toolKey, ToolInstance toolInstance){
256                                    ATerm[] queuedValues = toolInstance.getQueuedValues();
257                                    ATerm[] queuedEvents = toolInstance.getQueuedEvents();
258                                    ATerm[] queuedRequests = toolInstance.getQueuedRequests();
259                                    
260                                    int nrOfQueueValues = queuedValues.length;
261                                    int nrOfQueueEvents = queuedEvents.length;
262                                    int nrOfQueuedRequests = queuedRequests.length;
263                                    
264                                    if((nrOfQueueValues + nrOfQueueEvents + nrOfQueuedRequests) > 0){
265                                            System.err.println(toolKey+":");
266                                            
267                                            for(int i = nrOfQueueValues - 1; i >= 0; i--){
268                                                    System.err.println("rec-value("+queuedValues[i]+")");
269                                            }
270                                            
271                                            for(int i = nrOfQueueEvents - 1; i >= 0; i--){
272                                                    System.err.println("rec-event("+queuedEvents[i]+")");
273                                            }
274                                            
275                                            for(int i = nrOfQueuedRequests - 1; i >= 0; i--){
276                                                    System.err.println("rec-request("+queuedRequests[i]+")");
277                                            }
278                                    }
279                                    
280                                    return EntryHandlerConstants.CONTINUE;
281                            }
282                    };
283                    activeTools.iterate(activeToolsIterationHandler);
284            }
285            
286            public void showStatus(){
287                    // Show the active tools.
288                    HashMapEntryHandler<ATerm, ToolInstance> activeToolsIterationHandler = new ReadOnlyHashMapEntryHandler<ATerm, ToolInstance>(){
289                            public int handle(ATerm toolKey, ToolInstance toolInstance){
290                                    System.err.println("A: " + toolInstance.showStatus());
291                                    
292                                    return EntryHandlerConstants.CONTINUE;
293                            }
294                    };
295                    activeTools.iterate(activeToolsIterationHandler);
296                    
297                    // Show the pending tools.
298                    HashMapEntryHandler<ATerm, ToolInstance> pendingToolsIterationHandler = new ReadOnlyHashMapEntryHandler<ATerm, ToolInstance>(){
299                            public int handle(ATerm toolKey, ToolInstance toolInstance){
300                                    System.err.println("P: " + toolInstance.showStatus());
301                                    
302                                    return EntryHandlerConstants.CONTINUE;
303                            }
304                    };
305                    pendingTools.iterate(pendingToolsIterationHandler);
306                    
307                    // Show the dynamicly connected tools.
308                    HashSetEntryHandler<ToolInstance> dynamicToolsIterationHandler = new ReadOnlyHashSetEntryHandler<ToolInstance>(){
309                            public int handle(ToolInstance toolInstance){
310                                    System.err.println("D: " + toolInstance.showStatus());
311                                    
312                                    return EntryHandlerConstants.CONTINUE;
313                            }
314                    };
315                    dynamiclyConnectedTools.iterate(dynamicToolsIterationHandler);
316            }
317    }