Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
fiwka committed Jun 2, 2021
0 parents commit e4fa190
Show file tree
Hide file tree
Showing 22 changed files with 806 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
**/build
**/**/build
.idea
.gradle
gradle.properties
26 changes: 26 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
subprojects {
apply plugin: 'java'

group 'ru.kdev'
version '1.0-SNAPSHOT'

repositories {
mavenCentral()
}

dependencies {
compileOnly files('../extensions-core/build/libs/extensions-core-1.0-SNAPSHOT.jar')
implementation 'org.ow2.asm:asm:9.1'
implementation group: 'org.ow2.asm', name: 'asm-tree', version: '9.1'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}

jar {
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }}
}

test {
useJUnitPlatform()
}
}
7 changes: 7 additions & 0 deletions extensions-core/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
jar {
manifest {
attributes 'Premain-Class': 'ru.kdev.extensions.ExtensionsBootstrap',
'Can-Redefine-Classes': 'true',
'Can-Retransform-Classes': 'true'
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ru.kdev.extensions;

import ru.kdev.extensions.annotation.Extension;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class ExtensionList {

private final List<Class<?>> extensions = new ArrayList<>();

public static ExtensionList parse(InputStream stream) throws ClassNotFoundException {
Scanner scanner = new Scanner(stream);
ExtensionList list = new ExtensionList();

while (scanner.hasNext()) {
String line = scanner.nextLine();
list.extensions.add(Class.forName(line));
}

return list;
}

public Class<?> getExtensionByTarget(Class<?> target) {
for(Class<?> extension : extensions) {
if(Arrays.asList(extension.getAnnotation(Extension.class).classes()).contains(target)) {
return extension;
}
}
return null;
}

public Class<?>[] getAllTargets() {
List<Class<?>> targets = new ArrayList<>();

for(Class<?> ext : extensions) {
targets.addAll(Arrays.asList(ext.getAnnotation(Extension.class).classes()));
}

return targets.toArray(new Class<?>[0]);
}

public List<Class<?>> getExtensions() {
return extensions;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ru.kdev.extensions;

import ru.kdev.extensions.processor.ExtensionsClassFileTransformer;

import java.lang.instrument.Instrumentation;

public class ExtensionsBootstrap {

public static void premain(String arg, Instrumentation instrumentation) {
try {
ExtensionList list = ExtensionList.parse(ExtensionsBootstrap.class.getResourceAsStream("/extensions"));

instrumentation.addTransformer(new ExtensionsClassFileTransformer(list), true);
instrumentation.retransformClasses(list.getAllTargets());
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException("Main class not found or main method not found.");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ru.kdev.extensions.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Extension {

/**
* Target classes
* */
Class<?>[] classes();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package ru.kdev.extensions.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Inject {

/**
* Target method(s)
* */
String[] method();

/**
* Target place
* */
At at();

/**
* Allows to change return node
* Only on bottom inject
* */
boolean changeReturn() default false;

enum At {
TOP,
BOTTOM
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ru.kdev.extensions.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TargetField {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ru.kdev.extensions.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TargetMethod {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ru.kdev.extensions.internal;

import org.objectweb.asm.Type;
import sun.misc.Unsafe;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public final class Util {

public static MethodHandles.Lookup TRUSTED_LOOKUP;
public static Unsafe UNSAFE;

public static String getMethodDescriptor(Method m) {
return Type.getMethodDescriptor(m);
}

static {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
UNSAFE = (Unsafe) theUnsafe.get(null);
Field implLookup = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
TRUSTED_LOOKUP = (MethodHandles.Lookup) UNSAFE.getObjectVolatile(UNSAFE.staticFieldBase(implLookup), UNSAFE.staticFieldOffset(implLookup));
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ru.kdev.extensions.processor;

import ru.kdev.extensions.ExtensionList;

import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;

public class ExtensionsClassFileTransformer implements ClassFileTransformer {

private final ExtensionList extensionList;

public ExtensionsClassFileTransformer(ExtensionList list) {
this.extensionList = list;
}

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
Class<?> extension = extensionList.getExtensionByTarget(classBeingRedefined);

if(extension != null) {
try {
return ExtensionsProcessor.process(extension, classBeingRedefined);
} catch (IOException e) {
e.printStackTrace();
}
}

return classfileBuffer;
}
}
Loading

0 comments on commit e4fa190

Please sign in to comment.