URLStreamHandlerRuntime.java
1/*******************************************************************************
2 * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and Contributors
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Marc R. Hoffmann - initial API and implementation
10 *
11 *******************************************************************************/
12package org.jacoco.core.runtime;
13
14import java.io.IOException;
15import java.lang.reflect.Field;
16import java.net.URL;
17import java.net.URLConnection;
18import java.net.URLStreamHandler;
19import java.util.Hashtable;
20
21import org.jacoco.core.instr.InstrSupport;
22import org.objectweb.asm.MethodVisitor;
23import org.objectweb.asm.Opcodes;
24
25/**
26 * This {@link IRuntime} implementation registers a special
27 * {@link URLStreamHandler} to process coverage data. The handler is not
28 * actually used for opening a URL, but to get access to the runtime object.
29 *
30 * @author Marc R. Hoffmann
31 * @version 0.4.1.20101007204400
32 */
33public class URLStreamHandlerRuntime extends AbstractRuntime {
34
35 private static final String PROTOCOLPREFIX = "jacoco-";
36
37 private final String protocol;
38
39 private Hashtable<String, URLStreamHandler> handlers;
40
41 /**
42 * Creates a new runtime.
43 */
44 public URLStreamHandlerRuntime() {
45 protocol = PROTOCOLPREFIX + Integer.toHexString(hashCode());
46 }
47
48 public void startup() throws Exception {
49 setStartTimeStamp();
50 handlers = getHandlersReference();
51 handlers.put(protocol, handler);
52 }
53
54 private Hashtable<String, URLStreamHandler> getHandlersReference()
55 throws Exception {
56 final Field field = URL.class.getDeclaredField("handlers");
57 field.setAccessible(true);
58 @SuppressWarnings("unchecked")
59 final Hashtable<String, URLStreamHandler> handlers = (Hashtable<String, URLStreamHandler>) field
60 .get(null);
61 return handlers;
62 }
63
64 public void shutdown() {
65 handlers.remove(protocol);
66 }
67
68 public int generateDataAccessor(final long classid, final String classname,
69 final int probecount, final MethodVisitor mv) {
70
71 // The data accessor performs the following steps:
72 //
73 // final URL url = new URL(protocol, null, "");
74 // final URLConnection connection = url.openConnection();
75 // final Object[] args = new Object[3];
76 // args[0] = Long.valueOf(classid);
77 // args[1] = classname;
78 // args[2] = Integer.valueOf(probecount);
79 // connection.equals(args);
80 // final byte[] probedata = (byte[]) args[0];
81
82 ExecutionDataAccess.generateArgumentArray(classid, classname,
83 probecount, mv);
84 mv.visitInsn(Opcodes.DUP);
85
86 // Stack[1]: [Ljava/lang/Object;
87 // Stack[0]: [Ljava/lang/Object;
88
89 mv.visitTypeInsn(Opcodes.NEW, "java/net/URL");
90 mv.visitInsn(Opcodes.DUP);
91 mv.visitLdcInsn(protocol);
92 mv.visitInsn(Opcodes.ACONST_NULL);
93 mv.visitLdcInsn("");
94 mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/net/URL", "<init>",
95 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
96
97 // Stack[2]: [Ljava/net/URL;
98 // Stack[1]: [Ljava/lang/Object;
99 // Stack[0]: [Ljava/lang/Object;
100
101 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/net/URL",
102 "openConnection", "()Ljava/net/URLConnection;");
103
104 // Stack[2]: [Ljava/net/URLConnection;
105 // Stack[1]: [Ljava/lang/Object;
106 // Stack[0]: [Ljava/lang/Object;
107
108 mv.visitInsn(Opcodes.SWAP);
109
110 // Stack[2]: [Ljava/lang/Object;
111 // Stack[1]: [Ljava/net/URLConnection;
112 // Stack[0]: [Ljava/lang/Object;
113
114 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals",
115 "(Ljava/lang/Object;)Z");
116
117 // Stack[1]: Z;
118 // Stack[0]: [Ljava/lang/Object;
119
120 mv.visitInsn(Opcodes.POP);
121
122 // Stack[0]: [Ljava/lang/Object;
123
124 mv.visitInsn(Opcodes.ICONST_0);
125 mv.visitInsn(Opcodes.AALOAD);
126 mv.visitTypeInsn(Opcodes.CHECKCAST, InstrSupport.DATAFIELD_DESC);
127
128 return 7;
129 }
130
131 private final URLStreamHandler handler = new URLStreamHandler() {
132 @Override
133 protected URLConnection openConnection(final URL u) throws IOException {
134 return connection;
135 }
136 };
137
138 private final URLConnection connection = new URLConnection(null) {
139 @Override
140 public void connect() throws IOException {
141 throw new AssertionError();
142 }
143
144 @Override
145 public boolean equals(final Object obj) {
146 return access.equals(obj);
147 }
148 };
149
150}