Skip to contentMethod: getQueryParameter(Integer)
1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.query.sparql;
16:
17: import cz.cvut.kbss.jopa.exception.QueryParserException;
18: import cz.cvut.kbss.jopa.query.QueryParameter;
19: import cz.cvut.kbss.jopa.query.QueryParser;
20:
21: import java.util.ArrayList;
22: import java.util.HashMap;
23: import java.util.List;
24: import java.util.Map;
25:
26: public class SparqlQueryParser implements QueryParser {
27:
28: private String query;
29:
30: private Map<Object, QueryParameter<?>> uniqueParams;
31: private Integer positionalCounter;
32:
33: List<String> queryParts;
34: List<QueryParameter<?>> parameters;
35: private boolean inParam;
36: private boolean inSQString; // In apostrophe string (')
37: private boolean inDQString; // In double-quoted string (")
38: private int lastParamEndIndex;
39: private int paramStartIndex;
40: ParamType currentParamType;
41:
42: private enum ParamType {
43: POSITIONAL, NAMED
44: }
45:
46: @Override
47: public SparqlQueryHolder parseQuery(String query) {
48: this.query = query;
49: this.queryParts = new ArrayList<>();
50: this.uniqueParams = new HashMap<>();
51: this.positionalCounter = 1;
52: this.parameters = new ArrayList<>();
53: this.inSQString = false;
54: // In double-quoted string
55: this.inDQString = false;
56: this.inParam = false;
57: this.lastParamEndIndex = 0;
58: this.paramStartIndex = 0;
59: this.currentParamType = null;
60: int i;
61: for (i = 0; i < query.length(); i++) {
62: final char c = query.charAt(i);
63: switch (c) {
64: case '\'':
65: inSQString = !inSQString;
66: break;
67: case '"':
68: inDQString = !inDQString;
69: break;
70: case '$':
71: parameterStart(i, ParamType.POSITIONAL);
72: break;
73: case '?':
74: parameterStart(i, ParamType.NAMED);
75: break;
76: // TODO Take a look at some existing SPARQL parsers and maybe use them instead of this simplified version
77: case '<':
78: case '>':
79: case ',':
80: case '\n':
81: case ')':
82: case ' ':
83: case '.':
84: case ';':
85: if (inParam) {
86: parameterEnd(i);
87: }
88: break;
89: default:
90: break;
91: }
92: }
93: if (inParam) {
94: parameterEnd(i);
95: } else {
96: queryParts.add(query.substring(lastParamEndIndex));
97: }
98: return new SparqlQueryHolder(query, queryParts, parameters);
99: }
100:
101: private void parameterStart(int index, ParamType paramType) {
102: if (!inSQString && !inDQString) {
103: queryParts.add(query.substring(lastParamEndIndex, index));
104: paramStartIndex = index + 1;
105: inParam = true;
106: this.currentParamType = paramType;
107: }
108: }
109:
110: private void parameterEnd(int index) {
111: this.lastParamEndIndex = index;
112: this.inParam = false;
113: final String param = query.substring(paramStartIndex, index);
114: parameters.add(resolveParamIdentification(param));
115: }
116:
117: private QueryParameter<?> resolveParamIdentification(String identification) {
118: final QueryParameter<?> queryParameter;
119: if (identification.isEmpty()) {
120: if (currentParamType == ParamType.POSITIONAL) {
121: queryParameter = getQueryParameter(positionalCounter++);
122: } else {
123: throw new QueryParserException("Missing parameter name in query " + query);
124: }
125: } else {
126: if (currentParamType == ParamType.POSITIONAL) {
127: try {
128: Integer position = Integer.parseInt(identification);
129: positionalCounter++;
130: queryParameter = getQueryParameter(position);
131: } catch (NumberFormatException e) {
132: throw new QueryParserException(identification + " is not a valid parameter position.", e);
133: }
134: } else {
135: queryParameter = getQueryParameter(identification);
136: }
137: }
138: return queryParameter;
139: }
140:
141: private QueryParameter<?> getQueryParameter(String name) {
142: // We want to reuse the param instances, so that changes to them apply throughout the whole query
143: if (!uniqueParams.containsKey(name)) {
144: uniqueParams.put(name, new QueryParameter<>(name));
145: }
146: return uniqueParams.get(name);
147: }
148:
149: private QueryParameter<?> getQueryParameter(Integer position) {
150: // We want to reuse the param instances, so that changes to them apply throughout the whole query
151:• if (uniqueParams.containsKey(position)) {
152: throw new QueryParserException("Parameter with position " + position + " already found in query " + query);
153: }
154: final QueryParameter<?> qp = new QueryParameter<>(position);
155: uniqueParams.put(position, qp);
156: return qp;
157: }
158: }