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}