
/*
 * Isomorphic Smart GWT web presentation layer
 * Copyright 2000 and beyond Isomorphic Software, Inc.
 *
 * OWNERSHIP NOTICE
 * Isomorphic Software owns and reserves all rights not expressly granted in this source code,
 * including all intellectual property rights to the structure, sequence, and format of this code
 * and to all designs, interfaces, algorithms, schema, protocols, and inventions expressed herein.
 *
 *  If you have any questions, please email <sourcecode@isomorphic.com>.
 *
 *  This entire comment must accompany any portion of Isomorphic Software source code that is
 *  copied or moved from this file.
 */
/* sgwtgen */
package com.smartgwt.client.docs.serverds;

import com.smartgwt.client.types.*;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.docs.*;
import com.smartgwt.client.callbacks.*;
import com.smartgwt.client.widgets.form.fields.FormItem;
import java.util.List;
import java.util.Map;

/**
 * A specialized subclass of {@link com.smartgwt.client.data.DSRequest} that you use to declare
 * the properties of
 *  a subquery (a {@link com.smartgwt.client.docs.serverds.Criterion#fieldQuery fieldQuery} or 
 * {@link com.smartgwt.client.docs.serverds.Criterion#valueQuery valueQuery}) to be used in {@link
 * com.smartgwt.client.docs.serverds.AdvancedCriteria}.<p>
 * <b>This class is not meant to be created and used, it is actually documentation of settings
 * allowed in a DataSource descriptor (.ds.xml file), for use with Smart GWT Pro Edition and
 * above.
 * See {@link com.smartgwt.client.docs.serverds} for how to use this documentation.</b>
 * <p>
 * 
 *  Subquery definitions are often very compact; only a few properties are permitted for a 
 *  client-driven subquery (see "Restrictions on client-driven subqueries", below), and many 
 *  use cases can be satisfied specifying just a 
 * {@link com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#dataSource dataSource} and a
 * 
 * {@link com.smartgwt.client.data.AdvancedCriterionSubquery#getSummaryFunctions summary
 * function}.
 *  <p>
 *  Criteria subquery definitions fall into two broad categories:<ul>
 * <li><b>Aggregation</b>, where the subquery uses a {@link
 * com.smartgwt.client.types.SummaryFunctionType} to aggregate
 *  or summarize a related dataset, and then filter on that aggregated or summarized value.  For
 *  example, orders with more than 10 lines, customers with an average order value more than 
 *  $1000, UK customers with an outstanding payment more than a week old, etc</li>
 *  <li><b>Related value</b>, where the subquery selects a value (or, for <code>inSet</code>-type
 *  clauses, a set of values) from a related dataSource and then filters on that value.  For 
 *  example, Products that were not ordered last month, Employees who are based in one of the 
 *  North American offices, Orders that include a particular category of Product, etc</li>
 *  </ul>
 *  <p> 
 * In ideal circumstances - when both main and subquery {@link
 * com.smartgwt.client.docs.serverds.DataSource dataSource}s are
 * {@link com.smartgwt.client.docs.SqlDataSource SQL DataSources}, and a number of other
 * restrictions are 
 *  satisfied - subqueries are implemented by incorporating their functionality into a larger
 *  overall SQL query, because this is the most efficient thing to do, and gives the best 
 * performance.  See {@link
 * com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#canEmbedSQL canEmbedSQL} for a
 * description
 *  of the rules and nuances around this.
 *  <p>
 *  In cases where we cannot implement subqueries by embedding SQL, they are implemented by 
 *  converting the subquery definitions into separate real <code>DSRequest</code>s, executing
 *  them, and then combining their results into the wider resultset.
 *  <h3>Subquery Overview</h3>
 *  Subqueries are used to derive a value to be compared as part of the main query, from a set
 *  of related data where there is no way to directly join to a single record (usually because 
 *  the subquery is summarizing or extracting from a larger dataset).  Each subquery must 
 *  return a single value per record in the main query, because it going to be compared to a 
 *  single value from each main record (this value either comes directly from the main record,
 *  or is derived via a <code>fieldQuery</code>)
 *  <p>
 *  Because the nature of a subquery is that it is deriving a single value from multiple records,
 *  subqueries are often involved in some kind of aggregation (returning a record count, or the
 *  minimum value, for example).  While this is the most common use of subqueries, it is not
 *  the only one - see the "Simple valueQuery" example below.
 *  <p>
 *  Whether or not a subquery is aggregating multiple records, it typically needs to be 
 *  constrained by a join to the outer query.  For example, if you were looking for all customers
 *  that have placed more than $1000-worth of orders, you would use something like the 
 *  "Simple aggregating subquery" below.  As you will see, that example displays no explicit 
 *  means of joining the subquery to the outer query, and yet one is obviously necessary because
 *  we are looking for the sum of "lineValue" customer-by-customer, not the total sum for all 
 *  customers.
 *  <p>
 *  This join from the subquery to the outer query is applied implicitly by Smart GWT's SQL 
 *  engine.  It auto-discovers a Relation between the main dataSource and subquery dataSource
 * by following {@link com.smartgwt.client.docs.serverds.DataSourceField#foreignKey foreignKey}
 * definitions from the subquery 
 *  dataSource, until it finds a path to the main dataSource.  This auto-discovery usually does
 *  the right thing, but there are two possibilities it does not address:<ul>
 *  <li>There is no direct or indirect Relation from the subquery dataSource to the main 
 *  dataSource.  This is an unusual case for a subquery - most use use cases call for related 
 *  dataSources - but valid cases are conceivable.  To cope with this scenario, you set 
 * {@link com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#queryFK queryFK} to the
 * special value 
 *  "<code><b>*none*</b></code>".  Note, if Smart GWT fails to find a path from the subquery
 *  dataSource to the main dataSource and <code>queryFK:"*none*"</code> has not been set, the 
 *  framework will log a warning and the fetch will fail</li>
 *  <li>There is more than one direct or indirect Relation from the subquery dataSource to the 
 *  main dataSource, and you want to use a different one from the one that was auto-discovered.
 * Again, the solution is to explicitly name the {@link
 * com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#queryFK queryFK}
 *  - see the documentation for that property for details of the syntax</li>
 *  </ul>
 *  <p>
 *  Since Smart GWT can usually only make use of a single value as output from a subquery
 *  (see the section "Subqueries with inSet criteria" below for an important caveat), if your
 *  subquery returns multiple records, we will simply use the first.  If the query returns
 *  multiple fields, you can specify the field to use as the subquery output with 
 * {@link com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#queryOutput queryOutput}. 
 * If the subquery returns more 
 *  than one field and no <code>queryOutput</code> is specified, we will use the first 
 * aggregated ({@link com.smartgwt.client.data.AdvancedCriterionSubquery#getSummaryFunctions
 * summaryFunction}) field, or
 * the first {@link com.smartgwt.client.data.AdvancedCriterionSubquery#getGroupBy grouped} field
 * if there are no 
 * aggregated fields, or the {@link com.smartgwt.client.docs.serverds.DataSourceField#primaryKey
 * primaryKey} field if there are 
 *  also no <code>groupBy</code> fields, or just the first numeric field failing all else.  
 *  Note, however, that although we attempt to derive a sensible value, it never makes sense to
 *  return multiple records from a subquery, and it only really makes sense to return multiple 
 *  fields if you explicitly identify the correct field with <code>queryOutput</code>.  
 *  Ideally, for the sake of clarity, return a single record, and either have that record 
 *  contain a single field, or specify <code>queryOutput</code>
 *  <h4>Restrictions on client-driven subqueries</h4>
 * For security reasons, subqueries in {@link com.smartgwt.client.data.DSRequest requests} that
 * came from the 
 *  client-side are only permitted to specify a handful of properties.  These properties are
 *  sufficient to allow the full power of the subquery feature to be used, without allowing any
 *  of the much broader set of general properties associated with the <code>DSRequest</code>
 *  superclass.  The properties that can be set in a client-driven subquery are just those that
 *  are documented as direct properties of the <code>AdvancedCriterionSubquery</code> class - 
 * specifically {@link com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#canEmbedSQL
 * canEmbedSQL}, 
 *  {@link com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#criteria criteria}, 
 *  {@link com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#dataSource dataSource}, 
 *  {@link com.smartgwt.client.data.AdvancedCriterionSubquery#getGroupBy groupBy}, 
 *  {@link com.smartgwt.client.data.AdvancedCriterionSubquery#getOperationId operationId}, 
 *  {@link com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#queryFK queryFK}, 
 * {@link com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#queryOutput queryOutput},
 * and
 * {@link com.smartgwt.client.data.AdvancedCriterionSubquery#getSummaryFunctions summaryFunctions}
 *  <p>
 *  For <code>DSRequest</code>s that originally came from the server, it is possible to have a
 *  subquery that specifies any <code>DSRequest</code> property.  Many of these would only have
 *  any relevance or effect if the subquery was run separately rather than embedded (as 
 * described above and in the {@link
 * com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#canEmbedSQL canEmbedSQL} doc).  
 *  If you need to do this, look in the server Javadoc for 
 *  <code>DSRequest.setAllowArbitrarySubqueries(boolean)</code>
 *  <p>
 *  Finally, note that it is possible to switch off the ability to use subqueries altogether, 
 * either  {@link com.smartgwt.client.docs.serverds.DataSource#allowCriteriaSubqueries
 * per-DataSource}, or globally by setting 
 * the <code>allowCriteriaSubqueries</code> flag in your <code>server.properties</code> file:<pre>
 *  allowCriteriaSubqueries: false
 *  </pre>
 *  <p>
 *  <h4>Subqueries with inSet criteria</h4>
 *  As noted above, subqueries nearly always need to return a single value, since that value is 
 *  going to be used instead of a literal scalar value in record-by-record comparisons.  The 
 *  exception to this rule is when you are specifying a <code>valueQuery</code> with the 
 *  <code>inSet</code> operator.  In this case, you are saying that the field value must be one
 *  of a set of valid values, so in this one case it is appropriate and correct for the
 *  <code>valueQuery</code> to return a list of values rather than a single value.  Note, we are 
 *  still comparing a single field to the values in the list, so it should be a list of 
 *  simple values (strings, numbers, booleans or dates, as appropriate), NOT a list of records
 *  <p>
 *  <h4><code>exists / notExists</code> operators (SQLDataSource only)</h4>
 * The {@link com.smartgwt.client.types.OperatorId <code>exists / notExists</code>} operators
 * provide a concise
 *  way to filter records based on the existence (or absence) of related rows.
 *  <p>
 *  When both main DataSource and subquery DataSource are instances of <code>SQLDataSource</code>,
 *  these operators are transformed into <code>EXISTS (...)</code> / <code>NOT EXISTS (...)</code>
 *  correlated subselects in the generated SQL. Non-SQL backends, as well as when
 * {@link com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#canEmbedSQL
 * canEmbedSQL:false} is set for SQL backends, will
 * execute subqueries as separate {@link com.smartgwt.client.data.DSRequest DSRequests} and apply
 * their results manually.
 *  <p>
 * These operators must be used with a {@link
 * com.smartgwt.client.docs.serverds.Criterion#fieldQuery fieldQuery}:
 *  <pre>
 *  // EXISTS: at least one related row matches the subquery
 *  { operator: "exists",
 *    fieldQuery: { dataSource: "OrderLine", criteria: { ... } }
 *  }
 *  </pre>
 *  See full examples in the "Examples" section below.
 *  <p>
 *  <h3>Examples</h3>
 *  Subqueries are quite hard to describe in narrative text, but the following examples 
 *  demonstrate their use and should make things clearer
 *  <p>
 *  <h4>Simple aggregating subquery</h4>
 *  This example uses a <code>fieldQuery</code> to select all Order records for customer 
 *  1234, where the order total (sum of all the order line values) is greater than $1000.<pre>
 *  Order.fetchData({
 *      _constructor: "AdvancedCriteria", operator: "and", criteria: [
 *          {fieldName: "customerNumber", operator: "equals", value: 1234},
 *          {
 *               fieldQuery: {
 *                   dataSource: "OrderLine",
 *                   summaryFunctions: {lineValue: "sum"}
 *               }, operator: "greaterThan", value: 1000
 *          }
 *      ] 
 *  });
 *  </pre>
 *  <h4>Simple valueQuery</h4>
 *  This example uses a <code>valueQuery</code> to derive the employeeNumber of a manager when
 *  we only know the email address of that manager, so we can find out who reports to her.  
 *  This example shows how to use additional criteria within a subquery.  It also demonstrates 
 *  the relatively rare situation where no join to the outer dataSource is required (hence the
 *  declaration of <code>queryFK: "*none*"</code>)<pre>
 *  Employee.fetchData({
 *      _constructor: "AdvancedCriteria", operator: "and", criteria: [
 *          {
 *              fieldName: "reportsTo", 
 *              operator: "equals",
 *                  valueQuery: {
 *                      dataSource: "Employee",
 *                      queryFK: "*none*",
 *                      criteria: { operator: "and", criteria: [
 *                          {fieldName: "email", operator: "equals", value: 'mpatterson@classicmodelcars.com'}
 *                      ]
 *                  }
 *              }
 *          }
 *      ]
 *  });
 *  </pre>
 *  <h4>More complex aggregation example</h4>
 *  This example uses both a <code>fieldQuery</code> and a <code>valueQuery</code> to select 
 *  all US-based customers who placed more orders in 2022 than they placed in 2021.  Note, this 
 *  is the number of orders, not the value, and the particular field that we add the "count"
 *  function to is not important (count is the same regardless of which field you count).  We
 *  chose the orderNumber in this case, but that choice is arbitrary<pre>
 *  Customer.fetchData({
 *      _constructor: "AdvancedCriteria", operator: "and", criteria: [
 *          {fieldName: "country", operator: "equals", value: "USA"},
 *          {
 *              fieldQuery: {
 *                  dataSource: "Order",
 *                  summaryFunctions : { orderNumber : "count" },
 *                  criteria: {fieldName: "orderDate", operator: "iBetweenInclusive", 
 *                                          start:new Date("2021-01-01"), end:new Date("2021-12-31")}
 *              }, 
 *              operator: "lessThan",
 *              valueQuery: {
 *                  dataSource: "Order",
 *                  summaryFunctions : { orderNumber : "count" },
 *                  criteria: {fieldName: "orderDate", operator: "iBetweenInclusive", 
 *                                          start:new Date("2022-01-01"), end:new Date("2022-12-31")}
 *              }
 *          }
 *      ]
 *  });
 *  </pre>
 *  <h4><code>exists</code> / <code>notExists</code> operators</h4>
 *  Show customers with any Orders in 2024 (exists).
 *  <pre>
 *  Customer.fetchData({
 *    _constructor: "AdvancedCriteria", operator: "and", criteria: [
 *      { operator: "exists",
 *        fieldQuery: {
 *          dataSource: "Order",
 *          criteria: { fieldName: "orderDate", operator: "iBetweenInclusive",
 *                      start: new Date("2024-01-01"), end: new Date("2024-12-31") }
 *        }
 *      }
 *    ]
 *  });
 *  </pre>
 *  Products not ordered last month (notExists).
 *  <pre>
 *  Product.fetchData({
 *    _constructor: "AdvancedCriteria", operator: "and", criteria: [
 *      { operator: "notExists",
 *        fieldQuery: {
 *          dataSource: "OrderLine",
 *          criteria: { operator: "and", criteria: [
 *            { fieldName: "orderDate", operator: "iBetweenInclusive",
 *              start: startOfLastMonth, end: endOfLastMonth }
 *          ]}
 *        }
 *      }
 *    ]
 *  });
 *  </pre>
 */
public class AdvancedCriterionSubquery {

    /**
     * The name of the field that will be used as the output of this query.  Only useful if your
     * subquery returns more than one field, and optional even in that case.  See the  {@link
     * com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery Subqueries overview} for more
     * details
     *
     * <p>Default value is null
     * @see com.smartgwt.client.docs.AdvancedFilter Advanced Filtering
     */
    public String queryOutput;

    /**
     * The default for a subquery is that the records are joined to the main DataSource on the  first
     * {@link com.smartgwt.client.docs.serverds.DataSourceField#foreignKey foreignKey} one-to-many
     * relationship found, in field order.  So for example, querying <code>Customer</code>s with a
     * subquery on  <code>Order</code>s, we discover <code>Order.customerId</code> FK pointing to 
     * <code>Customer.id</code>.  More complicated relations are also auto-discovered: for example,
     * querying <code>Customer</code>s with a subquery on <code>OrderLine</code>s, we will discover
     * the link to <code>Customer</code> via <code>OrderLine.orderNumber</code> and then 
     * <code>Order.customerId</code>. <p> For many use cases, there is only one relation between any
     * two DataSources, so this default discovery of the relation is often sufficient.  However, if
     * you need to, you can optionally  specify a <code>queryFK</code> as the fieldName of a
     * <code>foreignKey</code> from the "many" to  the "one".  If the relation is indirect - as with
     * the join from <code>OrderLine</code> to  <code>Customer</code> described above - you can
     * specify <code>queryFK</code> as a  dot-separated path from "many" to "one", like this: 
     * <code>queryFK: "orderNumber.customerId"</code> (but note that this is optional - often, a start
     * point is all that is required to identify the relation-path to use) <p> <b>NOTE:</b>The
     * <code>queryFK</code> property leverages the  {@link
     * com.smartgwt.client.docs.serverds.DataSourceField#includeVia includeVia} feature, and so is
     * constrained by the same  restrictions as that feature.  Primarily, this means that
     * <code>queryFK</code> can only name a <code>foreignKey</code> field on the  {@link
     * com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#dataSource subquery dataSouce}; it
     * is not valid to name a  field on the main dataSource.  In practice, this is not usually a
     * restriction because  typically the subquery dataSource will be at the "many" end of a direct or
     * indirect  relation to the main dataSource, and so is naturally the one that declares the
     * <code>foreignKey</code> <p> You can also specify the special value "*none*" for
     * <code>queryFK</code>, which means the  aggregation query should be done independently from the
     * main query, to simply produce a  value separately without any joins to the main dataset.  A
     * subquery that specifies  <code>queryFK: "*none*"</code> is quite unusual because most use cases
     * of subqueries require a join to the parent dataSource; however, valid use cases do exist - see
     * the  "Simple valueQuery" example on the  {@link
     * com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery subquery overview page}
     *
     * <p>Default value is null
     * @see com.smartgwt.client.docs.AdvancedFilter Advanced Filtering
     */
    public String queryFK;

    /**
     * Optional criteria to use for this subquery.  Note, subqueries usually have implicit criteria,
     * because they are joined to the main dataSource fetch unless  the {@link
     * com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#queryFK queryFK} is set to the
     * special value "*none*". <p> Also, because subqueries are themselves part of a larger set of
     * criteria, the subquery  result is compared to some other value in that larger criteria - it is
     * easy to get confused by this multi-level criteria issue.  You may find it helpful to think of
     * this property as  "inside criteria" (criteria used inside this subquery to derive its result)
     * and the criterion of which the subquery is a component (as a {@link
     * com.smartgwt.client.docs.serverds.Criterion#fieldQuery fieldQuery} or {@link
     * com.smartgwt.client.docs.serverds.Criterion#valueQuery valueQuery}), as "outside criteria"
     *
     * <p>Default value is null
     * @see com.smartgwt.client.docs.AdvancedFilter Advanced Filtering
     */
    public Criteria criteria;

    /**
     * Indicates whether this subquery can be implemented by embedding SQL directly in the wider SQL
     * statement that will be used to resolve the fetch request.  This property is considered as part
     * of a set of rules we apply to decide whether a subquery can be resolved by  embedding SQL
     * (which is the most efficient thing to do, and may be significantly faster),  or if we must
     * resolve by separating the subquery out into its own {@link com.smartgwt.client.data.DSRequest} 
     * and manually applying the results. <p> There are two reasons why we might decide to run a
     * subquery as its own <code>DSRequest</code>: First, if either the "main" dataSource or the
     * subquery dataSource is not an {@link com.smartgwt.client.docs.SqlDataSource SQL dataSource},
     * then obviously we cannot merge into a single SQL statement.  More subtly, if there is the
     * possibility that customized logic might be in  play, we run the subquery separately because in
     * that case we may interfere with - or  completely fail to apply - the custom logic if we  do not
     * run the subquery as a  full-fledged <code>DSRequest</code>.   <p> <code>canEmbedSQL</code> is
     * intended to allow you to override our heuristics, for cases  where you know a particular
     * subquery definitely can, or definitely can't, be embedded. <p> Note, whether or not we separate
     * out the subquery into its own <code>DSRequest</code>,  {@link
     * com.smartgwt.client.docs.DeclarativeSecurity declarative security rules} are always applied. 
     * So, for  example, if the current user is not permitted to use the  {@link
     * com.smartgwt.client.docs.serverds.AdvancedCriterionSubquery#dataSource subquery dataSource} or
     * an  {@link com.smartgwt.client.data.AdvancedCriterionSubquery#getOperationId operation}
     * explicitly named on the subquery, the entire fetch operation that the subquery is part of will
     * fail.  More nuanced, if the current user is prohibited by {@link
     * com.smartgwt.client.docs.serverds.DataSourceField#canView field-level security} from viewing a 
     * field, that field will be stripped out of the subquery, which may lead to the subquery  failing
     * in a hard-to-predict way (but note, we always log a warning to the server logs when a field is
     * removed in these circumstances). <p> The rules around embedding or separating a subquery are,
     * in order, as follows.   As you can see, <code>canEmbedSQL</code> overrides all rules except the
     * first (we obviously can't  embed SQL if one of the dataSources isn't implemented using SQL)<ol>
     * <li>If either the "main" dataSource or the subquery dataSource is not an {@link
     * com.smartgwt.client.docs.serverds.DataSource#serverType sql dataSource}, the subquery must by
     * separated.  Otherwise,</li> <li>If the <code>canEmbedSQL</code> flag is non-null, we honor it. 
     * Otherwise,</li> <li>If the subquery specifies an explicit operationId, the subquery must be
     * separated.   Otherwise,</li> <li>If the subquery dataSource declares a custom fetch {@link
     * com.smartgwt.client.docs.serverds.OperationBinding operation} (that is, a fetch operation that
     * does not declare an  {@link com.smartgwt.client.docs.serverds.OperationBinding#operationId
     * operationId}), the subquery must be separated.   Otherwise,</li> <li>If the subquery dataSource
     * declares either of the dataSource-level customization  properties {@link
     * com.smartgwt.client.docs.serverds.DataSource#serverObject DataSource.serverObject} or {@link
     * com.smartgwt.client.docs.serverds.DataSource#script DataSource.script}, the subquery must be
     * separated.  Otherwise,</li> <li>If the subquery DataSource is a direct instance of the base
     * class (ie, its canonical class name is <code>com.isomorphic.sql.SQLDataSource</code>), the
     * subquery can be embedded. Otherwise,</li> <li>We now know that subquery dataSource is a
     * subclass of <code>SQLDataSource</code>.  We use Reflection to inspect the implementing class:
     * if it overrides any of the methods  <code>execute()</code>, <code>executeFetch{}</code> or
     * <code>SQLExecute</code>, the subquery must be separated (note, we cache the results of these
     * tests so Reflection is only used the first time a given dataSource instance is used)</li>
     * <li>If we get to this point without having decided whether the subquery can be embedded, or
     * must be separated, the subquery can be embedded</li> </ol>
     *
     * <p>Default value is null
     * @see com.smartgwt.client.docs.AdvancedFilter Advanced Filtering
     */
    public Boolean canEmbedSQL;

    /**
     * The name of the {@link com.smartgwt.client.docs.serverds.DataSource} to use for this subquery
     *
     * <p>Default value is null
     * @see com.smartgwt.client.docs.AdvancedFilter Advanced Filtering
     */
    public String dataSource;

}
