1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.submitted.language;
17
18 import java.io.StringReader;
19 import java.io.StringWriter;
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import org.apache.ibatis.builder.BuilderException;
24 import org.apache.ibatis.mapping.BoundSql;
25 import org.apache.ibatis.mapping.SqlSource;
26 import org.apache.ibatis.session.Configuration;
27 import org.apache.velocity.Template;
28 import org.apache.velocity.VelocityContext;
29 import org.apache.velocity.app.Velocity;
30 import org.apache.velocity.runtime.RuntimeServices;
31 import org.apache.velocity.runtime.RuntimeSingleton;
32 import org.apache.velocity.runtime.parser.node.SimpleNode;
33
34
35
36
37 public class VelocitySqlSource implements SqlSource {
38
39 public static final String PARAMETER_OBJECT_KEY = "_parameter";
40 public static final String DATABASE_ID_KEY = "_databaseId";
41
42 private final Configuration configuration;
43 private final Template script;
44
45 static {
46 Velocity.setProperty("runtime.log", "target/velocity.log");
47 Velocity.init();
48 }
49
50 public VelocitySqlSource(Configuration configuration, String scriptText) {
51 this.configuration = configuration;
52 try {
53 RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
54 StringReader reader = new StringReader(scriptText);
55 Template template = new Template();
56 template.setName("Template name");
57 SimpleNode node = runtimeServices.parse(reader, template);
58 script = new Template();
59 script.setRuntimeServices(runtimeServices);
60 script.setData(node);
61 script.initDocument();
62 } catch (Exception ex) {
63 throw new BuilderException("Error parsing velocity script", ex);
64 }
65 }
66
67 @Override
68 public BoundSql getBoundSql(Object parameterObject) {
69 Map<String, Object> bindings = createBindings(parameterObject, configuration);
70 VelocityContext context = new VelocityContext(bindings);
71 StringWriter sw = new StringWriter();
72 script.merge(context, sw);
73 VelocitySqlSourceBuilder sqlSourceParser = new VelocitySqlSourceBuilder(configuration);
74 Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
75 SqlSource sqlSource = sqlSourceParser.parse(sw.toString(), parameterType);
76 BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
77 for (Map.Entry<String, Object> entry : bindings.entrySet()) {
78 boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
79 }
80 return boundSql;
81
82 }
83
84 public static Map<String, Object> createBindings(Object parameterObject, Configuration configuration) {
85 Map<String, Object> bindings = new HashMap<>();
86 bindings.put(PARAMETER_OBJECT_KEY, parameterObject);
87 bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId());
88 bindings.put("it", new IteratorParameter(bindings));
89 return bindings;
90 }
91
92 public static class IteratorParameter {
93
94 private static final String PREFIX = "__frch_";
95 private int count;
96 private final Map<String, Object> bindings;
97
98 public IteratorParameter(Map<String, Object> bindings) {
99 this.bindings = bindings;
100 }
101
102 public String next(Object prop) {
103 StringBuilder sb = new StringBuilder();
104 String name = sb.append(PREFIX).append("_ITEM").append("_").append(count++).toString();
105 bindings.put(name, prop);
106 return name;
107 }
108 }
109 }