1 package org.apidesign.livedb.impl;
3 import java.io.IOException;
5 import java.sql.CallableStatement;
6 import java.sql.Connection;
7 import java.sql.DatabaseMetaData;
8 import java.sql.Driver;
9 import java.sql.ResultSet;
10 import java.sql.ResultSetMetaData;
11 import java.sql.SQLException;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.Map.Entry;
16 import java.util.Properties;
17 import java.util.ServiceLoader;
19 import javax.annotation.processing.AbstractProcessor;
20 import javax.annotation.processing.Completion;
21 import javax.annotation.processing.Completions;
22 import javax.annotation.processing.Filer;
23 import javax.annotation.processing.Processor;
24 import javax.annotation.processing.RoundEnvironment;
25 import javax.annotation.processing.SupportedAnnotationTypes;
26 import javax.annotation.processing.SupportedSourceVersion;
27 import javax.lang.model.SourceVersion;
28 import javax.lang.model.element.AnnotationMirror;
29 import javax.lang.model.element.AnnotationValue;
30 import javax.lang.model.element.Element;
31 import javax.lang.model.element.ExecutableElement;
32 import javax.lang.model.element.PackageElement;
33 import javax.lang.model.element.TypeElement;
34 import javax.tools.Diagnostic;
35 import javax.tools.JavaFileObject;
36 import org.apidesign.livedb.LiveDB;
37 import org.openide.util.lookup.ServiceProvider;
41 * @author Jaroslav Tulach <jtulach@netbeans.org>
43 // BEGIN: livedb.processor
44 @SupportedAnnotationTypes("org.apidesign.livedb.LiveDB")
45 @SupportedSourceVersion(SourceVersion.RELEASE_6)
46 @ServiceProvider(service=Processor.class)
47 public final class LiveDBProcessor extends AbstractProcessor {
49 public boolean process(
50 Set<? extends TypeElement> annotations, RoundEnvironment roundEnv
52 final Filer filer = processingEnv.getFiler();
53 for (Element e : roundEnv.getElementsAnnotatedWith(LiveDB.class)) {
54 LiveDB db = e.getAnnotation(LiveDB.class);
55 PackageElement pe = (PackageElement)e;
56 String clsName = pe.getQualifiedName() + "." + db.classname();
58 JavaFileObject src = filer.createSourceFile(clsName, pe);
59 Writer w = src.openWriter();
60 Connection c = getConnection(
61 db.url(), db.user(), db.password()
63 CallableStatement s = c.prepareCall(db.query());
64 ResultSet rs = s.executeQuery();
65 ResultSetMetaData md = rs.getMetaData();
66 generateClassHeader(w, pe, db);
67 w.append("class " + db.classname() + " {\n");
68 for (int i = 1; i <= md.getColumnCount(); i++) {
69 generateField(w, md, i);
71 generateConstructor(w, db, md);
72 generateQueryMethod(w, db, md);
75 } catch (IOException | SQLException ex) {
76 processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, ex.getMessage(), e);
81 // FINISH: livedb.processor
83 private void generateQueryMethod(Writer w, LiveDB db, ResultSetMetaData md) throws SQLException, IOException {
84 w.append(" public static List<" + db.classname() + "> ")
85 .append("query() throws SQLException {\n");
86 w.append(" Connection c = DriverManager.getConnection(\"")
87 .append(db.url()).append("\", \"")
88 .append(db.user()).append("\", \"")
89 .append(db.password()).append("\");\n");
90 w.append(" List<").append(db.classname())
91 .append("> res = new ArrayList<")
92 .append(db.classname()).append(">();\n");
93 w.append(" CallableStatement s = c.prepareCall(\"")
94 .append(db.query()).append("\");\n");
95 w.append(" ResultSet rs = s.executeQuery();\n");
96 w.append(" ResultSetMetaData md = rs.getMetaData();\n");
97 w.append(" while (rs.next()) {\n");
98 w.append(" res.add(new " + db.classname() + "(\n");
99 for (int i = 1; i <= md.getColumnCount(); i++) {
101 .append(md.getColumnClassName(i))
102 .append(")rs.getObject(" + i).append(")");
103 if (i < md.getColumnCount()) {
111 w.append(" return res;\n");
115 private void generateConstructor(Writer w, LiveDB db, ResultSetMetaData md) throws SQLException, IOException {
116 w.append(" private " + db.classname() + "(\n");
117 for (int i = 1; i <= md.getColumnCount(); i++) {
118 w.append(" ").append(md.getColumnClassName(i))
119 .append(" ").append(md.getColumnName(i));
120 if (i < md.getColumnCount()) {
127 for (int i = 1; i <= md.getColumnCount(); i++) {
129 .append(md.getColumnName(i))
131 .append(md.getColumnName(i))
137 private void generateField(Writer w, ResultSetMetaData md, int i) throws IOException, SQLException {
138 w.append(" public final ")
139 .append(md.getColumnClassName(i))
141 .append(md.getColumnName(i))
145 private void generateClassHeader(Writer w, PackageElement pe, LiveDB db) throws IOException {
146 w.append("package " + pe.getQualifiedName() + ";\n");
147 w.append("import java.util.List;\n");
148 w.append("import java.util.ArrayList;\n");
149 w.append("import java.sql.*;\n");
151 private static Connection getConnection(String url, String user, String password)
152 throws SQLException {
153 final ClassLoader cl = LiveDBProcessor.class.getClassLoader();
154 for (Driver d : ServiceLoader.load(Driver.class, cl)) {
155 // System.out.println("looked up: " + d);
156 if (d.acceptsURL(url)) {
157 //System.out.println("accepts: " + d);
158 Properties p = new Properties();
160 p.put("password", password);
161 return d.connect(url, p);
164 throw new SQLException("No driver found for " + url);
169 // BEGIN: livedb.completions
171 public Iterable<? extends Completion> getCompletions(
172 Element element, AnnotationMirror annotation,
173 ExecutableElement member, String userText
175 if (!"query".equals(member.getSimpleName().toString())) {
176 return Collections.emptyList();
178 if (userText == null || userText.length() <= 1) {
179 return Collections.singleton(Completions.of("\"SELECT "));
181 if (userText.toUpperCase().matches(".*FROM *")) {
182 String user = extractValue(annotation, "user");
183 String password = extractValue(annotation, "password");
184 String url = extractValue(annotation, "url");
185 if (user == null || password == null || url == null) {
186 return Collections.emptyList();
189 List<Completion> arr = new ArrayList<Completion>();
190 Connection c = getConnection(url, user, password);
191 DatabaseMetaData meta = c.getMetaData();
192 ResultSet res = meta.getTables(null, null, "%", null);
193 boolean ok = res.first();
195 String txt = userText + res.getString("TABLE_NAME");
196 arr.add(Completions.of(txt));
200 } catch (SQLException ex) {
201 throw new IllegalStateException(ex);
204 return Collections.emptyList();
206 // END: livedb.completions
208 private static String extractValue(AnnotationMirror am, String param) {
209 AnnotationValue av = null;
210 for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : am.getElementValues().entrySet()) {
211 if (entry.getKey().toString().equals(param + "()")) {
212 av = entry.getValue();
219 String s = av.toString();
220 if (s.startsWith("\"")) {
223 if (s.endsWith("\"")) {
224 s = s.substring(0, s.length() - 1);