Merge "Reuse PEM provider in netconf-testtool."
[controller.git] / opendaylight / md-sal / sal-dom-xsql / src / main / java / org / opendaylight / controller / md / sal / dom / xsql / jdbc / JDBCServer.java
1 package org.opendaylight.controller.md.sal.dom.xsql.jdbc;
2
3 import java.net.ServerSocket;
4 import java.net.Socket;
5 import java.sql.SQLException;
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.StringTokenizer;
11 import java.util.concurrent.ConcurrentHashMap;
12 import org.opendaylight.controller.md.sal.dom.xsql.XSQLAdapter;
13 import org.opendaylight.controller.md.sal.dom.xsql.XSQLBluePrint;
14 import org.opendaylight.controller.md.sal.dom.xsql.XSQLBluePrintNode;
15 import org.opendaylight.controller.md.sal.dom.xsql.XSQLColumn;
16 import org.opendaylight.controller.md.sal.dom.xsql.XSQLCriteria;
17
18 public class JDBCServer extends Thread {
19     private ServerSocket socket = null;
20     private XSQLAdapter adapter = null;
21
22     public JDBCServer(XSQLAdapter a) {
23         super("JDBC Server");
24         this.adapter = a;
25         start();
26     }
27
28     public void run() {
29         try {
30             socket = new ServerSocket(40004);
31             while (!adapter.stopped) {
32                 Socket s = socket.accept();
33                 new JDBCConnection(s, adapter);
34             }
35         } catch (Exception err) {
36             err.printStackTrace();
37         }
38     }
39
40     public void connectToClient(String addr) {
41         try {
42             Socket s = new Socket(addr, 50003);
43             new JDBCConnection(s, adapter);
44         } catch (Exception err) {
45             err.printStackTrace();
46         }
47     }
48
49     public static void execute(JDBCResultSet rs, XSQLAdapter adapter)
50             throws SQLException {
51         if(rs.getSQL().toLowerCase().trim().equals("select 1")){
52             rs.setFinished(true);
53             return;
54         }
55         checkAndBreakSubQueries(rs, adapter);
56         if (rs.getSubQueries().size() == 0) {
57             parseTables(rs, adapter.getBluePrint());
58             parseFields(rs, adapter.getBluePrint());
59             parseCriteria(rs, adapter.getBluePrint());
60             try {
61                 adapter.execute(rs);
62             } catch (Exception err) {
63                 throw new SQLException("Error", err);
64             }
65         } else {
66             parseExternalQuery(rs);
67         }
68     }
69
70     public static void parseExternalQuery(JDBCResultSet rs) throws SQLException {
71         String sql = rs.getSQL();
72         for (Map.Entry<String, JDBCResultSet> entry : rs.getSubQueries()
73                 .entrySet()) {
74             int index = sql.toLowerCase().indexOf(entry.getValue().getSQL());
75             String extSql = sql.substring(0, index);
76             index = extSql.lastIndexOf("(");
77             extSql = extSql.substring(0, index);
78             System.out.println("External SQL=" + extSql);
79             parseLogicalFields(extSql, rs);
80         }
81     }
82
83     public static void parseLogicalFields(String sql, JDBCResultSet rs)
84             throws SQLException {
85         if(sql.trim().toLowerCase().equals("select * from")){
86             for (Map.Entry<String, JDBCResultSet> entry : rs.getSubQueries().entrySet()) {
87                 for(XSQLBluePrintNode node:entry.getValue().getTables()){
88                     rs.addTableToQuery(node);
89                 }
90                 rs.getFields().addAll(entry.getValue().getFields());
91                 while (entry.getValue().next()) {
92                     Map<String, Object> rec = entry.getValue().getCurrent();
93                     Map<String, Object> newRec = new HashMap<>();
94                     newRec.putAll(rec);
95                     rs.addRecord(newRec);
96                 }
97             }
98             rs.setFinished(true);
99             return;
100         }
101
102         Map<String, XSQLBluePrintNode> logicalNameToNode = new HashMap<String, XSQLBluePrintNode>();
103         Map<String, String> origNameToName = new HashMap<String, String>();
104         List<XSQLColumn> columnOrder = new ArrayList<>();
105         int nextLogField = addNextLogicalField(sql, 0,
106                 logicalNameToNode, origNameToName,columnOrder);
107         int next = sql.toLowerCase().indexOf(" as ", nextLogField);
108         while (next != -1) {
109             nextLogField = addNextLogicalField(sql, nextLogField + 1,
110                     logicalNameToNode, origNameToName,columnOrder);
111             next = sql.toLowerCase().indexOf(" as ", nextLogField + 1);
112         }
113
114         for (XSQLBluePrintNode node : logicalNameToNode.values()) {
115             rs.addTableToQuery(node);
116         }
117         rs.getFields().addAll(columnOrder);
118         for (Map.Entry<String, JDBCResultSet> entry : rs.getSubQueries().entrySet()) {
119             while (entry.getValue().next()) {
120                 Map<String, Object> rec = entry.getValue().getCurrent();
121                 Map<String, Object> newRec = new HashMap<>();
122                 for (Map.Entry<String, Object> e : rec.entrySet()) {
123                     Object value = e.getValue();
124                     String logicalKey = origNameToName.get(e.getKey());
125                     if (value != null && logicalKey != null) {
126                         newRec.put(logicalKey, value);
127                     }
128                 }
129                 rs.addRecord(newRec);
130             }
131         }
132         rs.setFinished(true);
133     }
134
135     public static void main(String args[]) {
136         String sql = "SELECT DISTINCT"
137                 + "\"LOGICAL_TABLE_1\".\"nodes/node.id\" AS \"COL0\"\n"
138                 + ",\"LOGICAL_TABLE_1\".\"nodes/node.id\" AS \"COL1\"\n"
139                 + ",\"LOGICAL_TABLE_1\".\"nodes/node.id\" AS \"COL2\"\n"
140                 + "FROM\n"
141                 + "(select * from nodes/node;) \"LOGICAL_TABLE_1\"\n";
142         JDBCResultSet rs = new JDBCResultSet(sql);
143         try {
144             parseLogicalFields(sql, rs);
145         } catch (Exception err) {
146             err.printStackTrace();
147         }
148     }
149
150     public static int addNextLogicalField(String sql, int startIndex,
151             Map<String, XSQLBluePrintNode> logicalNameToNode,
152             Map<String, String> origNameToName, List<XSQLColumn> columnOrder) {
153         int index1 = sql.indexOf("\"", startIndex);
154         int index2 = sql.indexOf("\".\"", index1);
155         int index3 = sql.indexOf("\"", index2 + 3);
156         int index4 = sql.toLowerCase().indexOf(" as ", startIndex);
157         int index5 = sql.indexOf("\"", index4);
158         int index6 = sql.indexOf("\"", index5 + 1);
159
160         String tblName = sql.substring(index1 + 1, index2);
161         String origFieldNameFull = sql.substring(index2 + 3, index3);
162         String origTableName = "";
163         String origFieldName = "";
164         if (origFieldNameFull.indexOf(".") != -1) {
165             origTableName = origFieldNameFull.substring(0,origFieldNameFull.indexOf("."));
166             origFieldName = origFieldNameFull.substring(origFieldNameFull.indexOf(".") + 1);
167         }
168         String logicalFieldName = sql.substring(index5 + 1, index6);
169         XSQLBluePrintNode node = logicalNameToNode.get(tblName);
170         if (node == null) {
171             node = new XSQLBluePrintNode(tblName, origTableName, 0);
172             logicalNameToNode.put(tblName, node);
173         }
174         columnOrder.add(node.addColumn(logicalFieldName, tblName, origFieldName, origTableName));
175         origNameToName.put(origFieldNameFull, tblName + "." + logicalFieldName);
176         return index6;
177     }
178
179     public static void checkAndBreakSubQueries(JDBCResultSet rs,XSQLAdapter adapter) throws SQLException {
180         String sql = rs.getSQL().toLowerCase();
181         int index = sql.indexOf("select");
182         if (index == -1)
183             throw new SQLException("Select statement is missing...");
184         int index2 = sql.indexOf("select", index + 6);
185         if (index2 != -1) {
186             int startSubQuery = index2;
187             for (int i = startSubQuery; i >= 0; i--) {
188                 if (sql.charAt(i) == '(') {
189                     startSubQuery = i;
190                     break;
191                 }
192             }
193             int braketCount = 0;
194             int endSubQuery = startSubQuery;
195             do {
196                 if (sql.charAt(endSubQuery) == '(') {
197                     braketCount++;
198                 }
199                 else if (sql.charAt(endSubQuery) == ')') {
200                     braketCount--;
201                 }
202                 endSubQuery++;
203             } while (braketCount > 0 || endSubQuery == sql.length());
204             String subQuerySQL = sql.substring(startSubQuery + 1,endSubQuery - 1);
205             if(rs.getSQL().toLowerCase().substring(0,startSubQuery).trim().equals("select * from")){
206                 rs.setSQL(subQuerySQL);
207                 return;
208             }
209             index = sql.indexOf("\"", endSubQuery);
210             index2 = sql.indexOf("\"", index + 1);
211             if(index==-1){
212                 index = endSubQuery;
213                 index2 = sql.length();
214             }
215             String logicalName = rs.getSQL().substring(index + 1, index2).trim();
216             JDBCResultSet subRS = rs.addSubQuery(subQuerySQL, logicalName);
217             JDBCServer.execute(subRS, adapter);
218         }
219     }
220
221     public static void parseTables(JDBCResultSet rs, XSQLBluePrint bp)
222             throws SQLException {
223         String lowSQL = rs.getSQL().toLowerCase();
224         int from = lowSQL.indexOf("from");
225         int where = lowSQL.indexOf("where");
226         int subQuery = lowSQL.indexOf("select", 2);
227         int fromTo = lowSQL.indexOf(";");
228
229         if (where != -1 && subQuery != -1 && where < subQuery) {
230             fromTo = where;
231         } else if (where != -1 && subQuery != -1 && where > subQuery) {
232             fromTo = subQuery;
233         } else if (where != -1) {
234             fromTo = where;
235         } else if (subQuery != -1) {
236             fromTo = subQuery;
237         }
238
239         if (from == -1) {
240             throw new SQLException("Missing \"from\" statement.");
241         }
242
243         if (fromTo == -1) {
244             throw new SQLException("Missing terminating \";\".");
245         }
246
247         String tableNames = rs.getSQL().substring(from + 4, fromTo).trim();
248         StringTokenizer tokens = new StringTokenizer(tableNames, ",");
249         while (tokens.hasMoreTokens()) {
250             String tableName = tokens.nextToken().trim();
251             XSQLBluePrintNode table = bp.getBluePrintNodeByTableName(tableName);
252             if (table == null) {
253                 throw new SQLException("Unknown table name \"" + tableName
254                         + "\"");
255             }
256             rs.addTableToQuery(table);
257         }
258     }
259
260     public static void addCriteria(XSQLColumn col, XSQLCriteria c,
261             JDBCResultSet rs) {
262         Map<XSQLColumn, List<XSQLCriteria>> tblCriteria = rs.getCriteria().get(
263                 col.getTableName());
264         if (tblCriteria == null) {
265             tblCriteria = new ConcurrentHashMap<XSQLColumn, List<XSQLCriteria>>();
266             rs.getCriteria().put(col.getTableName(), tblCriteria);
267         }
268         List<XSQLCriteria> lstCriteria = tblCriteria.get(col);
269         if (lstCriteria == null) {
270             lstCriteria = new ArrayList<XSQLCriteria>();
271             tblCriteria.put(col, lstCriteria);
272         }
273         lstCriteria.add(c);
274     }
275
276     public static void parseFields(JDBCResultSet rs, XSQLBluePrint bp)
277             throws SQLException {
278         String lowSQL = rs.getSQL().toLowerCase();
279         if (!lowSQL.startsWith("select")) {
280             throw new SQLException("Missing 'select' statement.");
281         }
282         int from = lowSQL.indexOf("from");
283         if (from == -1) {
284             throw new SQLException("Missing 'from' statement.");
285         }
286         String fields = rs.getSQL().substring(6, from).trim();
287         StringTokenizer tokens = new StringTokenizer(fields, ",");
288         while (tokens.hasMoreTokens()) {
289             String token = tokens.nextToken().trim();
290             if (token.equals("*")) {
291                 for (XSQLBluePrintNode table : rs.getTables()) {
292                     rs.getFields().addAll(table.getColumns());
293                 }
294                 return;
295             }
296             if (token.indexOf(".") != -1) {
297                 XSQLBluePrintNode tbl = bp.getBluePrintNodeByTableName(token
298                         .substring(0, token.indexOf(".")).trim());
299                 String p = token.substring(token.indexOf(".") + 1);
300                 if (p.equals("*")) {
301                     for (XSQLColumn c : tbl.getColumns()) {
302                         rs.getFields().add(c);
303                     }
304                 } else {
305                     XSQLColumn col = tbl.findColumnByName(p);
306                     rs.getFields().add(col);
307                 }
308             } else {
309                 XSQLColumn col = null;
310                 for (XSQLBluePrintNode table : rs.getTables()) {
311                     try {
312                         col = table.findColumnByName(token);
313                     } catch (Exception err) {
314                     }
315                     if (col != null) {
316                         break;
317                     }
318                 }
319                 if (col == null) {
320                     throw new SQLException("Unknown field name '" + token
321                             + "'.");
322                 }
323
324                 rs.getFields().add(col);
325             }
326         }
327     }
328
329     public static void parseCriteria(JDBCResultSet rs, XSQLBluePrint bp) {
330         String lowSQL = rs.getSQL().toLowerCase();
331         int where = lowSQL.indexOf("where");
332         int order = lowSQL.indexOf("order");
333         int whereTo = lowSQL.indexOf(";");
334
335         if (where == -1) {
336             return;
337         }
338
339         if (order != -1) {
340             whereTo = order;
341         }
342
343         if(whereTo==-1) {
344             whereTo=lowSQL.length();
345         }
346
347         String whereStatement = rs.getSQL().substring(where + 5, whereTo)
348                 .trim();
349         XSQLCriteria cr = new XSQLCriteria(whereStatement, -1);
350         for (XSQLBluePrintNode tbl : rs.getTables()) {
351             for (XSQLColumn col : tbl.getColumns()) {
352                 String colCriteria = cr.getCriteriaForProperty(col);
353                 if (colCriteria != null && !colCriteria.trim().equals("")) {
354                     addCriteria(col, new XSQLCriteria(colCriteria, -1), rs);
355                 }
356             }
357         }
358     }
359 }