public static void addMixinInterfacesToBootstrap(final Instrumentation inst) { if (isDisableMixinsOnBootstrap()) { System.out.println("New Relic Agent: mixin interfaces not moved to bootstrap"); return; } JarResource agentJarResource = null; try { agentJarResource = AgentJarHelper.getAgentJarResource(); final URL agentJarUrl = AgentJarHelper.getAgentJarUrl(); addMixinInterfacesToBootstrap(agentJarResource, agentJarUrl, inst); } finally { try { agentJarResource.close(); } catch (Throwable th) { logIfNRDebug("closing Agent jar resource", th); } } }
public static void addMixinInterfacesToBootstrap( final JarResource agentJarResource, final URL agentJarUrl, final Instrumentation inst) { boolean succeeded = false; final Pattern packageSearchPattern = Pattern.compile("com/newrelic/agent/instrumentation/pointcuts/(.*).class"); final String interfaceMixinAnnotation = "Lcom/newrelic/agent/instrumentation/pointcuts/InterfaceMixin;"; final String loadOnBootstrapAnnotation = "Lcom/newrelic/agent/instrumentation/pointcuts/LoadOnBootstrap;"; final String interfaceMapperAnnotation = "Lcom/newrelic/agent/instrumentation/pointcuts/InterfaceMapper;"; final String methodMapperAnnotation = "Lcom/newrelic/agent/instrumentation/pointcuts/MethodMapper;"; final String fieldAccessorAnnotation = "Lcom/newrelic/agent/instrumentation/pointcuts/FieldAccessor;"; final List<String> bootstrapAnnotations = Arrays.asList( "Lcom/newrelic/agent/instrumentation/pointcuts/InterfaceMixin;", "Lcom/newrelic/agent/instrumentation/pointcuts/InterfaceMapper;", "Lcom/newrelic/agent/instrumentation/pointcuts/MethodMapper;", "Lcom/newrelic/agent/instrumentation/pointcuts/FieldAccessor;", "Lcom/newrelic/agent/instrumentation/pointcuts/LoadOnBootstrap;"); File generatedFile = null; JarOutputStream outputJarStream = null; try { generatedFile = File.createTempFile("newrelic-bootstrap", ".jar"); final Manifest manifest = createManifest(); outputJarStream = createJarOutputStream(generatedFile, manifest); final long modTime = System.currentTimeMillis(); final Collection<String> fileNames = AgentJarHelper.findJarFileNames(agentJarUrl, packageSearchPattern); for (final String fileName : fileNames) { final int size = (int) agentJarResource.getSize(fileName); final ByteArrayOutputStream out = new ByteArrayOutputStream(size); Streams.copy(agentJarResource.getInputStream(fileName), out, size, true); final byte[] classBytes = out.toByteArray(); final ClassReader cr = new ClassReader(classBytes); final ClassStructure structure = ClassStructure.getClassStructure(cr, 4); final Collection<String> annotations = structure.getClassAnnotations().keySet(); if (containsAnyOf(bootstrapAnnotations, annotations)) { final JarEntry entry = new JarEntry(fileName); entry.setTime(modTime); outputJarStream.putNextEntry(entry); outputJarStream.write(classBytes); } } outputJarStream.closeEntry(); succeeded = true; } catch (IOException iox) { logIfNRDebug("generating mixin jar file", iox); try { outputJarStream.close(); } catch (Throwable th) { logIfNRDebug("closing outputJarStream", th); } } finally { try { outputJarStream.close(); } catch (Throwable th2) { logIfNRDebug("closing outputJarStream", th2); } } if (succeeded) { JarFile jarFile = null; try { jarFile = new JarFile(generatedFile); inst.appendToBootstrapClassLoaderSearch(jarFile); generatedFile.deleteOnExit(); } catch (IOException iox2) { logIfNRDebug("adding dynamic mixin jar to bootstrap", iox2); try { jarFile.close(); } catch (Throwable th3) { logIfNRDebug("closing generated jar file", th3); } } finally { try { jarFile.close(); } catch (Throwable th4) { logIfNRDebug("closing generated jar file", th4); } } } }