diff --git a/pom.xml b/pom.xml index abe9225e6..43fca8ac3 100644 --- a/pom.xml +++ b/pom.xml @@ -83,6 +83,7 @@ teavm-cli teavm-chrome-rdp teavm-tests + teavm-extras-slf4j diff --git a/teavm-extras-slf4j/.gitignore b/teavm-extras-slf4j/.gitignore new file mode 100644 index 000000000..8bd3a0588 --- /dev/null +++ b/teavm-extras-slf4j/.gitignore @@ -0,0 +1,4 @@ +/target/ +/.settings/ +/.classpath +/.project diff --git a/teavm-extras-slf4j/pom.xml b/teavm-extras-slf4j/pom.xml new file mode 100644 index 000000000..ddf2d0477 --- /dev/null +++ b/teavm-extras-slf4j/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + + org.teavm + teavm + 0.3.0-SNAPSHOT + + teavm-extras-slf4j + + TeaVM slf4j + TeaVM backend for slf4j + + + + org.teavm + teavm-core + ${project.version} + provided + + + org.teavm + teavm-jso + ${project.version} + + + org.slf4j + slf4j-api + provided + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + ../checkstyle.xml + + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + \ No newline at end of file diff --git a/teavm-extras-slf4j/src/main/java/org/teavm/extras/slf4j/LoggerFactoryTransformer.java b/teavm-extras-slf4j/src/main/java/org/teavm/extras/slf4j/LoggerFactoryTransformer.java new file mode 100644 index 000000000..14bd34520 --- /dev/null +++ b/teavm-extras-slf4j/src/main/java/org/teavm/extras/slf4j/LoggerFactoryTransformer.java @@ -0,0 +1,81 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.extras.slf4j; + +import org.slf4j.ILoggerFactory; +import org.slf4j.LoggerFactory; +import org.teavm.diagnostics.Diagnostics; +import org.teavm.model.*; +import org.teavm.model.instructions.*; + +/** + * + * @author Alexey Andreev + */ +public class LoggerFactoryTransformer implements ClassHolderTransformer { + @Override + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { + if (!cls.getName().equals(LoggerFactory.class.getName())) { + return; + } + addCacheField(cls); + modifyClinit(cls); + replaceGetFactory(cls); + } + + private void addCacheField(ClassHolder cls) { + FieldHolder cacheField = new FieldHolder("loggerFactoryCache"); + cacheField.setLevel(AccessLevel.PRIVATE); + cacheField.getModifiers().add(ElementModifier.STATIC); + cacheField.setType(ValueType.object(TeaVMLoggerFactory.class.getName())); + cls.addField(cacheField); + } + + private void modifyClinit(ClassHolder cls) { + MethodHolder clinit = cls.getMethod(new MethodDescriptor("", void.class)); + BasicBlock clinitBlock = clinit.getProgram().basicBlockAt(0); + Variable factoryVar = clinit.getProgram().createVariable(); + ConstructInstruction construct = new ConstructInstruction(); + construct.setType(TeaVMLoggerFactory.class.getName()); + construct.setReceiver(factoryVar); + clinitBlock.getInstructions().add(0, construct); + InvokeInstruction init = new InvokeInstruction(); + init.setInstance(factoryVar); + init.setMethod(new MethodReference(TeaVMLoggerFactory.class, "", void.class)); + init.setType(InvocationType.SPECIAL); + clinitBlock.getInstructions().add(1, init); + PutFieldInstruction put = new PutFieldInstruction(); + put.setValue(factoryVar); + put.setField(new FieldReference(LoggerFactory.class.getName(), "loggerFactoryCache")); + clinitBlock.getInstructions().add(2, put); + } + + private void replaceGetFactory(ClassHolder cls) { + MethodHolder method = cls.getMethod(new MethodDescriptor("getILoggerFactory", ILoggerFactory.class)); + Program program = new Program(); + BasicBlock block = program.createBasicBlock(); + Variable cacheVar = program.createVariable(); + GetFieldInstruction get = new GetFieldInstruction(); + get.setField(new FieldReference(LoggerFactory.class.getName(), "loggerFactoryCache")); + get.setFieldType(ValueType.object(ILoggerFactory.class.getName())); + get.setReceiver(cacheVar); + block.getInstructions().add(get); + ExitInstruction exit = new ExitInstruction(); + exit.setValueToReturn(cacheVar); + block.getInstructions().add(exit); + method.setProgram(program); + } +} diff --git a/teavm-extras-slf4j/src/main/java/org/teavm/extras/slf4j/Slf4jPlugin.java b/teavm-extras-slf4j/src/main/java/org/teavm/extras/slf4j/Slf4jPlugin.java new file mode 100644 index 000000000..74502095e --- /dev/null +++ b/teavm-extras-slf4j/src/main/java/org/teavm/extras/slf4j/Slf4jPlugin.java @@ -0,0 +1,30 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.extras.slf4j; + +import org.teavm.vm.spi.TeaVMHost; +import org.teavm.vm.spi.TeaVMPlugin; + +/** + * + * @author Alexey Andreev + */ +public class Slf4jPlugin implements TeaVMPlugin { + @Override + public void install(TeaVMHost host) { + host.add(new LoggerFactoryTransformer()); + } +} \ No newline at end of file diff --git a/teavm-extras-slf4j/src/main/java/org/teavm/extras/slf4j/TeaVMLogger.java b/teavm-extras-slf4j/src/main/java/org/teavm/extras/slf4j/TeaVMLogger.java new file mode 100644 index 000000000..2d95dc16b --- /dev/null +++ b/teavm-extras-slf4j/src/main/java/org/teavm/extras/slf4j/TeaVMLogger.java @@ -0,0 +1,335 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.extras.slf4j; + +import org.slf4j.Logger; +import org.slf4j.Marker; + +/** + * + * @author Alexey Andreev + */ +public class TeaVMLogger implements Logger { + private String name; + + public TeaVMLogger(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean isTraceEnabled() { + return false; + } + + @Override + public void trace(String msg) { + } + + @Override + public void trace(String format, Object arg) { + } + + @Override + public void trace(String format, Object arg1, Object arg2) { + } + + @Override + public void trace(String format, Object... arguments) { + } + + @Override + public void trace(String msg, Throwable t) { + } + + @Override + public boolean isTraceEnabled(Marker marker) { + return false; + } + + @Override + public void trace(Marker marker, String msg) { + } + + @Override + public void trace(Marker marker, String format, Object arg) { + } + + @Override + public void trace(Marker marker, String format, Object arg1, Object arg2) { + } + + @Override + public void trace(Marker marker, String format, Object... argArray) { + } + + @Override + public void trace(Marker marker, String msg, Throwable t) { + } + + @Override + public boolean isDebugEnabled() { + return false; + } + + @Override + public void debug(String msg) { + } + + @Override + public void debug(String format, Object arg) { + } + + @Override + public void debug(String format, Object arg1, Object arg2) { + } + + @Override + public void debug(String format, Object... arguments) { + } + + @Override + public void debug(String msg, Throwable t) { + } + + @Override + public boolean isDebugEnabled(Marker marker) { + return false; + } + + @Override + public void debug(Marker marker, String msg) { + } + + @Override + public void debug(Marker marker, String format, Object arg) { + } + + @Override + public void debug(Marker marker, String format, Object arg1, Object arg2) { + } + + @Override + public void debug(Marker marker, String format, Object... arguments) { + } + + @Override + public void debug(Marker marker, String msg, Throwable t) { + } + + @Override + public boolean isInfoEnabled() { + return true; + } + + private void log(String level, String format, Object... arguments) { + StringBuffer sb = new StringBuffer(); + sb.append('[').append(level).append("] ").append(name).append(": "); + int index = 0; + int argIndex = 0; + while (index < format.length()) { + int next = format.indexOf("{}", index); + if (next == -1) { + break; + } + sb.append(format.subSequence(index, next)); + sb.append(argIndex < arguments.length ? String.valueOf(arguments[argIndex]) : "{}"); + index = next + 2; + ++argIndex; + } + sb.append(format.substring(index)); + System.err.println(sb); + } + + @Override + public void info(String msg) { + info(msg, new Object[0]); + } + + @Override + public void info(String format, Object arg) { + info(format, new Object[] { arg }); + } + + @Override + public void info(String format, Object arg1, Object arg2) { + info(format, new Object[] { arg1, arg2 }); + } + + @Override + public void info(String format, Object... arguments) { + log("INFO", format, arguments); + } + + @Override + public void info(String msg, Throwable t) { + info(msg); + } + + @Override + public boolean isInfoEnabled(Marker marker) { + return true; + } + + @Override + public void info(Marker marker, String msg) { + info(msg); + } + + @Override + public void info(Marker marker, String format, Object arg) { + info(format, arg); + } + + @Override + public void info(Marker marker, String format, Object arg1, Object arg2) { + info(format, arg1, arg2); + } + + @Override + public void info(Marker marker, String format, Object... arguments) { + info(format, arguments); + } + + @Override + public void info(Marker marker, String msg, Throwable t) { + info(msg, t); + } + + @Override + public boolean isWarnEnabled() { + return true; + } + + @Override + public void warn(String msg) { + warn(msg, new Object[0]); + } + + @Override + public void warn(String format, Object arg) { + warn(format, new Object[] { arg }); + } + + @Override + public void warn(String format, Object... arguments) { + log("WARN", format, arguments); + } + + @Override + public void warn(String format, Object arg1, Object arg2) { + warn(format, new Object[] { arg1, arg2 }); + } + + @Override + public void warn(String msg, Throwable t) { + warn(msg); + } + + @Override + public boolean isWarnEnabled(Marker marker) { + return true; + } + + @Override + public void warn(Marker marker, String msg) { + warn(msg); + } + + @Override + public void warn(Marker marker, String format, Object arg) { + warn(format, arg); + } + + @Override + public void warn(Marker marker, String format, Object arg1, Object arg2) { + warn(format, arg1, arg2); + } + + @Override + public void warn(Marker marker, String format, Object... arguments) { + warn(format, arguments); + } + + @Override + public void warn(Marker marker, String msg, Throwable t) { + warn(msg, t); + } + + @Override + public boolean isErrorEnabled() { + return true; + } + + @Override + public void error(String msg) { + error(msg, new Object[0]); + } + + @Override + public void error(String format, Object arg) { + error(format, new Object[] { arg }); + } + + @Override + public void error(String format, Object arg1, Object arg2) { + error(format, new Object[] { arg1, arg2 }); + } + + @Override + public void error(String format, Object... arguments) { + log("ERRO", format, arguments); + } + + @Override + public void error(String msg, Throwable t) { + error(msg); + } + + @Override + public boolean isErrorEnabled(Marker marker) { + return true; + } + + @Override + public void error(Marker marker, String msg) { + error(msg); + } + + @Override + public void error(Marker marker, String format, Object arg) { + error(format, arg); + } + + @Override + public void error(Marker marker, String format, Object arg1, Object arg2) { + error(format, arg1, arg2); + } + + @Override + public void error(Marker marker, String format, Object... arguments) { + error(format, arguments); + } + + @Override + public void error(Marker marker, String msg, Throwable t) { + error(msg, t); + } +} diff --git a/teavm-extras-slf4j/src/main/java/org/teavm/extras/slf4j/TeaVMLoggerFactory.java b/teavm-extras-slf4j/src/main/java/org/teavm/extras/slf4j/TeaVMLoggerFactory.java new file mode 100644 index 000000000..5eaf09800 --- /dev/null +++ b/teavm-extras-slf4j/src/main/java/org/teavm/extras/slf4j/TeaVMLoggerFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.extras.slf4j; + +import java.util.HashMap; +import java.util.Map; +import org.slf4j.ILoggerFactory; +import org.slf4j.Logger; + +/** + * + * @author Alexey Andreev + */ +public class TeaVMLoggerFactory implements ILoggerFactory { + private Map loggers = new HashMap<>(); + + @Override + public Logger getLogger(String name) { + TeaVMLogger logger = loggers.get(name); + if (logger == null) { + logger = new TeaVMLogger(name); + loggers.put(name, logger); + } + return logger; + } +} \ No newline at end of file diff --git a/teavm-extras-slf4j/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin b/teavm-extras-slf4j/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin new file mode 100644 index 000000000..e045db3fd --- /dev/null +++ b/teavm-extras-slf4j/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin @@ -0,0 +1 @@ +org.teavm.extras.slf4j.Slf4jPlugin \ No newline at end of file diff --git a/teavm-samples/teavm-samples-async/pom.xml b/teavm-samples/teavm-samples-async/pom.xml index 23133d3ec..99a38de06 100644 --- a/teavm-samples/teavm-samples-async/pom.xml +++ b/teavm-samples/teavm-samples-async/pom.xml @@ -33,6 +33,7 @@ org.teavm teavm-classlib ${project.version} + provided