Trac #88: API to specify the session identifier used by the agent.
diff --git a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/JacocoAgent.java b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/JacocoAgent.java
index 35c1956..d4dabe8 100644
--- a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/JacocoAgent.java
+++ b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/JacocoAgent.java
@@ -18,6 +18,9 @@
 import java.io.IOException;

 import java.io.OutputStream;

 import java.lang.instrument.Instrumentation;

+import java.net.InetAddress;

+import java.net.UnknownHostException;

+import java.util.Random;

 

 import org.jacoco.core.data.ExecutionDataWriter;

 import org.jacoco.core.runtime.AgentOptions;

@@ -66,10 +69,25 @@
 	 */

 	public void init(final Instrumentation inst) throws Exception {

 		runtime = createRuntime(inst);

+		String sessionId = options.getSessionId();

+		if (sessionId == null) {

+			sessionId = createSessionId();

+		}

+		runtime.setSessionId(sessionId);

 		runtime.startup();

 		inst.addTransformer(new CoverageTransformer(runtime, options));

 	}

 

+	private String createSessionId() {

+		String host;

+		try {

+			host = InetAddress.getLocalHost().getHostName();

+		} catch (UnknownHostException e) {

+			host = "unknownhost";

+		}

+		return host + "-" + Integer.toHexString(new Random().nextInt());

+	}

+

 	/**

 	 * Creates the specific coverage runtime implementation.

 	 * 

diff --git a/org.jacoco.ant.test/src/org/jacoco/ant/AgentTaskTest.xml b/org.jacoco.ant.test/src/org/jacoco/ant/AgentTaskTest.xml
index 7bc630b..d5e9f34 100644
--- a/org.jacoco.ant.test/src/org/jacoco/ant/AgentTaskTest.xml
+++ b/org.jacoco.ant.test/src/org/jacoco/ant/AgentTaskTest.xml
@@ -18,7 +18,7 @@
 	<target name="testCoverageAgent">

 		<jacoco:agent property="jacocoagent" append="false" destfile="test.exec"

 			exclClassLoader="EvilClassLoader" includes="org.example.*"

-		    excludes="*Test" dumponexit="false"/>

+		    excludes="*Test" sessionid="testid" dumponexit="false"/>

 		<au:assertPropertySet name="jacocoagent"/>

 		<au:assertPropertyContains name="jacocoagent" value="-javaagent:"/>

 		<au:assertPropertyContains name="jacocoagent" value="append=false"/>

@@ -27,6 +27,7 @@
 		<au:assertPropertyContains name="jacocoagent" value="exclclassloader=EvilClassLoader"/>

 		<au:assertPropertyContains name="jacocoagent" value="includes=org.example.*"/>

 		<au:assertPropertyContains name="jacocoagent" value="excludes=*Test"/>

+		<au:assertPropertyContains name="jacocoagent" value="sessionid=testid"/>

 		<au:assertPropertyContains name="jacocoagent" value="dumponexit=false"/>

 	</target>

 	

diff --git a/org.jacoco.ant/src/org/jacoco/ant/AbstractCoverageTask.java b/org.jacoco.ant/src/org/jacoco/ant/AbstractCoverageTask.java
index 5b6f08f..f54f7ea 100644
--- a/org.jacoco.ant/src/org/jacoco/ant/AbstractCoverageTask.java
+++ b/org.jacoco.ant/src/org/jacoco/ant/AbstractCoverageTask.java
@@ -124,6 +124,18 @@
 	}

 

 	/**

+	 * Sets the session identifier.

+	 * 

+	 * @ant.not-required Default is a auto-generated id

+	 * 

+	 * @param id

+	 *            session identifier

+	 */

+	public void setSessionId(final String id) {

+		agentOptions.setSessionId(id);

+	}

+

+	/**

 	 * Dump coverage data on VM termination

 	 * 

 	 * @ant.not-required Default is <code>true</code>

diff --git a/org.jacoco.build/buildbundle.xml b/org.jacoco.build/buildbundle.xml
index 6afc163..8165f58 100644
--- a/org.jacoco.build/buildbundle.xml
+++ b/org.jacoco.build/buildbundle.xml
@@ -112,7 +112,8 @@
 				append="true"

 				destfile="${result.tmp.coverage.file}"

 				includes="${testscope}"

-				exclClassLoader="sun.reflect.DelegatingClassLoader|org.jacoco.core.test.TargetLoader">

+				exclClassLoader="sun.reflect.DelegatingClassLoader|org.jacoco.core.test.TargetLoader"

+			    sessionid="${manifest.Bundle-SymbolicName}">

 			

 			<junit haltonfailure="true" fork="true" forkmode="once" dir="${source.bundle.dir}">

 				<jvmarg line="${verify.jvm.args}"/>

diff --git a/org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java
index b034a4c..75817d5 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java
@@ -14,6 +14,7 @@
 

 import static org.junit.Assert.assertEquals;

 import static org.junit.Assert.assertFalse;

+import static org.junit.Assert.assertNull;

 import static org.junit.Assert.assertTrue;

 

 import java.io.File;

@@ -44,6 +45,7 @@
 		assertEquals("", options.getExcludes());

 		assertEquals("sun.reflect.DelegatingClassLoader", options

 				.getExclClassloader());

+		assertNull(options.getSessionId());

 		assertTrue(options.getDumpOnExit());

 		assertEquals("", options.toString());

 	}

@@ -141,6 +143,20 @@
 	}

 

 	@Test

+	public void testGetSessionId() {

+		AgentOptions options = new AgentOptions("sessionid=testsession");

+		assertEquals("testsession", options.getSessionId());

+	}

+

+	@Test

+	public void testSetSessionId() {

+		AgentOptions options = new AgentOptions();

+		options.setSessionId("testsession");

+		assertEquals("testsession", options.getSessionId());

+		assertEquals("sessionid=testsession", options.toString());

+	}

+

+	@Test

 	public void testGetDumpOnExit() {

 		AgentOptions options = new AgentOptions("dumponexit=false");

 		assertFalse(options.getDumpOnExit());

diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java b/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java
index 61aebb2..94b98bc 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java
@@ -73,13 +73,20 @@
 	public static final String EXCLCLASSLOADER = "exclclassloader";

 

 	/**

+	 * Specifies a session identifier that is written with the execution data.

+	 * Without this parameter a random identifier is created by the agent.

+	 */

+	public static final String SESSIONID = "sessionid";

+

+	/**

 	 * Specifies whether the agent will automatically dump coverage data on VM

 	 * exit. Default is <code>true</code>

 	 */

 	public static final String DUMPONEXIT = "dumponexit";

 

 	private static final Collection<String> VALID_OPTIONS = Arrays.asList(

-			DESTFILE, APPEND, INCLUDES, EXCLUDES, EXCLCLASSLOADER, DUMPONEXIT);

+			DESTFILE, APPEND, INCLUDES, EXCLUDES, EXCLCLASSLOADER, SESSIONID,

+			DUMPONEXIT);

 

 	private final Map<String, String> options;

 

@@ -217,6 +224,25 @@
 	}

 

 	/**

+	 * Returns the session identifier.

+	 * 

+	 * @return session identifier

+	 */

+	public String getSessionId() {

+		return getOption(SESSIONID, null);

+	}

+

+	/**

+	 * Sets the session identifier.

+	 * 

+	 * @param id

+	 *            session identifier

+	 */

+	public void setSessionId(final String id) {

+		setOption(SESSIONID, id);

+	}

+

+	/**

 	 * Returns whether coverage data should be dumped on exit

 	 * 

 	 * @return <code>true</code> if coverage data will be written on VM exit

diff --git a/org.jacoco.doc/docroot/doc/agent.html b/org.jacoco.doc/docroot/doc/agent.html
index 56131d6..2a604ce 100644
--- a/org.jacoco.doc/docroot/doc/agent.html
+++ b/org.jacoco.doc/docroot/doc/agent.html
@@ -100,8 +100,17 @@
       <td><code>sun.reflect.DelegatingClassLoader</code></td>

     </tr>

     <tr>

+      <td><code>sessionid</code></td>

+      <td>A session identifier that is written with the execution data. Without

+          this parameter a random identifier is created by the agent.

+      </td>

+      <td><i>auto-generated</i></td>

+    </tr>  

+    <tr>

       <td><code>dumponexit</code></td>

-      <td>If set to <code>true</code> coverage data will be written on VM shutdown</td>

+      <td>If set to <code>true</code> coverage data will be written on VM

+          shutdown.

+      </td>

       <td><code>true</code></td>

     </tr>

   </tbody>

diff --git a/org.jacoco.doc/docroot/doc/ant.html b/org.jacoco.doc/docroot/doc/ant.html
index ad08b4b..888099f 100644
--- a/org.jacoco.doc/docroot/doc/ant.html
+++ b/org.jacoco.doc/docroot/doc/ant.html
@@ -173,8 +173,17 @@
       <td><code>sun.reflect.DelegatingClassLoader</code></td>

     </tr>

     <tr>

+      <td><code>sessionid</code></td>

+      <td>A session identifier that is written with the execution data. Without

+          this parameter a random identifier is created by the agent.

+      </td>

+      <td><i>auto-generated</i></td>

+    </tr>  

+    <tr>

       <td><code>dumponexit</code></td>

-      <td>If set to <code>true</code> coverage data will be written on VM shutdown</td>

+      <td>If set to <code>true</code> coverage data will be written on VM

+          shutdown.

+      </td>

       <td><code>true</code></td>

     </tr>

   </tbody>

diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index 8f03949..8210004 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -19,10 +19,17 @@
 

 <h2>Trunk Build @qualified.bundle.version@ (@build.date@)</h2>

 

+<h3>New Features</h3>

+<ul>

+  <li>Execution data now includes session information: an arbitrary identifier,

+      the start time and dump time (Trac #88).</li>

+</ul>

+

 <h3>API Changes</h3>

 <ul>

   <li>Execution data file header is written and read in any case (Trac #72).</li>

-  <li>Added dumponexit to Agent Options. (Trac #82)</li>

+  <li>Added <code>dumponexit</code> to agent options (Trac #82).</li>

+  <li>Added <code>sessionid</code> to agent options (Trac #88).</li>

   <li>Additional and modified methods in <code>IRuntime</code> to produce

       session information (Trac #88).</li>

 </ul>