Skip to content
This repository was archived by the owner on Oct 20, 2022. It is now read-only.

Commit 35a8237

Browse files
author
chartsboy
committed
Externalize error messages
1 parent dd9e139 commit 35a8237

File tree

9 files changed

+445
-14
lines changed

9 files changed

+445
-14
lines changed

src/main/java/com/google/visualization/datasource/DataSourceHelper.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.google.visualization.datasource.base.DataSourceParameters;
1919
import com.google.visualization.datasource.base.InvalidQueryException;
2020
import com.google.visualization.datasource.base.LocaleUtil;
21+
import com.google.visualization.datasource.base.MessagesEnum;
2122
import com.google.visualization.datasource.base.OutputType;
2223
import com.google.visualization.datasource.base.ReasonType;
2324
import com.google.visualization.datasource.base.ResponseStatus;
@@ -361,26 +362,35 @@ public static String generateErrorResponse(ResponseStatus responseStatus,
361362

362363
// -------------------------- Query helper methods ----------------------------------------------
363364

365+
/** @see #parseQuery(String, ULocale)*/
366+
public static Query parseQuery(String queryString) throws InvalidQueryException {
367+
return parseQuery(queryString, null);
368+
}
369+
364370
/**
365371
* Parses a query string (e.g., 'select A,B pivot B') and creates a Query object.
366372
* Throws an exception if the query is invalid.
367373
*
368374
* @param queryString The query string.
375+
* @param locale The user locale.
369376
*
370377
* @return The parsed query object.
371378
*
372379
* @throws InvalidQueryException If the query is invalid.
373380
*/
374-
public static Query parseQuery(String queryString) throws InvalidQueryException {
381+
public static Query parseQuery(String queryString, ULocale userLocale)
382+
throws InvalidQueryException {
375383
QueryBuilder queryBuilder = QueryBuilder.getInstance();
376-
Query query = queryBuilder.parseQuery(queryString);
384+
Query query = queryBuilder.parseQuery(queryString, userLocale);
377385

378386
return query;
379387
}
380388

381389
/**
382390
* Applies the given <code>Query</code> on the given <code>DataTable</code> and returns the
383391
* resulting <code>DataTable</code>. This method may change the given DataTable.
392+
* Error messages produced by this method will be localized according to the passed locale
393+
* unless the specified {@code DataTable} has a non null locale.
384394
*
385395
* @param query The query object.
386396
* @param dataTable The data table on which to apply the query.
@@ -393,8 +403,10 @@ public static Query parseQuery(String queryString) throws InvalidQueryException
393403
*/
394404
public static DataTable applyQuery(Query query, DataTable dataTable, ULocale locale)
395405
throws InvalidQueryException, DataSourceException {
406+
dataTable.setLocaleForUserMessages(locale);
396407
validateQueryAgainstColumnStructure(query, dataTable);
397408
dataTable = QueryEngine.executeQuery(query, dataTable, locale);
409+
dataTable.setLocaleForUserMessages(locale);
398410
return dataTable;
399411
}
400412

@@ -443,8 +455,8 @@ public static void validateQueryAgainstColumnStructure(Query query, DataTable da
443455
Set<String> mentionedColumnIds = query.getAllColumnIds();
444456
for (String columnId : mentionedColumnIds) {
445457
if (!dataTable.containsColumn(columnId)) {
446-
String messageToLogAndUser = "Column [" + columnId + "] does not"
447-
+ " exist in table.";
458+
String messageToLogAndUser = MessagesEnum.NO_COLUMN.getMessageWithArgs(
459+
dataTable.getLocaleForUserMessages(), columnId);
448460
log.error(messageToLogAndUser);
449461
throw new InvalidQueryException(messageToLogAndUser);
450462
}

src/main/java/com/google/visualization/datasource/base/ErrorMessages.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,43 @@ public class ErrorMessages extends ListResourceBundle {
4141
{"TIMEOUT", "Request timeout"},
4242
{"ILLEGAL_FORMATTING_PATTERNS", "Illegal formatting patterns"},
4343
{"OTHER", "Could not complete request"},
44-
{"SIGN_IN", "Sign in"}
44+
{"SIGN_IN", "Sign in"},
45+
// QUERY Errors
46+
{"NO_COLUMN", "Column [{0}] does not exist in table."},
47+
{"AVG_SUM_ONLY_NUMERIC",
48+
"'Average' and 'sum' aggreagation functions can be applied only on numeric values."},
49+
{"INVALID_AGG_TYPE", "Invalid aggregation type: {0}"},
50+
// Parse
51+
{"PARSE_ERROR", "Query parse error: {0}"},
52+
{"CANNOT_BE_IN_GROUP_BY", "Column [{0}] cannot be in GROUP BY because it has an aggregation."},
53+
{"CANNOT_BE_IN_PIVOT", "Column [{0}] cannot be in PIVOT because it has an aggregation."},
54+
{"CANNOT_BE_IN_WHERE", "Column [{0}] cannot appear in WHERE because it has an aggregation."},
55+
{"SELECT_WITH_AND_WITHOUT_AGG",
56+
"Column [{0}] cannot be selected both with and without aggregation in SELECT."},
57+
{"COL_AGG_NOT_IN_SELECT",
58+
"Column [{0}] which is aggregated in SELECT, cannot appear in GROUP BY."},
59+
{"CANNOT_GROUP_WITNOUT_AGG", "Cannot use GROUP BY when no aggregations are defined in SELECT."},
60+
{"CANNOT_PIVOT_WITNOUT_AGG", "Cannot use PIVOT when no aggregations are defined in SELECT."},
61+
{"AGG_IN_SELECT_NO_PIVOT",
62+
"Column [{0}] which is aggregated in SELECT, cannot appear in PIVOT."},
63+
{"FORMAT_COL_NOT_IN_SELECT",
64+
"Column [{0}] which is referenced in FORMAT, is not part of SELECT clause."},
65+
{"LABEL_COL_NOT_IN_SELECT",
66+
"Column [{0}] which is referenced in LABEL, is not part of SELECT clause."},
67+
{"ADD_COL_TO_GROUP_BY_OR_AGG",
68+
"Column [{0}] should be added to GROUP BY, removed from SELECT, or aggregated in SELECT."},
69+
{"AGG_IN_ORDER_NOT_IN_SELECT",
70+
"Aggregation [{0}] found in ORDER BY but was not found in SELECT"},
71+
{"NO_AGG_IN_ORDER_WHEN_PIVOT",
72+
"Column [{0}] cannot be aggregated in ORDER BY when PIVOT is used."},
73+
{"COL_IN_ORDER_MUST_BE_IN_SELECT",
74+
"Column [{0}] which appears in ORDER BY, must be in SELECT as well, " +
75+
"because SELECT contains aggregated columns."},
76+
{"NO_COL_IN_GROUP_AND_PIVOT", "Column [{0}] cannot appear both in GROUP BY and in PIVOT."},
77+
{"INVALID_OFFSET", "Invalid value for row offset: {0}"},
78+
{"COLUMN_ONLY_ONCE", "Column [{0}] cannot appear more than once in {1}."}
79+
80+
4581
};
4682

4783
/**

src/main/java/com/google/visualization/datasource/base/LocaleUtil.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package com.google.visualization.datasource.base;
1616

17+
import com.ibm.icu.text.MessageFormat;
1718
import com.ibm.icu.util.ULocale;
1819

1920
import java.util.Locale;
@@ -114,4 +115,27 @@ public static String getLocalizedMessageFromBundle(String bundleName, String key
114115
}
115116
return ResourceBundle.getBundle(bundleName, locale).getString(key);
116117
}
118+
119+
/**
120+
* Returns a localized message from the specified <code>ResourceBundle</code> for the given key
121+
* with the given arguments inserted to the message in the specified locations.
122+
* In case the locale is null, uses the default locale.
123+
* If locale is null, the default <code>ResourceBundle</code> is used.
124+
*
125+
*
126+
* @param bundleName The name of the resource bundle.
127+
* @param key The key of the requested string.
128+
* @param args Arguments to place in the error message.
129+
* @param locale The locale.
130+
*
131+
* @return A localized message from the bundle based on the given locale.
132+
*/
133+
public static String getLocalizedMessageFromBundleWithArguments(String bundleName, String key,
134+
String[] args, Locale locale) {
135+
String rawMesage = getLocalizedMessageFromBundle(bundleName, key, locale);
136+
if (args != null && args.length > 0) {
137+
return MessageFormat.format(rawMesage, args);
138+
}
139+
return rawMesage;
140+
}
117141
}
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
// Copyright 2009 Google Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.visualization.datasource.base;
16+
17+
import com.google.common.collect.Maps;
18+
19+
import com.ibm.icu.util.ULocale;
20+
21+
import java.util.Locale;
22+
import java.util.Map;
23+
24+
/**
25+
* An enum for messages used in the DataSource library. Each element references a message
26+
* in {@code ErrorMessages}. For example all the error messages produced in query parsing are
27+
* listed here.
28+
*
29+
* @author Hillel M.
30+
*/
31+
public enum MessagesEnum {
32+
33+
/**
34+
* Column in query is missing from the data table.
35+
* @param column id.
36+
*/
37+
NO_COLUMN,
38+
39+
/**
40+
* Average and sum aggregation can be applied only on numeric columns.
41+
*/
42+
AVG_SUM_ONLY_NUMERIC,
43+
44+
/**
45+
* Invalid aggregation type.
46+
* @param aggregation type.
47+
*/
48+
INVALID_AGG_TYPE,
49+
50+
/**
51+
* An error when parsing the query.
52+
* @param detailed message.
53+
*/
54+
PARSE_ERROR,
55+
56+
/**
57+
* Column can not be in group by because it has an aggregation.
58+
* @param column id
59+
*/
60+
CANNOT_BE_IN_GROUP_BY,
61+
62+
/**
63+
* Column can not be in pivot because it has an aggregation.
64+
* @param column id
65+
*/
66+
CANNOT_BE_IN_PIVOT,
67+
68+
/**
69+
* Column can not be in where because it has an aggregation.
70+
* @param column id
71+
*/
72+
CANNOT_BE_IN_WHERE,
73+
74+
/**
75+
* Column can not appear in select with and without aggregation.
76+
* @param column id.
77+
*/
78+
SELECT_WITH_AND_WITHOUT_AGG,
79+
80+
/**
81+
* Column which is aggregated in SELECT, cannot appear in GROUP BY.
82+
* @param column id
83+
*/
84+
COL_AGG_NOT_IN_SELECT,
85+
86+
/**
87+
* Cannot use GROUP BY when no aggregations are defined in SELECT.
88+
*/
89+
CANNOT_GROUP_WITNOUT_AGG,
90+
91+
/**
92+
* Cannot use PIVOT when no aggregations are defined in SELECT.
93+
*/
94+
CANNOT_PIVOT_WITNOUT_AGG,
95+
96+
/**
97+
* Column which is aggregated in SELECT, cannot appear in PIVOT.
98+
* @param column id
99+
*/
100+
AGG_IN_SELECT_NO_PIVOT,
101+
102+
/**
103+
* Column which is referenced in FORMAT, is not part of SELECT clause.
104+
* @param column id
105+
*/
106+
FORMAT_COL_NOT_IN_SELECT,
107+
108+
/**
109+
* Column which is referenced in LABEL, is not part of SELECT clause.
110+
* @param column id
111+
*/
112+
LABEL_COL_NOT_IN_SELECT,
113+
114+
/**
115+
* Column should be added to GROUP BY, removed from SELECT, or aggregated in SELECT.
116+
* @param column id
117+
*/
118+
ADD_COL_TO_GROUP_BY_OR_AGG,
119+
120+
121+
/**
122+
* Aggregation found in ORDER BY but was not found in SELECT.
123+
* @param aggreation column
124+
*/
125+
AGG_IN_ORDER_NOT_IN_SELECT,
126+
127+
/**
128+
* Column cannot be aggregated in ORDER BY when PIVOT is used.
129+
* @param aggregation column
130+
*/
131+
NO_AGG_IN_ORDER_WHEN_PIVOT,
132+
133+
/**
134+
* Column which appears in ORDER BY, must be in SELECT as well, because SELECT
135+
* contains aggregated columns.
136+
*/
137+
COL_IN_ORDER_MUST_BE_IN_SELECT,
138+
139+
/**
140+
* Column cannot appear both in GROUP BY and in PIVOT.
141+
* @param column id
142+
*/
143+
NO_COL_IN_GROUP_AND_PIVOT,
144+
145+
/**
146+
* Invalid value for row offset.
147+
* @param value
148+
*/
149+
INVALID_OFFSET,
150+
151+
/**
152+
* Column cannot appear more than once.
153+
* @param column id
154+
* @param clause
155+
*/
156+
COLUMN_ONLY_ONCE;
157+
158+
/**
159+
* A mapping from reason type to message.
160+
*/
161+
private static final Map<MessagesEnum, String>
162+
QUERY_ERROR_TO_MESSAGE = Maps.newEnumMap(MessagesEnum.class);
163+
164+
static {
165+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.NO_COLUMN,
166+
"NO_COLUMN");
167+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.AVG_SUM_ONLY_NUMERIC,
168+
"AVG_SUM_ONLY_NUMERIC");
169+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.INVALID_AGG_TYPE,
170+
"INVALID_AGG_TYPE");
171+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.PARSE_ERROR,
172+
"PARSE_ERROR");
173+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.CANNOT_BE_IN_GROUP_BY,
174+
"CANNOT_BE_IN_GROUP_BY");
175+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.CANNOT_BE_IN_PIVOT,
176+
"CANNOT_BE_IN_PIVOT");
177+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.CANNOT_BE_IN_WHERE,
178+
"CANNOT_BE_IN_WHERE");
179+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.SELECT_WITH_AND_WITHOUT_AGG,
180+
"SELECT_WITH_AND_WITHOUT_AGG");
181+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.COL_AGG_NOT_IN_SELECT,
182+
"COL_AGG_NOT_IN_SELECT");
183+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.CANNOT_GROUP_WITNOUT_AGG,
184+
"CANNOT_GROUP_WITNOUT_AGG");
185+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.CANNOT_PIVOT_WITNOUT_AGG,
186+
"CANNOT_PIVOT_WITNOUT_AGG");
187+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.AGG_IN_SELECT_NO_PIVOT,
188+
"AGG_IN_SELECT_NO_PIVOT");
189+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.FORMAT_COL_NOT_IN_SELECT,
190+
"FORMAT_COL_NOT_IN_SELECT");
191+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.LABEL_COL_NOT_IN_SELECT,
192+
"LABEL_COL_NOT_IN_SELECT");
193+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.ADD_COL_TO_GROUP_BY_OR_AGG,
194+
"ADD_COL_TO_GROUP_BY_OR_AGG");
195+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.AGG_IN_ORDER_NOT_IN_SELECT,
196+
"AGG_IN_ORDER_NOT_IN_SELECT");
197+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.NO_AGG_IN_ORDER_WHEN_PIVOT,
198+
"NO_AGG_IN_ORDER_WHEN_PIVOT");
199+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.COL_IN_ORDER_MUST_BE_IN_SELECT,
200+
"COL_IN_ORDER_MUST_BE_IN_SELECT");
201+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.NO_COL_IN_GROUP_AND_PIVOT,
202+
"NO_COL_IN_GROUP_AND_PIVOT");
203+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.INVALID_OFFSET,
204+
"INVALID_OFFSET");
205+
QUERY_ERROR_TO_MESSAGE.put(MessagesEnum.COLUMN_ONLY_ONCE,
206+
"COLUMN_ONLY_ONCE");
207+
}
208+
209+
210+
/**
211+
* Returns a localized message for this reason type and locale.
212+
*
213+
* @param locale The locale.
214+
* @param args An array of arguments.
215+
*
216+
* @return A localized message given a reason type and locale.
217+
*/
218+
public String getMessageWithArgs(ULocale ulocale, String... args) {
219+
Locale locale = ulocale != null ? ulocale.toLocale() : null;
220+
return LocaleUtil.getLocalizedMessageFromBundleWithArguments(
221+
"com.google.visualization.datasource.base.ErrorMessages", QUERY_ERROR_TO_MESSAGE.get(this),
222+
args, locale);
223+
}
224+
225+
/**
226+
* Returns a localized message for this reason type and locale.
227+
*
228+
* @param locale The locale.
229+
*
230+
* @return A localized message given a reason type and locale.
231+
*/
232+
public String getMessage(ULocale ulocale) {
233+
Locale locale = ulocale != null ? ulocale.toLocale() : null;
234+
return LocaleUtil.getLocalizedMessageFromBundle(
235+
"com.google.visualization.datasource.base.ErrorMessages", QUERY_ERROR_TO_MESSAGE.get(this),
236+
locale);
237+
}
238+
}

0 commit comments

Comments
 (0)