View Javadoc

1   /*
2    Copyright (C) 2006 Grid Systems, S.A.
3   
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8   
9    This library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13  
14   You should have received a copy of the GNU Lesser General Public
15   License along with this library; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
17  */
18  package com.gridsystems.nextgrid.components;
19  
20  import java.awt.Color;
21  import java.awt.EventQueue;
22  import java.util.Date;
23  import java.util.Formatter;
24  
25  import javax.swing.text.BadLocationException;
26  import javax.swing.text.JTextComponent;
27  import javax.swing.text.SimpleAttributeSet;
28  import javax.swing.text.StyleConstants;
29  
30  import nextgrid.api.pem.DiscoveryEvent;
31  import nextgrid.api.pem.DiscoveryListener;
32  import nextgrid.api.pem.ProcessEvent;
33  import nextgrid.api.pem.ProcessListener;
34  
35  /**
36   * <p>POMListener that writes event logs into a Swing JTextComponent.</p>
37   *
38   * <p>This is an example of how end-user applications can interact with the
39   * workflow enaction process.</p>
40   *
41   * @author Rodrigo Ruiz
42   */
43  public class SwingEventLogger implements DiscoveryListener, ProcessListener {
44  
45    /**
46     * Serial version UUID.
47     */
48    private static final long serialVersionUID = -355090363868006684L;
49  
50    /**
51     * Listener names.
52     */
53    private static final String[] CATEGORIES = {
54      "DISCOVERY",
55      " PROCESS "
56    };
57  
58    /**
59     * Category index.
60     */
61    private static final int DISCOVERY = 0;
62  
63    /**
64     * Category index.
65     */
66    private static final int PROCESS = 1;
67  
68    /**
69     * Attributes used for formatting the log output.
70     */
71    private static final SimpleAttributeSet[] ATTRIBS = {
72      new SimpleAttributeSet(), new SimpleAttributeSet()
73    };
74  
75    /**
76     * Index of the last added paragraph.
77     * <p>
78     * This integer is also used to determine which style must be used (even/odd).
79     * <p>
80     * It is safe to use it unsynchronised, as long as it is used only from the
81     * AWT event dispatch thread.
82     */
83    private static int pIndex;
84  
85    static {
86      StyleConstants.setBackground(ATTRIBS[0], Color.decode("0xFFFFCC"));
87      StyleConstants.setBackground(ATTRIBS[1], Color.WHITE);
88      StyleConstants.setFontFamily(ATTRIBS[0], "Courier");
89      StyleConstants.setFontFamily(ATTRIBS[1], "Courier");
90      StyleConstants.setSpaceAbove(ATTRIBS[0], 2.0f);
91      StyleConstants.setSpaceBelow(ATTRIBS[0], 2.0f);
92      StyleConstants.setSpaceAbove(ATTRIBS[1], 2.0f);
93      StyleConstants.setSpaceBelow(ATTRIBS[1], 2.0f);
94    }
95  
96    /**
97     * Text component to write logs to.
98     */
99    private final JTextComponent tc;
100 
101   /**
102    * Set to true for ignoring discovery events.
103    */
104   private boolean filterDiscoveryEvents;
105 
106   /**
107    * Set to true for ignoring process events.
108    */
109   private boolean filterProcessEvents;
110 
111   /**
112    * Set to false for filtering events from descendant nodes.
113    */
114   private boolean listen = true;
115 
116   /**
117    * Creates a new instance.
118    *
119    * @param tc Text component
120    */
121   public SwingEventLogger(JTextComponent tc) {
122     this.tc = tc;
123   }
124 
125   /**
126    * Gets the managed text component.
127    *
128    * @return The managed text component
129    */
130   public final JTextComponent getTextComponent() {
131     return this.tc;
132   }
133 
134   /**
135    * Gets the "discovery events filtered" flag value.
136    *
137    * @return The flag value
138    */
139   public final boolean isDiscoveryFiltered() {
140     return this.filterDiscoveryEvents;
141   }
142 
143   /**
144    * Gets the "process events filtered" flag value.
145    *
146    * @return The flag value
147    */
148   public final boolean isProcessFiltered() {
149     return this.filterProcessEvents;
150   }
151 
152   /**
153    * Sets the "discovery events filtered" flag value.
154    *
155    * @param filtered The new flag value
156    */
157   public final void setDiscoveryFiltered(boolean filtered) {
158     this.filterDiscoveryEvents = filtered;
159   }
160 
161   /**
162    * Sets the "process events filtered" flag value.
163    *
164    * @param filtered The new flag value
165    */
166   public final void setProcessFiltered(boolean filtered) {
167     this.filterProcessEvents = filtered;
168   }
169 
170   /**
171    * {@inheritDoc}
172    */
173   public final void discovererSelected(DiscoveryEvent event) {
174     if (!filterDiscoveryEvents) {
175       log(event.getTimestamp(), CATEGORIES[DISCOVERY],
176         "Discoverer selected",
177         "Process Name : " + event.getProcess().getName(),
178         "Discoverer   : " + event.getDiscoverer()
179       );
180     }
181   }
182 
183   /**
184    * {@inheritDoc}
185    */
186   public final void discoveryFailed(DiscoveryEvent event) {
187     if (!filterDiscoveryEvents) {
188       log(event.getTimestamp(), CATEGORIES[DISCOVERY],
189         "Discovery failed",
190         "Process Name : " + event.getProcess().getName(),
191         "Message      : " + event.getException().getMessage()
192       );
193     }
194   }
195 
196   /**
197    * {@inheritDoc}
198    */
199   public final void discoveryFinished(DiscoveryEvent event) {
200     if (!filterDiscoveryEvents) {
201       log(event.getTimestamp(), CATEGORIES[DISCOVERY],
202         "Discovery finished",
203         "Process Name : " + event.getProcess().getName()
204       );
205     }
206   }
207 
208   /**
209    * {@inheritDoc}
210    */
211   public final void discoveryStarting(DiscoveryEvent event) {
212     if (!filterDiscoveryEvents) {
213       log(event.getTimestamp(), CATEGORIES[DISCOVERY],
214         "Discovery started",
215         "Process Name : " + event.getProcess().getName()
216       );
217     }
218   }
219 
220   /**
221    * {@inheritDoc}
222    */
223   public final boolean isListeningToDescendants() {
224     return this.listen;
225   }
226 
227   /**
228    * Sets the "listens to descendant events" flag value.
229    *
230    * @param doListen The new flag value
231    */
232   public final void setListeningToDescendants(boolean doListen) {
233     this.listen  = doListen;
234   }
235 
236   /**
237    * {@inheritDoc}
238    */
239   public final void processEvaluated(ProcessEvent event) {
240     if (!filterProcessEvents) {
241       log(event.getTimestamp(), CATEGORIES[PROCESS],
242         "Evaluation done",
243         "Process Name : " + event.getProcess().getName()
244       );
245     }
246   }
247 
248   /**
249    * {@inheritDoc}
250    */
251   public final void processFinished(ProcessEvent event) {
252     if (!filterProcessEvents) {
253       log(event.getTimestamp(), CATEGORIES[PROCESS],
254         "Execution finished",
255         "Process Name : " + event.getProcess().getName()
256       );
257     }
258   }
259 
260   /**
261    * {@inheritDoc}
262    */
263   public final void processFailed(ProcessEvent event) {
264     if (!filterProcessEvents) {
265       log(event.getTimestamp(), CATEGORIES[PROCESS], "Execution failed",
266         "Process Name : " + event.getProcess().getName(),
267         "Exception    : " + event.getException());
268 
269     }
270   }
271 
272   /**
273    * {@inheritDoc}
274    */
275   public final void processSelected(ProcessEvent event) {
276     if (!filterProcessEvents) {
277       log(event.getTimestamp(), CATEGORIES[PROCESS],
278         "Process selected",
279         "Process Name : " + event.getProcess().getName()
280       );
281     }
282   }
283 
284   /**
285    * {@inheritDoc}
286    */
287   public final void processStarted(ProcessEvent event) {
288     if (!filterProcessEvents) {
289       log(event.getTimestamp(), CATEGORIES[PROCESS],
290         "Execution started",
291         "Process Name : " + event.getProcess().getName()
292       );
293     }
294   }
295 
296   /**
297    * Logs some lines.
298    *
299    * @param ts       Event timestamp
300    * @param category An event category name
301    * @param text     Text lines to log
302    */
303   public final void log(long ts, String category, String... text) {
304     EventQueue.invokeLater(new Worker(new Date(ts), category, text));
305   }
306 
307   /**
308    * Logs some lines.
309    *
310    * @param d        Event timestamp
311    * @param category An event category name
312    * @param text     Text lines to log
313    */
314   public final void log(Date d, String category, String... text) {
315     EventQueue.invokeLater(new Worker(d, category, text));
316   }
317 
318   /**
319    * Append worker.
320    */
321   private class Worker implements Runnable {
322     /** Timestamp. */
323     private final Date d;
324 
325     /** Log category name. */
326     private final String category;
327 
328     /** Lines to log. */
329     private final String[] lines;
330 
331     /**
332      * Creates a new instance.
333      *
334      * @param d         A timestamp
335      * @param category  Category name
336      * @param lines     Lines to log
337      */
338     public Worker(Date d, String category, String[] lines) {
339       this.d = d;
340       this.category = category;
341       this.lines = lines;
342     }
343 
344     /**
345      * {@inheritDoc}
346      */
347     public void run() {
348       Formatter f = new Formatter();
349       f.format("%tT [%s]", d, category);
350       String prefix = f.toString();
351       String spaces = "                         ".substring(0, prefix.length());
352 
353       f = new Formatter();
354       for (int i = 0; i < lines.length; i++) {
355         f.format("%s %-100s%n", (i == 0) ? prefix : spaces, lines[i]);
356       }
357 
358       try {
359         if (tc == null) {
360           System.out.println(f.toString());
361         } else {
362 
363           SimpleAttributeSet attr = ATTRIBS[pIndex % 2];
364 
365           int len = tc.getDocument().getLength();
366 
367           tc.getDocument().insertString(len, f.toString(), attr);
368 
369           pIndex++;
370         }
371       } catch (BadLocationException e) {
372         // This should never happen
373         throw new RuntimeException(e);
374       }
375     }
376   }
377 }