diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReader.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReader.java index 8ad29ac2..44c6e450 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReader.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReader.java @@ -43,6 +43,16 @@ protected Logger getLogger() { return gcResource.getLogger(); } + private DataReaderTools dataReaderTools; + + protected DataReaderTools getDataReaderTools() { + if (dataReaderTools == null) { + dataReaderTools = new DataReaderTools(getLogger()); + } + + return dataReaderTools; + } + @Override public abstract GCModel read() throws IOException; diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReaderSun.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReaderSun.java index f27966ac..87bed904 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReaderSun.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/AbstractDataReaderSun.java @@ -1,13 +1,5 @@ package com.tagtraum.perf.gcviewer.imp; -import com.tagtraum.perf.gcviewer.model.AbstractGCEvent; -import com.tagtraum.perf.gcviewer.model.AbstractGCEvent.ExtendedType; -import com.tagtraum.perf.gcviewer.model.AbstractGCEvent.GcPattern; -import com.tagtraum.perf.gcviewer.model.GCEvent; -import com.tagtraum.perf.gcviewer.model.GCResource; -import com.tagtraum.perf.gcviewer.util.NumberParser; -import com.tagtraum.perf.gcviewer.util.ParseInformation; - import java.io.IOException; import java.io.InputStream; import java.io.LineNumberReader; @@ -22,6 +14,14 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.tagtraum.perf.gcviewer.model.AbstractGCEvent; +import com.tagtraum.perf.gcviewer.model.AbstractGCEvent.ExtendedType; +import com.tagtraum.perf.gcviewer.model.AbstractGCEvent.GcPattern; +import com.tagtraum.perf.gcviewer.model.GCEvent; +import com.tagtraum.perf.gcviewer.model.GCResource; +import com.tagtraum.perf.gcviewer.util.NumberParser; +import com.tagtraum.perf.gcviewer.util.ParseInformation; + /** * The AbstractDataReaderSun is the base class of most Sun / Oracle parser implementations. *
@@ -79,24 +79,7 @@ protected AbstractDataReaderSun(GCResource gcResource, InputStream in, GcLogType * @return amount of memory in kilobyte */ private int getMemoryInKiloByte(double memoryValue, char memUnit, String line) { - if ('B' == memUnit) { - return (int) Math.rint(memoryValue / 1024); - } - else if ('K' == memUnit) { - return (int) Math.rint(memoryValue); - } - else if ('M' == memUnit) { - return (int) Math.rint(memoryValue * 1024); - } - else if ('G' == memUnit) { - return (int) Math.rint(memoryValue * 1024*1024); - } - else { - if (getLogger().isLoggable(Level.WARNING)) { - getLogger().warning("unknown memoryunit '" + memUnit + "' in line " + line); - } - return 1; - } + return getDataReaderTools().getMemoryInKiloByte(memoryValue, memUnit, line); } /** diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderFacade.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderFacade.java index 5061643c..4fd5c764 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderFacade.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderFacade.java @@ -1,14 +1,5 @@ package com.tagtraum.perf.gcviewer.imp; -import com.tagtraum.perf.gcviewer.ctrl.impl.GcSeriesLoader; -import com.tagtraum.perf.gcviewer.model.GCModel; -import com.tagtraum.perf.gcviewer.model.GCResource; -import com.tagtraum.perf.gcviewer.model.GcResourceFile; -import com.tagtraum.perf.gcviewer.model.GcResourceSeries; -import com.tagtraum.perf.gcviewer.util.BuildInfoReader; -import com.tagtraum.perf.gcviewer.util.HttpUrlConnectionHelper; -import com.tagtraum.perf.gcviewer.util.LocalisationHelper; - import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; @@ -21,6 +12,15 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Logger; +import com.tagtraum.perf.gcviewer.ctrl.impl.GcSeriesLoader; +import com.tagtraum.perf.gcviewer.model.GCModel; +import com.tagtraum.perf.gcviewer.model.GCResource; +import com.tagtraum.perf.gcviewer.model.GcResourceFile; +import com.tagtraum.perf.gcviewer.model.GcResourceSeries; +import com.tagtraum.perf.gcviewer.util.BuildInfoReader; +import com.tagtraum.perf.gcviewer.util.HttpUrlConnectionHelper; +import com.tagtraum.perf.gcviewer.util.LocalisationHelper; + /** * DataReaderFacade is a helper class providing a simple interface to read a gc log file * including standard error handling. @@ -103,34 +103,46 @@ private GCModel readModel(GcResourceFile gcResource) throws IOException { URL url = gcResource.getResourceNameAsUrl(); DataReaderFactory factory = new DataReaderFactory(); long contentLength = 0L; - InputStream in; - if (url.getProtocol().startsWith("http")) { - AtomicLong cl = new AtomicLong(); - URLConnection conn = url.openConnection(); - in = HttpUrlConnectionHelper.openInputStream((HttpURLConnection)conn, HttpUrlConnectionHelper.GZIP, cl); - contentLength = cl.get(); - } - else { - in = url.openStream(); - if (url.getProtocol().startsWith("file")) { - File file = new File(url.getFile()); - if (file.exists()) { - contentLength = file.length(); + InputStream in = null; + try { + if (url.getProtocol().startsWith("http")) { + AtomicLong cl = new AtomicLong(); + URLConnection conn = url.openConnection(); + in = HttpUrlConnectionHelper.openInputStream((HttpURLConnection) conn, + HttpUrlConnectionHelper.GZIP, + cl); + contentLength = cl.get(); + } + else { + in = url.openStream(); + if (url.getProtocol().startsWith("file")) { + File file = new File(url.getFile()); + if (file.exists()) { + contentLength = file.length(); + } } } - } - if (contentLength > 100L) { - in = new MonitoredBufferedInputStream(in, DataReaderFactory.FOUR_KB, contentLength); - for (PropertyChangeListener listener : propertyChangeListeners) { - ((MonitoredBufferedInputStream)in).addPropertyChangeListener(listener); + if (contentLength > 100L) { + in = new MonitoredBufferedInputStream(in, DataReaderFactory.FOUR_KB, contentLength); + for (PropertyChangeListener listener : propertyChangeListeners) { + ((MonitoredBufferedInputStream) in).addPropertyChangeListener(listener); + } } - } - DataReader reader = factory.getDataReader(gcResource, in); - GCModel model = reader.read(); - model.setURL(url); + DataReader reader = factory.getDataReader(gcResource, in); + GCModel model = reader.read(); + model.setURL(url); - return model; + return model; + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + gcResource.getLogger().warning("A problem occurred trying to close the InputStream: " + e.toString()); + } + } + } } } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderHPUX1_2.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderHPUX1_2.java index 4c6175ba..acf6b4e6 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderHPUX1_2.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderHPUX1_2.java @@ -148,12 +148,6 @@ public GCModel read() throws IOException { return model; } finally { - if (in != null) - try { - in.close(); - } - catch (IOException ioe) { - } if (getLogger().isLoggable(Level.INFO)) getLogger().info("Reading done."); } } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderHPUX1_4_1.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderHPUX1_4_1.java index 65885545..52e54dc8 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderHPUX1_4_1.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderHPUX1_4_1.java @@ -204,12 +204,6 @@ If the heap area holding the reflection objects (representing classes and method return model; } finally { - if (in != null) - try { - in.close(); - } - catch (IOException ioe) { - } if (getLogger().isLoggable(Level.INFO)) getLogger().info("Reading done."); } } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM1_3_0.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM1_3_0.java index b3c95a5d..9bde64db 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM1_3_0.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM1_3_0.java @@ -81,12 +81,6 @@ public GCModel read() throws IOException { return model; } finally { - if (in != null) - try { - in.close(); - } - catch (IOException ioe) { - } if (getLogger().isLoggable(Level.INFO)) getLogger().info("Reading done."); } } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM1_3_1.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM1_3_1.java index 256f3591..3d61740e 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM1_3_1.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM1_3_1.java @@ -111,12 +111,6 @@ else if (line.indexOf("managing allocation failure, action=3") != -1) { return model; } finally { - if (in != null) - try { - in.close(); - } - catch (IOException ioe) { - } if (getLogger().isLoggable(Level.INFO)) getLogger().info("Done reading."); } } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM1_4_2.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM1_4_2.java index e0219185..ff330b27 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM1_4_2.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBM1_4_2.java @@ -119,12 +119,6 @@ else if (line.indexOf("managing allocation failure, action=3") != -1) { return model; } finally { - if (in != null) - try { - in.close(); - } - catch (IOException ioe) { - } if (getLogger().isLoggable(Level.INFO)) getLogger().info("Done reading."); } } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBMi5OS1_4_2.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBMi5OS1_4_2.java index 82a04cc5..c24e123e 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBMi5OS1_4_2.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderIBMi5OS1_4_2.java @@ -130,12 +130,6 @@ else if (line.indexOf("collection ending") != -1) { return model; } finally { - if (in != null) - try { - in.close(); - } - catch (IOException ioe) { - } if (getLogger().isLoggable(Level.INFO)) getLogger().info("Done reading."); } } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderJRockit1_4_2.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderJRockit1_4_2.java index 68a95b59..921ad1ee 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderJRockit1_4_2.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderJRockit1_4_2.java @@ -144,12 +144,6 @@ else if (line.substring(startTimeIndex).startsWith("<")) { return model; } finally { - if (in != null) - try { - in.close(); - } - catch (IOException ioe) { - } if (getLogger().isLoggable(Level.INFO)) getLogger().info("Reading done."); } } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderJRockit1_5_0.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderJRockit1_5_0.java index 867c7ba5..9512ea24 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderJRockit1_5_0.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderJRockit1_5_0.java @@ -185,12 +185,6 @@ else if (line.indexOf("->") == -1){ return model; } finally { - if (in != null) - try { - in.close(); - } - catch (IOException ioe) { - } if (getLogger().isLoggable(Level.INFO)) getLogger().info("Reading done."); } } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderJRockit1_6_0.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderJRockit1_6_0.java index 1e37cbc2..afcfad9c 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderJRockit1_6_0.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderJRockit1_6_0.java @@ -180,12 +180,6 @@ else if ((line.indexOf("C#") == -1) || (line.indexOf("->") == -1)){ return model; } finally { - if (in != null) - try { - in.close(); - } - catch (IOException ioe) { - } if (getLogger().isLoggable(Level.INFO)) getLogger().info("Reading done."); } } diff --git a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderShenandoah.java b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderShenandoah.java index 93283962..3976a6f2 100644 --- a/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderShenandoah.java +++ b/src/main/java/com/tagtraum/perf/gcviewer/imp/DataReaderShenandoah.java @@ -1,70 +1,88 @@ package com.tagtraum.perf.gcviewer.imp; -import com.tagtraum.perf.gcviewer.model.AbstractGCEvent; -import com.tagtraum.perf.gcviewer.model.GCModel; -import com.tagtraum.perf.gcviewer.model.GCResource; -import com.tagtraum.perf.gcviewer.model.ShenandoahGCEvent; - -import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.time.ZonedDateTime; import java.util.Arrays; import java.util.List; +import java.util.Objects; +import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; +import com.tagtraum.perf.gcviewer.model.AbstractGCEvent; +import com.tagtraum.perf.gcviewer.model.ConcurrentGCEvent; +import com.tagtraum.perf.gcviewer.model.GCEvent; +import com.tagtraum.perf.gcviewer.model.GCModel; +import com.tagtraum.perf.gcviewer.model.GCResource; + /** - * Currently only parsing 5 main messages for GCViewer with default decorations. - * Initial mark, concurrent mark, final mark, concurrent evacuation + * DataReaderShenandoah can parse all the main messages for GCViewer with default decorations.
+ * Initial mark, Final mark, Init Update Refs, Final Update Refs, Pause Full Allocation Failure, Pause Full (System.gc()), + * Concurrent mark, Concurrent evacuation, Concurrent reset bitmaps, Concurrent update references, Concurrent precleaning + *
+ * For more information: Shenandoah Wiki at OpenJDK + * *
* Example Format - * [0.730s][info][gc,start ] GC(0) Pause Init Mark - * [0.731s][info][gc ] GC(0) Pause Init Mark 1.021ms - * [0.731s][info][gc,start ] GC(0) Concurrent marking - * [0.735s][info][gc ] GC(0) Concurrent marking 74M->74M(128M) 3.688ms - * [0.735s][info][gc,start ] GC(0) Pause Final Mark - * [0.736s][info][gc ] GC(0) Pause Final Mark 74M->76M(128M) 0.811ms - * [0.736s][info][gc,start ] GC(0) Concurrent evacuation - * ... - * [29.628s][info][gc ] Cancelling concurrent GC: Allocation Failure - * ... skipping detailed messages as those aren't parsed yet - * [43.948s][info][gc ] GC(831) Pause Full (Allocation Failure) 7943M->6013M(8192M) 14289.335ms + *
[0.730s][info][gc,start ] GC(0) Pause Init Mark + *
[0.731s][info][gc ] GC(0) Pause Init Mark 1.021ms + *
[0.731s][info][gc,start ] GC(0) Concurrent marking + *
[0.735s][info][gc ] GC(0) Concurrent marking 74M->74M(128M) 3.688ms + *
[0.735s][info][gc,start ] GC(0) Pause Final Mark + *
[0.736s][info][gc ] GC(0) Pause Final Mark 74M->76M(128M) 0.811ms + *
[0.736s][info][gc,start ] GC(0) Concurrent evacuation + *
... + *
[43.948s][info][gc ] GC(831) Pause Full (Allocation Failure) 7943M->6013M(8192M) 14289.335ms
*/
public class DataReaderShenandoah extends AbstractDataReader {
// Input: [0.693s][info][gc ] GC(0) Pause Init Mark 1.070ms
// Group 1: 0.693
- // Group 2: 1.070
- // Regex without breaking: ^\[([0-9]+[.,][0-9]+)[^\-]*[ ]([0-9]+[.,][0-9]+)
- private static final Pattern PATTERN_WITHOUT_HEAP = Pattern.compile("^\\[([0-9]+[.,][0-9]+)[^\\-]*[ ]([0-9]+[.,][0-9]+)");
+ // Group 2: Pause Init Mark
+ // Group 3: 1.070
+ // Regex: ^\[([^s\]]*)[^\-]*\)[ ]([^\-]*)[ ]([0-9]+[.,][0-9]+)
+ private static final Pattern PATTERN_WITHOUT_HEAP = Pattern.compile(
+ "^\\[([^s\\]]*)[^\\-]*\\)[ ]([^\\-]*)[ ]([0-9]+[.,][0-9]+)");
// Input: [13.522s][info][gc ] GC(708) Concurrent evacuation 4848M->4855M(4998M) 2.872ms
// Group 1: 13.522
- // Group 2: 4848M->4855M(4998M)
- // Group 3: 2.872
- // Regex without breaking: ^\[([0-9]+[.,][0-9]+).*[ ]([0-9]+[BKMG]\-\>[0-9]+[BKMG]\([0-9]+[BKMG]\)) ([0-9]+[.,][0-9]+)
- private static final Pattern PATTERN_WITH_HEAP = Pattern.compile("^\\[([0-9]+[.,][0-9]+)" +
- ".*[ ]([0-9]+[BKMG]\\-\\>[0-9]+[BKMG]\\([0-9]+[BKMG]\\)) " +
- "([0-9]+[.,][0-9]+)");
+ // Group 2: Concurrent evacuation
+ // Group 3: 4848M->4855M(4998M)
+ // Group 4: 2.872
+ // Regex: ^\[([^s\]]*).*\)[ ](.*)[ ]([0-9]+[BKMG]\-\>[0-9]+[BKMG]\([0-9]+[BKMG]\)) ([0-9]+[.,][0-9]+)
+ private static final Pattern PATTERN_WITH_HEAP = Pattern.compile(
+ "^\\[([^s\\]]*).*\\)[ ](.*)[ ]([0-9]+[BKMG]\\-\\>[0-9]+[BKMG]\\([0-9]+[BKMG]\\)) ([0-9]+[.,][0-9]+)");
// Input: 4848M->4855M(4998M)
// Group 1: 4848
// Group 2: 4855
// Group 3: 4998
- // Regex without breaking: ([0-9]+)[BKMG]\-\>([0-9]+)[BKMG]\(([0-9]+)[BKMG]\)
- private static final Pattern PATTERN_HEAP_CHANGES = Pattern.compile("([0-9]+)[BKMG]->([0-9]+)[BKMG]\\(([0-9]+)[BKMG]\\)");
+ // Regex: ([0-9]+)[BKMG]\-\>([0-9]+)[BKMG]\(([0-9]+)[BKMG]\)
+ private static final Pattern PATTERN_HEAP_CHANGES = Pattern.compile(
+ "([0-9]+)([BKMG])->([0-9]+)([BKMG])\\(([0-9]+)([BKMG])\\)");
+
+ // Input: 2017-08-30T23:22:47.357+0300
+ // Regex: ^\d{4}\-\d\d\-\d\d[tT][\d:\.]*?(?:[zZ]|[+\-]\d\d:?\d\d)?$
+ private static final Pattern PATTERN_ISO8601_DATE = Pattern.compile(
+ "^\\d{4}\\-\\d\\d\\-\\d\\d[tT][\\d:\\.]*?(?:[zZ]|[+\\-]\\d\\d:?\\d\\d)?$");
private static final int NO_HEAP_TIMESTAMP = 1;
- private static final int NO_HEAP_DURATION = 2;
+ private static final int NO_HEAP_EVENT_NAME = 2;
+ private static final int NO_HEAP_DURATION = 3;
private static final int WITH_HEAP_TIMESTAMP = 1;
- private static final int WITH_HEAP_MEMORY = 2;
- private static final int WITH_HEAP_DURATION = 3;
+ private static final int WITH_HEAP_EVENT_NAME = 2;
+ private static final int WITH_HEAP_MEMORY = 3;
+ private static final int WITH_HEAP_DURATION = 4;
private static final int HEAP_BEFORE = 1;
- private static final int HEAP_AFTER = 2;
- private static final int HEAP_CURRENT_TOTAL = 3;
+ private static final int HEAP_BEFORE_UNIT = 2;
+ private static final int HEAP_AFTER = 3;
+ private static final int HEAP_AFTER_UNIT = 4;
+ private static final int HEAP_CURRENT_TOTAL = 5;
+ private static final int HEAP_CURRENT_TOTAL_UNIT = 6;
private static final ListmemUnit
, input is
+ * converted to kilobyte.
+ * @param memoryValue amount of memory
+ * @param memUnit memory unit
+ * @param line line that is parsed
+ * @return amount of memory in kilobyte
+ */
+ public int getMemoryInKiloByte(double memoryValue, char memUnit, String line) {
+ if ('B' == memUnit) {
+ return (int) Math.rint(memoryValue / 1024);
+ }
+ else if ('K' == memUnit) {
+ return (int) Math.rint(memoryValue);
+ }
+ else if ('M' == memUnit) {
+ return (int) Math.rint(memoryValue * 1024);
+ }
+ else if ('G' == memUnit) {
+ return (int) Math.rint(memoryValue * 1024*1024);
+ }
+ else {
+ if (logger.isLoggable(Level.WARNING)) {
+ logger.warning("unknown memoryunit '" + memUnit + "' in line " + line);
+ }
+ return 1;
+ }
+ }
+
+}
diff --git a/src/main/java/com/tagtraum/perf/gcviewer/model/AbstractGCEvent.java b/src/main/java/com/tagtraum/perf/gcviewer/model/AbstractGCEvent.java
index 6b880e66..582c6be2 100644
--- a/src/main/java/com/tagtraum/perf/gcviewer/model/AbstractGCEvent.java
+++ b/src/main/java/com/tagtraum/perf/gcviewer/model/AbstractGCEvent.java
@@ -2,7 +2,15 @@
import java.io.Serializable;
import java.time.ZonedDateTime;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeSet;
/**
* The abstract gc event is the base class for all types of events. All sorts of general
@@ -12,6 +20,12 @@
* @author Joerg Wuethrich
*/
public abstract class AbstractGCEvent