// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.visualization.datasource;
import javax.servlet.http.HttpServletRequest;
import java.util.Locale;
import com.google.visualization.datasource.base.DataSourceException;
import com.google.visualization.datasource.base.DataSourceParameters;
import com.google.visualization.datasource.base.InvalidQueryException;
import com.google.visualization.datasource.base.LocaleUtil;
import com.google.visualization.datasource.base.OutputType;
import com.google.visualization.datasource.query.Query;
import com.google.visualization.datasource.query.parser.QueryBuilder;
import com.ibm.icu.util.ULocale;
/**
* This class contains all information concerning a data source request. The information in this
* class is used to create a data table and return a corresponding response to the user.
*
* @author Yaniv S.
*/
public class DataSourceRequest {
/**
* The query (based on the "tq" request parameter).
*/
private Query query;
/**
* The data source parameters (based on the "tqx" request parameter).
*/
private DataSourceParameters dsParams;
/**
* The user locale.
*/
private ULocale userLocale;
/**
* Indicates whether the request is from the same origin.
*/
private boolean sameOrigin;
/**
* A request header name. Used to determine if the request was sent from the same domain as the
* server.
*/
public static final String SAME_ORIGIN_HEADER = "X-DataSource-Auth";
/**
* The name of the request parameter that specifies the query to execute.
*/
public static final String QUERY_REQUEST_PARAMETER = "tq";
/**
* The name of the request parameter that specifies the data source parameters.
*/
public static final String DATASOURCE_REQUEST_PARAMETER = "tqx";
public DataSourceRequest() {
this(new Query(), new DataSourceParameters(), null);
}
public DataSourceRequest(DataSourceParameters dsParams) {
this(new Query(), dsParams, null);
}
/**
* Constructor.
* Useful for debugging and testing.
* Do not use it for production.
*
* @param query The query.
* @param dsParams The data source parameters.
* @param userLocale The user locale.
*/
public DataSourceRequest(Query query, DataSourceParameters dsParams, ULocale userLocale) {
this.setUserLocale(userLocale);
this.dsParams = dsParams;
this.query = query;
}
/**
* Builds a DataSource request from an <code>HttpServletRequest</code>.
*
* @param req The HttpServletRequest.
* @throws DataSourceException In case of an invalid 'tq' or 'tqx' parameter.
*/
public DataSourceRequest(HttpServletRequest req) throws DataSourceException {
this(parseQuery(req.getParameter(QUERY_REQUEST_PARAMETER)),
new DataSourceParameters(req.getParameter(DATASOURCE_REQUEST_PARAMETER)),
getLocaleFromRequest(req));
sameOrigin = determineSameOrigin(req);
// For backward compatibility, set the OutputType to be 'jsonp' in case the request is cross
// domain and the 'out' property in the 'tqx' parameter is 'json'.
if(dsParams.getOutputType() == OutputType.JSON && !sameOrigin) {
dsParams.setOutputType(OutputType.JSONP);
}
}
/**
* Determines whether the given request is from the same origin (based on
* request headers set by the ).
*
* @param req The http servlet request.
* @return True if this is a same origin request false otherwise.
*/
public static boolean determineSameOrigin(HttpServletRequest req) {
// We conclude that the request is sent from the same origin if it contains a predefined
// header that the client application inserted. This is a known way of verifying that
// a request is xhr and hence was sent from the same domain.
return (req.getHeader(SAME_ORIGIN_HEADER) != null);
}
/**
* The name of the http request parameter that indicates the requested locale.
*/
protected static final String LOCALE_REQUEST_PARAMETER = "hl";
/**
* Get the locale from the given request.
*
* @param req The http serlvet request
* @return The locale for the given request.
*/
public static ULocale getLocaleFromRequest(HttpServletRequest req) {
Locale locale;
String requestLocale = req.getParameter(LOCALE_REQUEST_PARAMETER);
if(requestLocale != null) {
// Try to take the locale from the 'hl' parameter in the request.
locale = LocaleUtil.getLocaleFromLocaleString(requestLocale);
}
else {
// Else, take the browser locale.
locale = req.getLocale();
}
return ULocale.forLocale(locale);
}
/**
* @see #parseQuery(String, ULocale)
*/
public static Query parseQuery(String queryString) throws InvalidQueryException {
return parseQuery(queryString, null);
}
/**
* Parses a query string (e.g., 'select A,B pivot B') and creates a Query object.
* Throws an exception if the query is invalid.
*
* @param queryString The query string.
* @param userLocale The user locale.
* @return The parsed query object.
* @throws InvalidQueryException If the query is invalid.
*/
public static Query parseQuery(String queryString, ULocale userLocale)
throws InvalidQueryException {
return QueryBuilder.getInstance().parseQuery(queryString, userLocale);
}
/**
* Returns the query.
*
* @return The query.
*/
public Query getQuery() {
return query;
}
/**
* Returns the data source parameters.
*
* @return The data source parameters.
*/
public DataSourceParameters getDataSourceParameters() {
return dsParams;
}
/**
* Sets the user locale.
*
* @param userLocale The user locale.
*/
public void setUserLocale(ULocale userLocale) {
this.userLocale = userLocale;
}
/**
* Returns the user locale.
*
* @return The user locale.
*/
public ULocale getUserLocale() {
return userLocale;
}
/**
* Returns true if the request is same-origin.
*
* @return True if the request is same-origin.
*/
public boolean isSameOrigin() {
return sameOrigin;
}
}