
package com.smartgwt.client.docs;

/**
 * <h3>Automatic Cache Synchronization</h3>
 * <i>Cache synchronization</i> is the mechanism used by Smart GWT to ensure that updates
 * made by {@link com.smartgwt.client.widgets.DataBoundComponent dataBoundComponent}s or
 * programmatically on 
 * {@link com.smartgwt.client.data.DataSource dataSource}s directly, are reflected in the
 * client-side caches of other
 *  <code>dataBoundComponent</code>s.  Automatic cache sync means that components update 
 *  themselves to reflect data changes - so if you update a record in a 
 * {@link com.smartgwt.client.widgets.form.DynamicForm form}, and the same information is
 * currently visible in a 
 * {@link com.smartgwt.client.widgets.grid.ListGrid grid}, the grid data will change to reflect
 * the updates automatically.
 *  <p>
 *  The Smart GWT server is designed to retrieve cache sync data in the most optimal way, 
 *  taking into account the capabilities of the target data store or data service and the 
 *  context of the request, such as whether it came from a browser or was programmatically 
 *  initiated on the server.  The cacheSyncStrategy setting can be used to manually control 
 *  how cache sync is performed server-side, whenever that's necessary.
 *  <h3>CacheSyncStrategy</h3>
 * Cache sync configuration revolves around the {@link
 * com.smartgwt.client.types.CacheSyncStrategy} type, and to a 
 * lesser extent the {@link com.smartgwt.client.types.CacheSyncTiming}.  These settings allow you
 * to define a
 *  default cache sync approach globally, overridable
 *  {@link com.smartgwt.client.data.DataSource#getCacheSyncStrategy per-DataSource}, 
 *  {@link com.smartgwt.client.data.OperationBinding#getCacheSyncStrategy per-Operation} or 
 *  {@link com.smartgwt.client.data.DSRequest#getCacheSyncStrategy per-request}.  
 * See the {@link com.smartgwt.client.types.CacheSyncStrategy CacheSyncStrategy documentation} for
 * details.
 *  <p>
 *  Note that DataSource-level, operation-level and request-level <code>cacheSyncStrategy</code>
 *  settings are honored in all cases (though see below for a caveat on that), but global 
 *  settings are defaults only.  Smart GWT will override the default if it detects that it 
 *  might lead to problems in a given case.
 *  <p>
 *  For example, if a DataSource declares a field that specifies the 
 * {@link com.smartgwt.client.docs.serverds.DataSourceField#autoGenerated autoGenerated} flag, it
 * is saying that field is not a 
 *  sequence but its value is nevertheless generated by the database or ORM platform, so we 
 *  would not expect a value for that field in the request values.  So if the global default 
 *  <code>cacheSyncStrategy</code> is "requestValuesPlusSequences", that is going to lead to 
 *  Smart GWT returning an incomplete cache sync record, which might well look to your 
 *  users like a broken application.
 *  <p>
 *  Smart GWT will detect these cases where we would have possibly incomplete cache sync data,
 *  and automatically change the strategy to "refetch".  This is done when we have a field 
 * that is part of the expected outputs (see {@link com.smartgwt.client.data.DSRequest#getOutputs
 * DSRequest.outputs} and 
 * {@link com.smartgwt.client.docs.serverds.OperationBinding#outputs OperationBinding.outputs})
 * and specifies any of the following properties (because 
 *  they all mean that the field's value is server-generated in some way):<ul>
 *  <li>autoGenerated</li>
 *  <li>customSQL</li>
 *  <li>customSelectExpression</li>
 *  </ul>
 *  Similarly, Smart GWT will override the global <code>cacheSyncTiming</code> setting according
 *  to the requirements of a given request.  For example, if the global default is "lazy" and
 *  there is no DataSource-level, operation-level or request-level timing setting, Smart GWT
 *  will override the timing to "immediate" for any client-originated request, amongst other 
 * things.  See the {@link com.smartgwt.client.types.CacheSyncTiming CacheSyncTiming
 * documentation} for further 
 *  details.
 *  <p>
 *  If you do not want these intelligent fallback behaviors for a given DataSource, operation 
 *  or request, set a <code>cacheSyncStrategy</code> or <code>cacheSyncTiming</code> on the 
 *  DataSource, operation or request.  This will always be honored for 
 *  <code>cacheSyncStrategy</code>, even when the system knows that it is going to lead to 
 *  incomplete cache-sync data.  However, even an explicit <code>cacheSyncTiming</code> setting
 *  at the DataSource, operation or request level will be ignored in certain circumstances, 
 *  where deferring the cache sync operation could break framework functionality.  An example 
 *  of this is auditing: if your dataSource is configured for 
 * {@link com.smartgwt.client.docs.serverds.DataSource#audit automatic auditing}, the framework
 * categorically <i>does</i> need 
 *  the cache sync data in order to write an audit record, and when deferred cache sync is in 
 *  force, we have no guarantee that cache sync will run at all.  So we ignore attempts to 
 *  configure it for deferred cache sync.
 *  <h3>CacheSyncStrategy support with different DataSource types</h3>
 *  Different DataSource types may support only a subset of cacheSyncStrategy options, since 
 *  some strategies are specific to the capabilities of specific data stores or remote services.
 *  The following section describes how <code>CacheSyncStrategy</code> applies to various 
 *  built-in dataSource types
 *  <h4>SQLDataSource</h4>
 *  SQL databases accessed via JDBC do not return the record-as-saved, so extra work is required
 *  to retrieve database-generated fields, such as sequences (though sequences are a special
 *  case, see below)
 *  <p>
 * With JDBC 3.0+ drivers and a {@link com.smartgwt.client.docs.serverds.DataSource#sequenceMode
 * sequenceMode} of <code>jdbcDriver</code>, 
 *  we can retrieve generated sequence values without requiring an explicit, separate SQL query
 *  to retrieve the generated keys.  With the default CacheSyncStrategy of 
 *  <code>requestValuesPlusSequences</code>, SQLDataSource uses this JDBC approach to avoid a 
 *  separate SQL query where possible - see the "requestValuesPlusSequences" section of the 
 * {@link com.smartgwt.client.types.CacheSyncStrategy} documentation for details.  With a
 * <code>sequenceMode</code>
 *  of <code>native</code>, we will issue a separate SQL query to retrieve the generated keys, 
 *  even if you are using "requestvaluesPlusSequences".  However, it is not a full refetch, it 
 *  is just a special native query, specific to the database in use, to retrieve just the 
 *  generated sequence values, so it is still likely to have a performance advantage over using
 *  "refetch" - in the refetch case, we perform an <i>additional</i> full fetch, using the 
 *  retrieved keys as the criteria.
 *  <p> 
 *  Note that sequences (or identity columns, or auto-increment columns - different databases 
 *  use different mechanisms and terminology for the same concept) are not the only kind of 
 *  database-generated value.  As well as the three DataSource field settings, mentioned above,
 *  that can explicitly denote a generated value - 
 *  {@link com.smartgwt.client.docs.serverds.DataSourceField#autoGenerated autoGenerated}, 
 *  {@link com.smartgwt.client.data.DataSourceField#getCustomSQL customSQL} and 
 * {@link com.smartgwt.client.data.DataSourceField#getCustomSelectExpression
 * customSelectExpression} - database-generated 
 *  values can come from database-declared default values, UDFs and stored procedures, and 
 *  triggers.  In addition, application code can modify data returned from the database in 
 *  arbitrary ways, via logic in a {@link com.smartgwt.client.docs.DmiOverview DMI}, 
 *  {@link com.smartgwt.client.docs.serverds.OperationBinding#script server script} or 
 * {@link com.smartgwt.client.docs.serverds.DataSource#serverConstructor custom DataSource
 * implementation}.  So there are cases 
 *  where "refetch" is necessary, and for some applications it may be that most or even all 
 *  cases require it (if you make extensive use of triggers, or enhance many database responses 
 *  in Java code, for example).
 *  <h4>Sequence field object type considerations</h4>
 *  SQL databases support different underlying column types for sequence fields.  Typically,
 *  you use either INTEGER or BIGINT, depending on the maximum number of rows you anticipate
 *  for a given table.  Unfortunately, the different database products are not always consistent
 *  in the way they convert values from the different underlying SQL types into Java objects.
 *  For example, MySQL returns values from SQL INTEGER columns as instances of
 *  <code>java.lang.Integer</code> in ordinary fetch ResultSets, but as instances of
 *  <code>java.lang.Long</code> from the <code>getGeneratedKeys()</code> API.
 *  <p>
 *  This is a problem if you have existing Java code that is expecting an instance of
 *  <code>Integer</code>; if you switch to the more efficient "requestValuesPlusSequences"
 *  cacheSyncStrategy, your code will be sent an instance of <code>Long</code> instead.  Note,
 *  this is only a problem for existing server-side Java code; client code is not affected
 *  because the Smart GWT framework already coerces all integer-type values to type
 *  <code>Long</code> for serialization to the client.
 *  <p>
 *  The Smart GWT framework offers a number of configurable mitigations for this problem:<ul>
 *  <li>We maintain a table of known Java types returned by each database product for "small"
 *  sequence columns (32-bit, SQL type INT or INTEGER) and "large" sequence columns (64-bit,
 *  SQL type BIGINT).  We also maintain a flag per database product indicating whether "small"
 *  or "large" sequence columns should be used (as mentioned in the bullet-point below, this 
 *  applies to integer key fields generally, not just sequences).  You can override this flag
 *  in your <code>server.properties</code> file, per database product or per 
 * {@link com.smartgwt.client.docs.serverds.DataSource#dbName dbName} (the latter is more specific
 * and wins if there is a 
 *  conflict).  For example:<pre>
 *     # Change all Postgres db connections to use small keys
 *     sql.postgresql.defaultKeySize: small
 *     # Change the db with the specific dbName "SalesDB" to use large keys
 *     sql.SalesDB.defaultKeySize: large
 *  </pre>
 *  <li>If you need Java types other than the defaults described above 
 *  (<code>java.lang.Integer</code> for "small" sequences, <code>java.lang.Long</code> for
 *  "large" sequences), you can declare entries in <code>server.properties</code> to override
 *  them, per database product or per dbName, like this:<pre>
 *     # For Postgres, large key values should be returned as instances of BigInteger
 *     sql.postgresql.javaTypeForLargeKey: java.math.BigInteger
 *     # and small key values should be returned as instances of Short
 *     sql.postgresql.javaTypeForSmallKey: java.lang.Short
 *     # But small key values should be returned as type BigDecimal for AdminDB
 *     sql.AdminDB.javaTypeForSmallKey: java.math.BigDecimal
 *  </pre>This is useful for new projects that may later switch database vendors, or for projects
 *  that use multiple database products in tandem, because it can be used to enforce
 *  cross-database type consistency.  We would recommend using <code>java.lang.Integer</code>
 *  and <code>java.lang.Long</code> for small and large sequences, respectively, since these
 *  cover exactly the same range of valid values as the corresponding SQL types, INTEGER and
 *  BIGINT</li>
 *  <br>
 *  <li>The <code>server.properties</code> flag <code>sql.transformGeneratedKeys</code>, on by
 *  default, causes the framework to transform the object returned by the getGeneratedKeys()
 *  API in accordance with the above.  So, if "SalesDB" and "AdminDB" are both PostgreSQL
 *  databases, the settings above would mean:<ul>
 *    <li>Adding a record to a DataSource with <code>dbName="SalesDB"</code> would return an
 *    instance of <code>java.math.BigInteger</code> for the sequence field</li>
 *    <li>Adding a record to a DataSource with <code>dbName="AdminDB"</code> would return an
 *    instance of <code>java.math.BigDecimal</code> for the sequence field (because of the 
 *    custom <code>javaTypeForSmallSequence</code> declared for that dbName)</li></ul></li>
 *  <br>
 *  <li>Note that the above rules are also applied by Smart GWT's table-creation logic when 
 * you use the {@link com.smartgwt.client.docs.AdminConsole Admin Console} to import SQL
 * DataSources.  Additionally,
 *  we use these rules to decide on a column type for any integer field that is marked as 
 * {@link com.smartgwt.client.data.DataSourceField#getPrimaryKey primaryKey} or {@link
 * com.smartgwt.client.data.DataSourceField#getForeignKey foreignKey},
 *  to ensure that the same SQL type is used at both ends of the relation (because some 
 *  databases require this)</li>
 *  <br>
 *  <li>If <code>sql.transformGeneratedKeys</code> is explicitly set false, no transformation
 *  takes place; your code is directly returned whatever object type the JDBC dirver returned</li>
 *  <br>
 *  <li>If you have an existing project where a mix of large and small sequence types is already
 *  in place, the above approaches to provide consistency will not help.  In this case, the
 *  <code>server.properties</code> flag "sql.transformGeneratedKeysToFetchType" should be
 *  considered.  This flag is off by default; when switched on, it causes the framework to cast
 *  the generated value of a sequence field, as returned by the JDBC driver or native query, to
 *  the same Java type that a regular fetch of that field would have returned.  This is
 *  accomplished by running a basic fetch of a single row the first time the information is
 *  required, determining the underlying SQL type from the ResultSetMetadata, and then caching
 *  that information for future use.  The performance impact of this is minor, since it
 *  involves a single additional fetch per DataSource instance for the lifetime of the JVM.
 *  Note, this flag has no effect if <code>sql.transformGeneratedKeys</code> is false</li>
 *  <br>
 *  <li><code>sql.transformGeneratedKeysToFetchType</code> is only intended for existing
 *  projects that have a lot of server-side code that interacts with the Smart GWT Server and
 *  may be affected by cacheSyncStrategy "requestValuesPlusSequences" returning a different
 *  Java object type for sequence fields than your existing code is expecting.  For any new
 *  project we would recommend using the other options outlined above to either match your
 *  database's return type for fetches, or to force consistency to types you specify</li>
 *  <br>
 *  <li>Finally, the Java type to use for a specific field can be set using the field's
 * {@link com.smartgwt.client.docs.serverds.DataSourceField#javaClass javaClass} property. 
 * Alternatively, Smart GWT will
 *  automatically coerce values to match declared types if you are using Javabeans rather than
 * Maps as your data model - see {@link com.smartgwt.client.docs.serverds.DataSource#beanClassName
 * beanClassName}.  Both of these
 *  approaches take precedence over the mechanisms described above</li>
 *  </ul>
 * 
 *  <h4>HibernateDataSource and JPADataSource</h4>
 *  {@link com.smartgwt.client.docs.HibernateIntegration HibernateDataSource} and 
 * {@link com.smartgwt.client.docs.JpaIntegration JPADataSource} only support
 * <code>refetch</code>.  These two
 *  implementations integrate with the underlying ORM system at the level of the ORM's API, 
 *  allowing it to handle the details of database interaction.  With these two DataSource types,
 *  we are simply working with "persistent objects" - how the ORM manages things like changes
 *  made by the database during update queries, or sequence values in add operations, is the 
 *  ORM's business.  
 *  <p>
 *  For this reason, <code>HibernateDataSource</code> and <code>JPADataSource</code> install a
 *  special <code>CacheSyncStrategy</code> implementation under the <code>refetch</code> 
 *  name, that just does nothing, leaving the response data returned by the update operation 
 *  unchanged.
 * 
 *  <h4>RestConnector</h4>
 * {@link com.smartgwt.client.docs.ServerRestConnector RestConnector} supports all four of the
 * default cache sync
 *  strategies.  Note that <code>refetch</code> involves a second round-trip to the REST 
 *  service, so may be a performance concern.
 *  <p>
 *  <code>requestValuesPlusSequences</code> attempts to extract the values for any missing 
 * {@link com.smartgwt.client.data.DataSource#getPrimaryKeyFields primaryKey fields} from the
 * response sent by the REST
 *  service to the add or update request, so it is obviously only of use if the REST service
 *  returns such values.
 *  <p>
 *  <code>responseValues</code>, the default strategy for <code>RestConnector</code>, just
 *  uses the response data sent by the REST service to the update or add request.  Again, this
 *  is only usable if the REST service returns such data, but if it does, this strategy is 
 *  ideal.
 * 
 *  <h4>Custom/Generic DataSources</h4>
 *  In addition to the built-in DataSource types listed above, you can of course write your own
 * {@link com.smartgwt.client.docs.WriteCustomDataSource custom dataSource} implementations. 
 * These custom
 *  DataSources will participate in cache sync like any other:<ul>
 * <li>You can specify a <code>cacheSyncStrategy</code> on the {@link
 * com.smartgwt.client.data.DataSource},
 * {@link com.smartgwt.client.data.OperationBinding operationBinding} or {@link
 * com.smartgwt.client.data.DSRequest dsRequest}</li>
 *  <li>The default strategy for a custom dataSource is "<code>responseValues</code>", because 
 *  that was the prevailing behavior for custom DataSources before <code>cacheSyncStrategy</code>
 *  was introduced</li>
 *  <li>If you want to use "<code>refetch</code>" (ie, you override the default in your
 *  <code>server.properties</code>, or set the strategy explicitly on your DataSource or operation
 *  binding), you must implement a fetch operation, and if your dataSource has fields of type 
 *  "sequence", your fetch mechanism must be able to resolve the values of such fields</li>
 *  </ul>
 *  Note that "<code>refetch</code>" with a custom dataSource is done lazily, and it is not 
 *  done at all if nothing asks for the response data.  This is because the integration with 
 *  cache sync happens when the server-side <code>DSResponse</code>'s <code>getData()</code> 
 *  method is called.  This happens automatically and will work perfectly for most use cases.  
 *  If, however, you have some unusual requirement which means you need "<code>refetch</code>" 
 *  to cause an immediate cache sync fetch like it does with the built-in dataSources, you can 
 *  do what they do: invoke the <code>CacheSyncStrategy</code> manually from your execution 
 *  flow, like this:<pre>
 *     CacheSyncStrategy strategy = dsRequest.getCacheSyncStrategy();
 *     if (strategy.shouldRunCacheSync(dsRequest)) {
 *         // Apply the cache sync data to the dsResponse, first fetching it if necessary
 *         strategy.applyCacheSyncStrategy(dsRequest, dsResponse)
 *     }
 *  </pre>
 * <h3><code>canSyncCache</code>, <code>cacheSyncOperation</code> and
 * <code>useForCacheSync</code></h3>
 * These three long-standing {@link com.smartgwt.client.data.OperationBinding operationBinding}
 * flags interact with the 
 *  above-documented behavior of <code>CacheSyncStrategy</code> as follows:<ul>
 * <li>If {@link com.smartgwt.client.data.OperationBinding#getCanSyncCache canSyncCache} is false,
 * no cache sync logic will
 *      run at all</li>
 * <li>If a {@link com.smartgwt.client.data.OperationBinding#getUseForCacheSync useForCacheSync}
 * operation is in force, or 
 * the update operation specifies a {@link
 * com.smartgwt.client.data.OperationBinding#getCacheSyncOperation cacheSyncOperation},
 *      that operation will be run if we are refetching the updated record - ie, if the 
 *      <code>cacheSyncStrategy</code> is <code>refetch</code>.  Depending on the 
 * {@link com.smartgwt.client.data.OperationBinding#getCacheSyncTiming cacheSyncTiming} in force,
 * the operation execution 
 *      may be deferred, and may not run at all.  If we are not refetching the updated record, 
 *      these two flags have no effect</li>
 *  </ul>
 *  <h3>Adding multiple records</h3>
 *  By default, cache sync is switched off for multi-insert requests (ie, add requests with more
 *  than one valueSet; cache sync is always off for 
 * {@link com.smartgwt.client.docs.serverds.OperationBinding#allowMultiUpdate allowMultiUpdate}
 * operations, unless you explicitly
 *  specify a <code>cacheSyncStrategy</code> on the request or operationBinding).  You can 
 *  change this default behavior for multi-inserts by changing <code>server.properties</code> 
 *  flag "<code>default.multi.update.cache.sync.strategy</code>" to "<code>sync</code>""; this
 *  will cause the system to use the same cacheSyncStrategy it would use for a regular 
 *  single-record request on that DataSource.  Note that in this case, the default strategy can
 *   be auto-overridden by the framework just like a normal single-update strategy.
 *  <p>
 *  You can also just set a specific <code>cacheSyncStrategy</code> on the DataSource, operation
 *  or DSRequest, just like with a regular single-record request, and again, these specific 
 *  settings are not auto-overridden except in cases where they could potentially cause feature 
 *  breakage, as described above.
     * @see com.smartgwt.client.types.CacheSyncStrategy
     * @see com.smartgwt.client.data.OperationBinding#getCanSyncCache
     * @see com.smartgwt.client.data.OperationBinding#getUseForCacheSync
     * @see com.smartgwt.client.data.OperationBinding#getCacheSyncOperation
 * @see com.smartgwt.client.data.DSResponse#getInvalidateCache
 */
public interface CacheSynchronization {
}
