Skip to content
This repository was archived by the owner on Oct 16, 2020. It is now read-only.

Commit 0a30d71

Browse files
authored
Merge pull request #43 from spideruci/issue38
Blinky Config: Module for managing configurations
2 parents 866affb + bcfbc5e commit 0a30d71

33 files changed

+1724
-293
lines changed

blinky-config/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target/

blinky-config/pom.xml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<parent>
5+
<artifactId>blinky</artifactId>
6+
<groupId>org.spideruci.analysis</groupId>
7+
<version>0.0.1-SNAPSHOT</version>
8+
</parent>
9+
10+
<groupId>org.spideruci.analysis.config</groupId>
11+
<artifactId>blinky-config</artifactId>
12+
<version>0.0.1-SNAPSHOT</version>
13+
<packaging>jar</packaging>
14+
15+
<name>Blinky Config</name>
16+
<description>A compile-time configuration manager for Blinky Core</description>
17+
18+
<url>https://github.com/spideruci/blinky</url>
19+
20+
<properties>
21+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
22+
</properties>
23+
24+
<dependencies>
25+
<dependency>
26+
<groupId>com.esotericsoftware.yamlbeans</groupId>
27+
<artifactId>yamlbeans</artifactId>
28+
<version>1.08</version>
29+
</dependency>
30+
<dependency>
31+
<groupId>org.apache.maven</groupId>
32+
<artifactId>maven-plugin-api</artifactId>
33+
<version>2.0</version>
34+
</dependency>
35+
<dependency>
36+
<groupId>junit</groupId>
37+
<artifactId>junit</artifactId>
38+
<version>4.12</version>
39+
<scope>test</scope>
40+
</dependency>
41+
</dependencies>
42+
43+
<build>
44+
<resources>
45+
<resource><directory>src/test/resources</directory></resource>
46+
</resources>
47+
<plugins>
48+
<plugin>
49+
<artifactId>maven-assembly-plugin</artifactId>
50+
<configuration>
51+
<descriptorRefs>
52+
<descriptorRef>jar-with-dependencies</descriptorRef>
53+
</descriptorRefs>
54+
</configuration>
55+
<executions>
56+
<execution>
57+
<phase>compile</phase>
58+
<goals>
59+
<goal>single</goal>
60+
</goals>
61+
</execution>
62+
</executions>
63+
</plugin>
64+
65+
</plugins>
66+
</build>
67+
68+
</project>
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package org.spideruci.analysis.config;
2+
3+
import java.io.File;
4+
import java.io.FileReader;
5+
import java.io.IOException;
6+
import java.io.Reader;
7+
import java.util.Collection;
8+
import java.util.Map;
9+
10+
import org.apache.maven.plugin.logging.Log;
11+
import org.apache.maven.plugin.logging.SystemStreamLog;
12+
13+
import com.esotericsoftware.yamlbeans.YamlConfig;
14+
import com.esotericsoftware.yamlbeans.YamlReader;
15+
16+
public class ConfigFile {
17+
18+
private final File file;
19+
20+
public static ConfigFile create(String fileName) {
21+
return create(fileName, new SystemStreamLog());
22+
}
23+
24+
public static ConfigFile create(String fileName, final Log log) {
25+
File configfile = getFile(fileName, log);
26+
ConfigFile configFile = new ConfigFile(configfile);
27+
return configFile;
28+
}
29+
30+
private static File getFile(String fileName, Log log) {
31+
32+
log.debug(String.format("Using config file: %s", fileName));
33+
File file = new File(fileName);
34+
35+
final boolean configNotExists = !file.exists();
36+
final boolean configNotFile = !file.isFile();
37+
final boolean configIsDirectory = file.isDirectory();
38+
39+
if(configNotExists || configNotFile || configIsDirectory) {
40+
log.debug(String.format("Config doesn't exist? %B", configNotExists));
41+
log.debug(String.format("Config not a file? %B", configNotFile));
42+
log.debug(String.format("Config is a directory? %B", configIsDirectory));
43+
44+
final String invalidFileMessage =
45+
String.format("No valid config file at %s", file.toString());
46+
log.error(invalidFileMessage);
47+
48+
throw new RuntimeException(invalidFileMessage);
49+
}
50+
51+
log.info(String.format("Valid config file available at %s", file.toString()));
52+
return file;
53+
}
54+
55+
private ConfigFile(final File file) {
56+
this.file = file;
57+
}
58+
59+
public File getFile() {
60+
return this.file;
61+
}
62+
63+
public Map<String, ?> readConfig() {
64+
65+
try {
66+
Reader reader = new FileReader(this.file);
67+
YamlConfig readerConfig = new YamlConfig();
68+
readerConfig.setClassTag("tag:yaml.org,2002:bool", Boolean.class);
69+
70+
YamlReader configReader = new YamlReader(reader, readerConfig);
71+
Object config = configReader.read();
72+
73+
@SuppressWarnings("unchecked")
74+
Map<String, ?> map = (Map<String, ?>) config;
75+
76+
configReader.close();
77+
78+
return map;
79+
80+
} catch (IOException e) {
81+
throw new RuntimeException(e);
82+
}
83+
}
84+
85+
public static void logConfig(Map<String, ?> map, Log log) {
86+
for(String key : map.keySet()) {
87+
Object value = map.get(key);
88+
System.out.println(key + " " + ((value == null) ? "null" : value.getClass()));
89+
if(value instanceof Collection) {
90+
91+
@SuppressWarnings("rawtypes")
92+
Collection collection = (Collection) value;
93+
for(Object item : collection) {
94+
log.debug("\t" + item.getClass());
95+
break;
96+
}
97+
98+
}
99+
}
100+
}
101+
102+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package org.spideruci.analysis.config;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.io.PrintStream;
6+
import java.nio.file.Files;
7+
import java.nio.file.Path;
8+
import java.nio.file.Paths;
9+
import java.util.Map;
10+
11+
import org.apache.maven.plugin.logging.Log;
12+
import org.apache.maven.plugin.logging.SystemStreamLog;
13+
import org.spideruci.analysis.config.definer.ConfigFieldsDefiner;
14+
15+
public class Main {
16+
17+
public final static String JAVA_PKG_SEP = "/";
18+
19+
private static final String CONFIG_FILEPATH = "config.filepath";
20+
private static final String CONFIG_CLASSNAME = "config.classname";
21+
private static final String CONFIG_COMPILEDOUTPUT = "config.compiledoutput";
22+
23+
public static final Log log = new SystemStreamLog();
24+
public static Log getLog() {
25+
return log;
26+
}
27+
28+
public static void main(String[] args) {
29+
final String introMessage =
30+
String.format("Setting up Compile-time configurations for BLINKY CORE!");
31+
log.info(introMessage);
32+
33+
final String configFilePath = System.getProperty(CONFIG_FILEPATH);
34+
35+
ConfigFile conf = ConfigFile.create(configFilePath);
36+
Map<String, ?> config = conf.readConfig();
37+
38+
final String configClassName = System.getProperty(CONFIG_CLASSNAME);
39+
final String className = configClassName.replaceAll("\\.", JAVA_PKG_SEP);
40+
41+
Path configClassPath = getConfigClassPath(className);
42+
File configClassFile = configClassPath.toFile();
43+
44+
byte[] modBytecode =
45+
ConfigFieldsDefiner.define(className, configClassFile, config);
46+
47+
writeToClassFile(modBytecode, configClassPath.toString());
48+
}
49+
50+
private static boolean isClassNameValid(String className) {
51+
return className != null && className.length() != 0;
52+
}
53+
54+
private static Path getConfigClassPath(String className) {
55+
if(!isClassNameValid(className)) {
56+
getLog().error(String.format("Invalid class name: %s", className));
57+
throw new RuntimeException();
58+
}
59+
60+
final String targetClasses = System.getProperty(CONFIG_COMPILEDOUTPUT);
61+
Path path = Paths.get(targetClasses);
62+
63+
if(Files.exists(path)) {
64+
getLog().info(path.toString());
65+
} else {
66+
getLog().error("Unable to find the classes directory :(");
67+
throw new RuntimeException();
68+
}
69+
70+
String[] classNameSplit = className.split(JAVA_PKG_SEP);
71+
for(int i = 0; i <= classNameSplit.length - 2; i += 1) {
72+
final String splitItem = classNameSplit[i];
73+
Path temp = path.resolve(splitItem);
74+
if(!Files.exists(temp)) {
75+
final String errMsg =
76+
String.format("Path is invalid: %s", String.valueOf(temp));
77+
78+
getLog().error(errMsg);
79+
throw new RuntimeException(errMsg);
80+
}
81+
82+
path = temp;
83+
}
84+
85+
Path configClassPath =
86+
path.resolve(classNameSplit[classNameSplit.length - 1] + ".class");
87+
final String confClsPathName = configClassPath.toString();
88+
if(Files.exists(configClassPath)) {
89+
getLog().info(String.format("Updating config class: %s", confClsPathName));
90+
} else {
91+
final String errMsg = String.format("Path invalid: %s", confClsPathName);
92+
getLog().error(errMsg);
93+
throw new RuntimeException(errMsg);
94+
}
95+
96+
return configClassPath;
97+
}
98+
99+
private static void writeToClassFile(byte[] bytecode, String filePath) {
100+
try {
101+
PrintStream byteStream = new PrintStream(filePath);
102+
byteStream.write(bytecode);
103+
byteStream.close();
104+
} catch(IOException ex) {
105+
throw new RuntimeException(ex);
106+
}
107+
}
108+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package org.spideruci.analysis.config.definer;
2+
3+
import java.io.File;
4+
import java.io.FileInputStream;
5+
import java.io.IOException;
6+
import java.io.PrintWriter;
7+
import java.io.StringWriter;
8+
9+
import org.objectweb.asm.ClassReader;
10+
import org.objectweb.asm.ClassVisitor;
11+
import org.objectweb.asm.ClassWriter;
12+
import org.objectweb.asm.util.CheckClassAdapter;
13+
14+
public class ClassAdapterRunner {
15+
16+
private final ClassReader classReader;
17+
private final ClassVisitor classAdapter;
18+
private final ClassWriter classWriter;
19+
20+
public static ClassAdapterRunner create(
21+
PrototypicalClassAdapter classAdapter, File classFile) {
22+
23+
ClassWriter cw = classAdapter.getClassWriter();
24+
ClassVisitor ca = classAdapter;
25+
ClassReader cr = getClassReader(classFile);
26+
27+
ClassAdapterRunner runner = new ClassAdapterRunner(cr, ca, cw);
28+
return runner;
29+
}
30+
31+
public static ClassAdapterRunner create(
32+
PrototypicalClassAdapter classAdapter,
33+
byte[] bytecode) {
34+
35+
ClassWriter cw = classAdapter.getClassWriter();
36+
ClassVisitor ca = classAdapter;
37+
ClassReader cr = new ClassReader(bytecode);
38+
39+
ClassAdapterRunner runner = new ClassAdapterRunner(cr, ca, cw);
40+
return runner;
41+
}
42+
43+
public static ClassAdapterRunner create(
44+
PrototypicalClassNode classAdapter,
45+
File classFile) {
46+
47+
ClassWriter cw = classAdapter.getClassWriter();
48+
ClassVisitor ca = classAdapter;
49+
ClassReader cr = getClassReader(classFile);
50+
51+
ClassAdapterRunner runner = new ClassAdapterRunner(cr, ca, cw);
52+
return runner;
53+
}
54+
55+
/**
56+
* @param bytecode
57+
* @param classFile
58+
* @return
59+
*/
60+
private static ClassReader getClassReader(File classFile) {
61+
if(classFile == null) {
62+
throw new RuntimeException("classfile is null.");
63+
}
64+
65+
try {
66+
FileInputStream in = new FileInputStream(classFile);
67+
ClassReader cr = new ClassReader(in);
68+
return cr;
69+
} catch(IOException ioEx ) {
70+
ioEx.printStackTrace();
71+
throw new RuntimeException(ioEx.getMessage());
72+
}
73+
}
74+
75+
public ClassAdapterRunner(ClassReader cr, ClassVisitor ca, ClassWriter cw) {
76+
this.classReader = cr;
77+
this.classAdapter = ca;
78+
this.classWriter = cw;
79+
}
80+
81+
/**
82+
* Adapts, i.e. transforms, the classfile based off the given class adapter,
83+
* and returns the adapted, i.e. transformed, classfile.
84+
*
85+
* @return the bytecode for the adapted classfile.
86+
*/
87+
public byte[] run() {
88+
byte[] bytecode = this.classReader.b;
89+
90+
try {
91+
classReader.accept(classAdapter, ClassReader.EXPAND_FRAMES);
92+
bytecode = classWriter.toByteArray();
93+
checkBytecode(bytecode);
94+
return bytecode;
95+
} catch (Exception e) {
96+
e.printStackTrace();
97+
throw e;
98+
}
99+
}
100+
101+
private static boolean debug = false;
102+
private void checkBytecode(byte[] bytecode2) {
103+
if(!debug) {
104+
return;
105+
}
106+
107+
StringWriter sw = new StringWriter();
108+
PrintWriter pw = new PrintWriter(sw);
109+
CheckClassAdapter.verify(new ClassReader(bytecode2), false, pw);
110+
if(sw.toString().length() != 0) {
111+
System.err.println(sw.toString());
112+
throw new RuntimeException();
113+
}
114+
}
115+
116+
}

0 commit comments

Comments
 (0)