001    // This file is part of the program FRYSK.
002    //
003    // Copyright 2005, Red Hat Inc.
004    //
005    // FRYSK is free software; you can redistribute it and/or modify it
006    // under the terms of the GNU General Public License as published by
007    // the Free Software Foundation; version 2 of the License.
008    //
009    // FRYSK is distributed in the hope that it will be useful, but
010    // WITHOUT ANY WARRANTY; without even the implied warranty of
011    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012    // General Public License for more details.
013    // 
014    // You should have received a copy of the GNU General Public License
015    // along with FRYSK; if not, write to the Free Software Foundation,
016    // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
017    // 
018    // In addition, as a special exception, Red Hat, Inc. gives You the
019    // additional right to link the code of FRYSK with code not covered
020    // under the GNU General Public License ("Non-GPL Code") and to
021    // distribute linked combinations including the two, subject to the
022    // limitations in this paragraph. Non-GPL Code permitted under this
023    // exception must only link to the code of FRYSK through those well
024    // defined interfaces identified in the file named EXCEPTION found in
025    // the source code files (the "Approved Interfaces"). The files of
026    // Non-GPL Code may instantiate templates or use macros or inline
027    // functions from the Approved Interfaces without causing the
028    // resulting work to be covered by the GNU General Public
029    // License. Only Red Hat, Inc. may make changes or additions to the
030    // list of Approved Interfaces. You must obey the GNU General Public
031    // License in all respects for all of the FRYSK code and other code
032    // used in conjunction with FRYSK except the Non-GPL Code covered by
033    // this exception. If you modify this file, you may extend this
034    // exception to your version of the file, but you are not obligated to
035    // do so. If you do not wish to provide this exception without
036    // modification, you must delete this exception statement from your
037    // version and license this file solely under the GPL without
038    // exception.
039    
040    
041    package frysk.gui.monitor.observers;
042    
043    import java.util.Iterator;
044    import java.util.List;
045    import java.util.logging.Level;
046    
047    import org.jdom.Element;
048    
049    import frysk.gui.dialogs.DialogManager;
050    import frysk.gui.monitor.Combo;
051    import frysk.gui.monitor.EventLogger;
052    import frysk.gui.monitor.GuiObject;
053    import frysk.gui.monitor.GuiTask;
054    import frysk.gui.monitor.ObservableLinkedList;
055    import frysk.gui.monitor.SaveableXXX;
056    import frysk.gui.monitor.actions.ActionPoint;
057    import frysk.gui.monitor.actions.GenericActionPoint;
058    import frysk.gui.monitor.eventviewer.EventManager;
059    import frysk.gui.monitor.filters.Filter;
060    import frysk.gui.monitor.filters.FilterPoint;
061    import frysk.proc.Action;
062    import frysk.proc.Task;
063    import frysk.proc.TaskObserver;
064    
065    /**
066     * A more sophisticated implementer of Observer. provides name and tool tip
067     * strings for GUI display purposes. Takes Action objects that can be used by
068     * clients to customize behaviour.
069     */
070    public class ObserverRoot
071        extends GuiObject
072        implements TaskObserver, SaveableXXX
073    {
074    
075      private ObservableLinkedList actions;
076    
077      private String info;
078    
079      private ObservableLinkedList filterPoints;
080    
081      private ObservableLinkedList actionPoints;
082    
083      private final String baseName;
084    
085      public GenericActionPoint genericActionPoint;
086    
087      private frysk.proc.Action returnAction;
088    
089      protected ObserverRoot ()
090      {
091        super();
092    
093        this.actions = new ObservableLinkedList();
094        this.info = new String();
095        this.filterPoints = new ObservableLinkedList();
096        this.actionPoints = new ObservableLinkedList();
097        this.baseName = "";
098    
099        this.returnAction = Action.CONTINUE;
100    
101        this.genericActionPoint = new GenericActionPoint(" ",
102                                                         "Actions that dont take any arguments");
103        this.addActionPoint(genericActionPoint);
104      }
105    
106      protected ObserverRoot (String name, String toolTip)
107      {
108        super(name, toolTip);
109    
110        this.actions = new ObservableLinkedList();
111        this.info = new String();
112        this.filterPoints = new ObservableLinkedList();
113        this.actionPoints = new ObservableLinkedList();
114        this.baseName = name;
115    
116        this.returnAction = Action.CONTINUE;
117    
118        this.genericActionPoint = new GenericActionPoint(" ",
119                                                         "Actions that dont take any arguments");
120        this.addActionPoint(genericActionPoint);
121      }
122    
123      protected ObserverRoot (ObserverRoot other)
124      {
125        super(other);
126    
127        this.actions = new ObservableLinkedList(other.actions, true);
128        this.info = new String(other.info);
129        this.filterPoints = new ObservableLinkedList(); // do not copy..
130        this.actionPoints = new ObservableLinkedList(); // ... because children
131                                                            // will readd items
132        this.baseName = other.baseName;
133    
134        this.returnAction = other.returnAction;
135    
136        this.genericActionPoint = new GenericActionPoint(other.genericActionPoint);
137        this.addActionPoint(genericActionPoint);
138      }
139    
140      public void addFailed (Object o, Throwable w)
141      {
142    
143        EventLogger.logAddFailed("addFailed(Object o, Throwable w)", o);
144        throw new RuntimeException("Failed to add " + this + " to " + o, w);
145      }
146    
147      /**
148             * Could be called by an action during the update call to get print
149             * generic information about the event that just occurred format (as
150             * currently used by logger): PID 123 did action ACTION on Host HOST
151             */
152      public String getInfo ()
153      {
154        return info;
155      }
156    
157      /**
158             * Should be called whent the observer has fired. Every time this is
159             * called it sends a message to the logs, so it should only be called
160             * once every time the information changes
161             * 
162             * @param info info string to be set
163             */
164      protected void setInfo (String info)
165      {
166        EventLogger.theLogger.getEventLogger().log(Level.INFO, info);
167        this.info = info;
168      }
169    
170      protected void runActions ()
171      {
172        this.genericActionPoint.runActions(this);
173      }
174    
175      public ObservableLinkedList getFilterPoints ()
176      {
177        return this.filterPoints;
178      }
179    
180      public ObservableLinkedList getActionPoints ()
181      {
182        return this.actionPoints;
183      }
184    
185      protected void addFilterPoint (FilterPoint filterPoint)
186      {
187        this.filterPoints.add(filterPoint);
188      }
189    
190      protected void addActionPoint (ActionPoint actionPoint)
191      {
192        this.actionPoints.add(actionPoint);
193      }
194    
195      public String getBaseName ()
196      {
197        return baseName;
198      }
199    
200      private void saveReturnAction (Element node)
201      {
202        if (this.getCurrentAction() == null)
203          {
204            node.setAttribute("returnAction", "null");
205            return;
206          }
207        if (this.getCurrentAction() == Action.BLOCK)
208          {
209            node.setAttribute("returnAction", Action.BLOCK.toString());
210            return;
211          }
212        if (this.getCurrentAction() == Action.CONTINUE)
213          {
214            node.setAttribute("returnAction", Action.CONTINUE.toString());
215            return;
216          }
217      }
218    
219      private Action loadReturnAction (Element node)
220      {
221        String actionString = node.getAttributeValue("returnAction");
222    
223        if (actionString.equals("null"))
224          {
225            return null;
226          }
227        if (actionString.equals(Action.BLOCK.toString()))
228          {
229            return Action.BLOCK;
230          }
231        if (actionString.equals(Action.CONTINUE.toString()))
232          {
233            return Action.CONTINUE;
234          }
235    
236        throw new RuntimeException("Error while loading observer: unkown action");
237      }
238    
239      public void save (Element node)
240      {
241        super.save(node);
242    
243        this.saveReturnAction(node);
244    
245        // actions
246        Element actionPointsXML = new Element("actionPoints");
247    
248        Iterator iterator = this.getActionPoints().iterator();
249        while (iterator.hasNext())
250          {
251            ActionPoint actionPoint = (ActionPoint) iterator.next();
252            Element actionPointXML = new Element("actionPoint");
253            actionPoint.save(actionPointXML);
254            actionPointsXML.addContent(actionPointXML);
255          }
256        node.addContent(actionPointsXML);
257    
258        // filters
259    
260        Element filterPointsXML = new Element("filterPoints");
261    
262        iterator = this.getFilterPoints().iterator();
263        while (iterator.hasNext())
264          {
265            FilterPoint filterPoint = (FilterPoint) iterator.next();
266            Element filterPointXML = new Element("filterPoint");
267            filterPoint.save(filterPointXML);
268            filterPointsXML.addContent(filterPointXML);
269          }
270        node.addContent(filterPointsXML);
271    
272      }
273    
274      public void load (Element node)
275      {
276        super.load(node);
277    
278        this.setReturnAction(this.loadReturnAction(node));
279    
280        // actions
281        Element actionPointsXML = node.getChild("actionPoints");
282        List list = (List) (actionPointsXML.getChildren("actionPoint"));
283        Iterator i = list.iterator();
284        Iterator j = this.getActionPoints().iterator();
285    
286        while (i.hasNext())
287          {
288            ((ActionPoint) j.next()).load(((Element) i.next()));
289          }
290    
291        // filters
292        Element filterPointsXML = node.getChild("filterPoints");
293        list = (List) filterPointsXML.getChildren("filterPoint");
294        i = list.iterator();
295        j = this.getFilterPoints().iterator();
296    
297        while (i.hasNext())
298          {
299            ((FilterPoint) j.next()).load(((Element) i.next()));
300          }
301      }
302    
303      protected GuiObject getCopy ()
304      {
305        return new ObserverRoot(this);
306      }
307    
308      /**
309             * Returns combo objects representing the currently applied filters.
310             * 
311             * @see Combo.
312             * @return List of combos.
313             */
314      public ObservableLinkedList getCurrentFilterCombos ()
315      {
316        ObservableLinkedList combos = new ObservableLinkedList();
317    
318        Iterator i = this.getFilterPoints().iterator();
319        while (i.hasNext())
320          {
321            FilterPoint filterPoint = (FilterPoint) i.next();
322            Iterator j = filterPoint.getItems().iterator();
323            while (j.hasNext())
324              {
325                Filter filter = (Filter) j.next();
326                combos.add(new Combo(filterPoint, filter));
327              }
328          }
329        return combos;
330      }
331    
332      /**
333             * Returns combo objects representing the currently applied actions.
334             * 
335             * @see Combo.
336             * @return List of combos.
337             */
338      public ObservableLinkedList getCurrentActionCombos ()
339      {
340        ObservableLinkedList combos = new ObservableLinkedList();
341    
342        Iterator i = this.getActionPoints().iterator();
343        while (i.hasNext())
344          {
345            ActionPoint actionPoint = (ActionPoint) i.next();
346            Iterator j = actionPoint.getItems().iterator();
347            while (j.hasNext())
348              {
349                frysk.gui.monitor.actions.Action action = (frysk.gui.monitor.actions.Action) j.next();
350                combos.add(new Combo(actionPoint, action));
351              }
352          }
353        return combos;
354      }
355    
356      /**
357             * Used to set which action is taken by the observer with respect to
358             * resuming execution of the observed thread after all the actions are
359             * executed. acceptable values are Action.BLOCK to block the process.
360             * Action.CONTINUE to continue the process. and null to pop-up a dialog
361             * and ask the user for action.
362             */
363      public void setReturnAction (frysk.proc.Action action)
364      {
365        this.returnAction = action;
366      }
367    
368      /**
369             * Should be used by inheriting observers to get the desired Action with
370             * respect to stoping/resumeing execution of the observed thread.
371             * 
372             * @return
373             */
374      protected frysk.proc.Action whatActionShouldBeReturned ()
375      {
376        if (this.returnAction != null)
377          {
378            return this.returnAction;
379          }
380        else
381          {
382            if (DialogManager.showQueryDialog(this.getName()
383                                              + ": would you like to resume thread execution ?"))
384              {
385                return Action.CONTINUE;
386              }
387            else
388              {
389                return Action.BLOCK;
390              }
391          }
392      }
393    
394      public frysk.proc.Action getCurrentAction ()
395      {
396        return this.returnAction;
397      }
398    
399      public void addedTo (Object observable)
400      {
401        EventManager.theManager.observerAdded(
402                                              GuiTask.GuiTaskFactory.getGuiTask((Task) observable),
403                                              this);
404      }
405    
406      public void deletedFrom (Object observable)
407      {
408        EventManager.theManager.observerAdded(
409                                              GuiTask.GuiTaskFactory.getGuiTask((Task) observable),
410                                              this);
411      }
412    
413    }