Remove http:.. prefix from logging in SCL
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / java / LoggingModule.java
1 package org.simantics.scl.compiler.elaboration.java;
2
3 import org.cojen.classfile.TypeDesc;
4 import org.osgi.service.component.annotations.Component;
5 import org.simantics.scl.compiler.commands.CommandSession;
6 import org.simantics.scl.compiler.common.names.Name;
7 import org.simantics.scl.compiler.compilation.CompilationContext;
8 import org.simantics.scl.compiler.constants.JavaMethod;
9 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
10 import org.simantics.scl.compiler.elaboration.expressions.EApply;
11 import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;
12 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
13 import org.simantics.scl.compiler.elaboration.expressions.Expression;
14 import org.simantics.scl.compiler.elaboration.macros.MacroRule;
15 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
16 import org.simantics.scl.compiler.internal.codegen.types.StandardTypeConstructor;
17 import org.simantics.scl.compiler.module.ConcreteModule;
18 import org.simantics.scl.compiler.types.TCon;
19 import org.simantics.scl.compiler.types.Type;
20 import org.simantics.scl.compiler.types.Types;
21 import org.simantics.scl.compiler.types.kinds.Kinds;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24 import org.slf4j.Marker;
25
26 @Component
27 public class LoggingModule extends ConcreteModule {
28
29     private static final String[] LOGGING_METHODS = new String[] {
30             "trace", "debug", "info", "warn", "error" 
31     };
32     
33     public static final TCon Throwable = Types.con("Prelude", "Throwable");
34
35     public LoggingModule() {
36         super("LoggingJava");
37         
38         // Logger
39         TCon Logger = Types.con(getName(), "Logger");
40         StandardTypeConstructor loggerConstructor = new StandardTypeConstructor(Logger, Kinds.STAR, TypeDesc.forClass(Logger.class));
41         loggerConstructor.external = true;
42         addTypeDescriptor("Logger", loggerConstructor);
43
44         // Marker
45         TCon Marker = Types.con(getName(), "Marker");
46         StandardTypeConstructor markerConstructor = new StandardTypeConstructor(Marker, Kinds.STAR, TypeDesc.forClass(Marker.class));
47         markerConstructor.external = true;
48         addTypeDescriptor("Marker", markerConstructor);
49         
50         // Common types
51         Type isEnabledType = Types.functionE(Types.PUNIT, Types.PROC, Types.BOOLEAN);
52         Type loggingType = Types.functionE(Types.STRING, Types.PROC, Types.UNIT);
53         Type loggingTypeWithMarker = Types.functionE(new Type[] { Marker, Types.STRING }, Types.PROC, Types.UNIT);
54         Type loggingTypeWithException = Types.functionE(new Type[] { Types.STRING, Throwable }, Types.PROC, Types.UNIT);
55         Type loggingTypeWithMarkerAndException = Types.functionE(new Type[] { Marker, Types.STRING, Throwable }, Types.PROC, Types.UNIT);
56
57         // Add logging methods
58         for(String methodName : LOGGING_METHODS) {
59             { // isEnabled :: <Proc> Boolean
60                 String completeMethodName = generateIsEnabledName(methodName);
61                 JavaMethod javaMethod = new JavaMethod(false, "org/slf4j/Logger", completeMethodName, Types.PROC, Types.BOOLEAN, Logger);
62                 SCLValue value = new SCLValue(Name.create(getName(), completeMethodName));
63                 value.setType(isEnabledType);
64                 value.setMacroRule(new MacroRule() {
65                     @Override
66                     public Expression apply(SimplificationContext context, Type[] typeParameters, EApply apply) {
67                         String identifier = resolveModuleIdentifier(context.getCompilationContext());
68                         apply.set(new ELiteral(javaMethod), new Expression[] {
69                                 new EExternalConstant(LoggerFactory.getLogger(identifier), Logger)
70                         });
71                         return apply;
72                     }
73                 });
74                 addValue(value);
75             }
76             { // logging function with single String-parameter :: String -> <Proc> ()
77                 JavaMethod javaMethod = new JavaMethod(false, "org/slf4j/Logger", methodName, Types.PROC, Types.UNIT, Logger, Types.STRING);
78                 SCLValue value = new SCLValue(Name.create(getName(), methodName));
79                 value.setType(loggingType);
80                 value.setMacroRule(new MacroRule() {
81                     @Override
82                     public Expression apply(SimplificationContext context, Type[] typeParameters, EApply apply) {
83                         String identifier = resolveModuleIdentifier(context.getCompilationContext());
84                         apply.set(new ELiteral(javaMethod), new Expression[] {
85                                 new EExternalConstant(LoggerFactory.getLogger(identifier), Logger),
86                                 apply.parameters[0]
87                         });
88                         return apply;
89                     }
90                 });
91                 addValue(value);
92             }
93             { // logging function with two parameters  :: String -> Throwable -> <Proc> ()
94                 JavaMethod javaMethod = new JavaMethod(false, "org/slf4j/Logger", methodName, Types.PROC, Types.UNIT, Logger, Types.STRING, Throwable);
95                 SCLValue value = new SCLValue(Name.create(getName(), methodName + "E"));
96                 value.setType(loggingTypeWithException);
97                 value.setMacroRule(new MacroRule() {
98                     @Override
99                     public Expression apply(SimplificationContext context, Type[] typeParameters, EApply apply) {
100                         String identifier = resolveModuleIdentifier(context.getCompilationContext());
101                         apply.set(new ELiteral(javaMethod), new Expression[] {
102                                 new EExternalConstant(LoggerFactory.getLogger(identifier), Logger),
103                                 apply.parameters[0],
104                                 apply.parameters[1]
105                         });
106                         return apply;
107                     }
108                 });
109                 addValue(value);
110             }
111             { // logging function with two parameters  :: Marker -> String -> <Proc> ()
112                 JavaMethod javaMethod = new JavaMethod(false, "org/slf4j/Logger", methodName, Types.PROC, Types.UNIT, Logger, Marker, Types.STRING);
113                 SCLValue value = new SCLValue(Name.create(getName(), methodName + "M"));
114                 value.setType(loggingTypeWithMarker);
115                 value.setMacroRule(new MacroRule() {
116                     @Override
117                     public Expression apply(SimplificationContext context, Type[] typeParameters, EApply apply) {
118                         String identifier = resolveModuleIdentifier(context.getCompilationContext());
119                         apply.set(new ELiteral(javaMethod), new Expression[] {
120                                 new EExternalConstant(LoggerFactory.getLogger(identifier), Logger),
121                                 apply.parameters[0],
122                                 apply.parameters[1]
123                         });
124                         return apply;
125                     }
126                 });
127                 addValue(value);
128             }
129             { // logging function with three parameters  :: Marker -> String -> Throwable -> <Proc> ()
130                 JavaMethod javaMethod = new JavaMethod(false, "org/slf4j/Logger", methodName, Types.PROC, Types.UNIT, Logger, Marker, Types.STRING, Throwable);
131                 SCLValue value = new SCLValue(Name.create(getName(), methodName + "ME"));
132                 value.setType(loggingTypeWithMarkerAndException);
133                 value.setMacroRule(new MacroRule() {
134                     @Override
135                     public Expression apply(SimplificationContext context, Type[] typeParameters, EApply apply) {
136                         String identifier = resolveModuleIdentifier(context.getCompilationContext());
137                         apply.set(new ELiteral(javaMethod), new Expression[] {
138                                 new EExternalConstant(LoggerFactory.getLogger(identifier), Logger),
139                                 apply.parameters[0],
140                                 apply.parameters[1],
141                                 apply.parameters[2]
142                         });
143                         return apply;
144                     }
145                 });
146                 addValue(value);
147             }
148         }
149         
150         setParentClassLoader(LoggerFactory.class.getClassLoader());
151     }
152
153     private static String generateIsEnabledName(String level) {
154         return "is" + capitalizeFirstCharacter(level) + "Enabled";
155     }
156     
157     private static String capitalizeFirstCharacter(String input) {
158         return input.substring(0, 1).toUpperCase() + input.substring(1);
159     }
160     
161     private static String resolveModuleIdentifier(CompilationContext context) {
162         ConcreteModule module = context.module;
163         String identifier;
164         if (module != null) {
165             String moduleName = module.getName();
166             if (moduleName.startsWith("http://")) {
167                 moduleName = moduleName.substring("http://".length());
168             }
169             identifier = moduleName.replaceAll("/", ".");
170         } else {
171             identifier = CommandSession.class.getName();
172         }
173         return identifier;
174     }
175 }