You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xap-commits@incubator.apache.org by jm...@apache.org on 2007/02/20 06:03:06 UTC
svn commit: r509431 - in /incubator/xap/trunk/codebase/src/xap/data: bridge/
controller/ datasource/
Author: jmargaris
Date: Mon Feb 19 22:03:05 2007
New Revision: 509431
URL: http://svn.apache.org/viewvc?view=rev&rev=509431
Log:
better documentation and some simplification
Modified:
incubator/xap/trunk/codebase/src/xap/data/bridge/DataSourceBridge.js
incubator/xap/trunk/codebase/src/xap/data/bridge/ObjectDataSourceBridge.js
incubator/xap/trunk/codebase/src/xap/data/bridge/SimpleDocumentDataSourceBridge.js
incubator/xap/trunk/codebase/src/xap/data/controller/Binding.js
incubator/xap/trunk/codebase/src/xap/data/controller/Iterator.js
incubator/xap/trunk/codebase/src/xap/data/datasource/AbstractDataSource.js
incubator/xap/trunk/codebase/src/xap/data/datasource/ObjectDataSource.js
incubator/xap/trunk/codebase/src/xap/data/datasource/QueryRecord.js
incubator/xap/trunk/codebase/src/xap/data/datasource/SimpleDocumentDataSource.js
Modified: incubator/xap/trunk/codebase/src/xap/data/bridge/DataSourceBridge.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/xap/data/bridge/DataSourceBridge.js?view=diff&rev=509431&r1=509430&r2=509431
==============================================================================
--- incubator/xap/trunk/codebase/src/xap/data/bridge/DataSourceBridge.js (original)
+++ incubator/xap/trunk/codebase/src/xap/data/bridge/DataSourceBridge.js Mon Feb 19 22:03:05 2007
@@ -89,9 +89,7 @@
// Protected Methods.
//-----------------------------------------------------------------------
/**
- * Calls initialize() on the data source
- * and adds the data source to the dataSourceContainer if the initialize
- * call was successfull.
+ * Adds the data source to the dataSourceContainer after checking for a valid ID.
* @throws InitializationException
*/
xap.data.bridge.DataSourceBridge.prototype.initializeDataSource = function () {
@@ -101,8 +99,6 @@
if (!id || xap.xml.dom.XapElement.isGeneratedId(id)){
throw new xap.util.Exception("Data source did not have an id: "+ this.getElement().toXml());
}
-
- this._dataSource.initialize(id, this.getSession(), this.getElement());
this.getDataSourceContainer().put(id, this._dataSource);
};
/**
Modified: incubator/xap/trunk/codebase/src/xap/data/bridge/ObjectDataSourceBridge.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/xap/data/bridge/ObjectDataSourceBridge.js?view=diff&rev=509431&r1=509430&r2=509431
==============================================================================
--- incubator/xap/trunk/codebase/src/xap/data/bridge/ObjectDataSourceBridge.js (original)
+++ incubator/xap/trunk/codebase/src/xap/data/bridge/ObjectDataSourceBridge.js Mon Feb 19 22:03:05 2007
@@ -34,7 +34,7 @@
//protected DataSource
xap.data.bridge.ObjectDataSourceBridge.prototype.createDataSource = function () {
- return new xap.data.datasource.ObjectDataSource();
+ return new xap.data.datasource.ObjectDataSource(this.getSession());
};
xap.data.bridge.ObjectDataSourceBridge.prototype.initializeDataSource = function () {
Modified: incubator/xap/trunk/codebase/src/xap/data/bridge/SimpleDocumentDataSourceBridge.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/xap/data/bridge/SimpleDocumentDataSourceBridge.js?view=diff&rev=509431&r1=509430&r2=509431
==============================================================================
--- incubator/xap/trunk/codebase/src/xap/data/bridge/SimpleDocumentDataSourceBridge.js (original)
+++ incubator/xap/trunk/codebase/src/xap/data/bridge/SimpleDocumentDataSourceBridge.js Mon Feb 19 22:03:05 2007
@@ -40,7 +40,7 @@
//protected DataSource
xap.data.bridge.SimpleDocumentDataSourceBridge.prototype.createDataSource = function () {
- return new xap.data.datasource.SimpleDocumentDataSource();
+ return new xap.data.datasource.SimpleDocumentDataSource(this.getSession());
};
xap.data.bridge.SimpleDocumentDataSourceBridge.prototype.initializeDataSource = function () {
Modified: incubator/xap/trunk/codebase/src/xap/data/controller/Binding.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/xap/data/controller/Binding.js?view=diff&rev=509431&r1=509430&r2=509431
==============================================================================
--- incubator/xap/trunk/codebase/src/xap/data/controller/Binding.js (original)
+++ incubator/xap/trunk/codebase/src/xap/data/controller/Binding.js Mon Feb 19 22:03:05 2007
@@ -336,26 +336,3 @@
}
};
-/**
- * This method and isDataRetrievalListener
- * will be used by the data source to determine
- * which sort of result set to expect
- * Their return values will be NOT'd in
- * the Iterator class's implementation.
- * @return false
-**/
-xap.data.controller.Binding.prototype.isDataSetRetrievalListener = function () {
- return false;
-};
-/**
- * This method and isDataSetRetrievalListener
- * will be used by the data source to determine
- * which sort of result set to expect
- * Their return values will be NOT'd in
- * the Iterator class's implementation.
- * @return true
-**/
-xap.data.controller.Binding.prototype.isDataRetrievalListener = function () {
- return true;
-};
-
Modified: incubator/xap/trunk/codebase/src/xap/data/controller/Iterator.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/xap/data/controller/Iterator.js?view=diff&rev=509431&r1=509430&r2=509431
==============================================================================
--- incubator/xap/trunk/codebase/src/xap/data/controller/Iterator.js (original)
+++ incubator/xap/trunk/codebase/src/xap/data/controller/Iterator.js Mon Feb 19 22:03:05 2007
@@ -64,6 +64,8 @@
this._parentLocation.setLocationListener(this);
this._name = name;
this._session = session;
+
+ this._iterating = false;
/*xap.data.controller.ElementLocation*/
var iteratorLocation = new xap.data.controller.ElementLocation(this._iteratorElement);
iteratorLocation.setLocationListener(this);
@@ -123,85 +125,8 @@
}
}
};
-Xap.setupClassAsSubclassOf("xap.data.controller.Iterator", "Object");
-/**
- * @private
- * The select string
- */
-xap.data.controller.Iterator.prototype._select = null;
-/**
- * @private
- * The name of this iterator.
- */
-xap.data.controller.Iterator.prototype._name = null;
-/**
- * @private
- * {xap.xml.dom.XapElement}
- * The <iterator> tag itself
- */
-xap.data.controller.Iterator.prototype._iteratorElement = null;
-/**
- * The parent of the <iterator> tag. We really also need to remember
- * something about the position of the iterator? Maybe we don't replace the
- * iterator until we do the first iteration, and when we iterate we just
- * find our own tag, remove it and then start adding the iterated items
- * in the position we were in. (Similar to include tag)
- * {xap.xml.dom.XapElement}
- * @private
- *
- */
-xap.data.controller.Iterator.prototype._parentElement = null;
-/**
- * @private
- * {xap.data.controller.ElementLocation}
- **/
-xap.data.controller.Iterator.prototype._parentLocation = null;
-/**
- * @private
- * {xap.xml.dom.XapElement}
- **/
-xap.data.controller.Iterator.prototype._iteratorPlaceHolderElement = null;
-/**
- * @
- private xap.data.controller.BindingType
-**/
-xap.data.controller.Iterator.prototype._bindingType = xap.data.controller.BindingType.ONE_TIME;
-
/**
- * @private
- * {xap.session.ClientSession }
-**/
-xap.data.controller.Iterator.prototype._session = null;
-/**
- * @private
- * {DataSet}
- * The current data set we are iterating over
- */
-xap.data.controller.Iterator.prototype._dataSet = null;
-/**
-* @private
-* {ContextStack}
-**/
-xap.data.controller.Iterator.prototype._contextStack = null;
-/**
-* @private
-* {Object}
-**/
-xap.data.controller.Iterator.prototype._context = null;
-/**
-* Listener on this iterator.
-* @private
-* {LocationListener}
-**/
-xap.data.controller.Iterator.prototype._locationListener;
-// This needs to be set to true while iterating
-// over a data set so that clean up logic can run without
-/**
- * @private boolean
-**/
-xap.data.controller.Iterator.prototype._iterating = false;
-/**
* Returns the name of this iterator.
*
* @return The name.
@@ -601,29 +526,6 @@
xap.data.controller.Iterator.prototype.remove = function () {
this.invalidate();
};
-/**
- * This method and isDataRetrievalListener
- * will be used by the data source to determine
- * which sort of result set to expect
- * Their return values will be NOT'd in
- * the <code>Binding</code> class's implementation.
- * @return true
-**/
-xap.data.controller.Iterator.prototype.isDataSetRetrievalListener = function () {
- return true;
-};
-/**
- * This method and isDataSetRetrievalListener
- * will be used by the data source to determine
- * which sort of result set to expect
- * Their return values will be NOT'd in
- * the <code>Binding</code> class's implementation.
- * @return false
-**/
-xap.data.controller.Iterator.prototype.isDataRetrievalListener = function () {
- return false;
-};
-
//-----------------------------------------------------------------------
Modified: incubator/xap/trunk/codebase/src/xap/data/datasource/AbstractDataSource.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/xap/data/datasource/AbstractDataSource.js?view=diff&rev=509431&r1=509430&r2=509431
==============================================================================
--- incubator/xap/trunk/codebase/src/xap/data/datasource/AbstractDataSource.js (original)
+++ incubator/xap/trunk/codebase/src/xap/data/datasource/AbstractDataSource.js Mon Feb 19 22:03:05 2007
@@ -27,91 +27,127 @@
Xap.require("xap.data.datasource.QueryRecord") ;
/**
-* An ease-of-use base class for DataSource implementations.
-*
-* <br><br>
-*
-* This class persists bound queries (i.e. queries whose binding type !=
-* BindingType.ONE_WAY) so that they can be later requeried when the data
-* changes.
-*
-* <br><br>
-*
-* This base class can also keep track of any queries that need to be postponed
-* and executed later if the data is being retrieved at the time of the original
-* query. It is up to the subclasses to take advantage of this functionality.
-* If subclasses add postponed queries, it is their responsibility to execute or
-* clean them up later (the queries are automatically cleaned up after the
-* execution).
-*
-* @author Igor Kaplansky
-* @author James Margaris
-*/
-xap.data.datasource.AbstractDataSource = function () {
+ * @fileoverview
+ * Implements the base class for all data sources.
+ */
+
+
+/**
+ * Creates a new AbstractDataSource.
+ *
+ * @class AbstractDataSource is the base class for all data sources. Data sources
+ * are typically declared in XML rather than instantiated in code.
+ * Data source methods can be called from XML as in the following example that
+ * loads a document data source with new data.
+ *
+ * <code><pre>
+ * <button text="Switch data source url"
+ * onCommand="dataSource:myDataSource.loadSourceFromServer('myPage.xml')" />
+ * </pre></code>
+ *
+ * @constructor
+ * @param {xap.session.ClientSession} session The client session this data source belongs to.
+ *
+ * @see xap.data.datasource.SimpleDocumentDataSource
+ * @see xap.data.datasource.ObjectDataSource
+ */
+xap.data.datasource.AbstractDataSource = function( session ) {
+ /** @private */
+ this._clientSession = session;
+ /** @private */
this._boundQueries = [];
+ /** @private */
this._postponedQueries = [];
+ /** @private */
this._asynchronousDataSourceListeners = [];
+ /** @private */
this._dataChangeListeners = [];
}
-/**
- * @see DataSource#initialize(String, ClientSession, Element)
- * <p/>
- * Subclasses have to call <code>super.initialize(String,ClientSession,
- * Element)</code> if they override this method.
- *
- *
- * @public
- * @param id{String}
- * @param session{ClientSession}
- * @param dataSourceElement{XapElement}
- * @return {void}
- * @throws InitializationException
- **/
-xap.data.datasource.AbstractDataSource.prototype.initialize = function (id, session, dataSourceElement) {
- this._id = id;
- this._clientSession = session;
- this._dataSourceElement = dataSourceElement;
-}
-
+/**
+ * Cleans up the data source.
+ *
+ * @private
+ */
xap.data.datasource.AbstractDataSource.prototype.destroy = function () {
this._boundQueries =[];
this._postponedQueries = [];
this._asynchronousDataSourceListeners = [];
this._dataChangeListeners = [];
}
+
+
/**
- * @see DataSource#getDataSet(String, DataSetRetrievalListener)
- * @public
- * @param query{String}
- * @param listener{DataRetrievalListener}
- * @param ctx a context (optional)
- * @throws DataAccessException, MalformedQueryException,UnsupportedBindingTypeException
- * @return {void}
+ * Attempts to run the query against the data source, calling the listener when the
+ * query is completed.
+ *
+ * @param {String} query A query string the datasource understands.
+ * @param listener A listener with a dataSetRetrieved() method to call back when the data is available.
+ * @param {xap.data.controller.ContextFrame} context An optional ContextFrame for nested iteration.
+ *
+ * @see xap.data.controller.Iterator#dataSetRetrieved <code>xap.data.controller.Iterator.dataSetRetrieved()</code> for an example listener.
**/
xap.data.datasource.AbstractDataSource.prototype.getDataSet = function (query, listener,context) {
- this.handleGenericQuery(query, context, listener);
+ //cases to cover here:
+ //if the listener is ONE_TIME and the source isn't available we need to save the postponed query
+ //if the listener is not ONE_TIME we need to save it as a bound query
+ //if the source is currently available we need to run the query
+
+
+ //if the listener is not ONE_TIME we need to save it for later
+ if (listener && listener.getBindingType() != xap.data.controller.BindingType.ONE_TIME) {
+ var queryRecord = new xap.data.datasource.QueryRecord(query, context, listener, true);
+ this._boundQueries.push(queryRecord);
+ }
+ //else if it IS ONE_TIME and we don't have a source yet we need to save the query
+ //for later
+ else if(!this.getSource()){
+ this.addPostponedQuery( query, context, listener, true );
+ }
+
+ if (this.getSource()){
+ this.handleQuery(query, context, listener, true);
+ }
};
+
+
/**
- * @see xap.data.datasource.DataSource#getDataSet
- * @public
- * @return {void}
- * @param query{String}
- * @param listener{DataRetrievalListener}
- * @param context{ContextFrame}
- * @throws DataAccessException, MalformedQueryException, UnsupportedBindingTypeException
+ * Atempts to run the query against the data source, calling the listener when the
+ * query is completed.
+ *
+ * @param {String} query A query string the datasource understands.
+ * @param listener A listener with a dataRetrieved() method to call back when the data is available.
+ * @param {xap.data.controller.ContextFrame} context An optional ContextFrame for nested iteration.
+ *
+ * @see xap.data.controller.Binding#dataRetrieved <code>xap.data.controller.Binding.dataRetrieved()</code>
**/
xap.data.datasource.AbstractDataSource.prototype.getData = function (query, listener, context) {
- this.handleGenericQuery(query, context, listener);
+ //if the listener is not ONE_TIME we need to save it for later
+ if (listener && listener.getBindingType() != xap.data.controller.BindingType.ONE_TIME) {
+ var queryRecord = new xap.data.datasource.QueryRecord(query, context, listener, false);
+ this._boundQueries.push(queryRecord);
+ }
+ //else if it IS ONE_TIME and we don't have a source yet we need to save the query
+ //for later
+ else if(!this.getSource()){
+ this.addPostponedQuery( query, context, listener, false );
+ }
+
+ if (this.getSource()){
+ this.handleQuery(query, context, listener, false);
+ }
}
/**
- * @see DataSource#removeListener(RetrievalListener)
- * @public
- * @param listener{RetrievalListener}
- * @return {void}
+ * Removes a listener that was registered in a call to <code>getData()</code> or
+ * <code>getDataSet()</code>.
+ *
+ * @param listener The listener to remove.
+ *
+ * @see #getData
+ * @see #getDataSet
**/
xap.data.datasource.AbstractDataSource.prototype.removeListener = function (listener) {
for (var i = 0; i < this._boundQueries.length; i++) {
@@ -129,52 +165,86 @@
}
}
};
+
/**
- * @param l{DataChangeListener}
+ * Adds a data change listener to the data source that will have
+ * <code>onDataChanged()</code> called whenever the data in this data source changes,
+ * with this data source as the argument. The data change listener is used for notification
+ * purposes only, queries should be run against the data source with a call to
+ * <code>getData()</code> or <code>getDataSet()</code>
+ *
+ * @param l The listener with the <code>onDataChanged()</code> method to add.
+ *
+ * @see #removeDataChangeListener
+ * @see #getData
+ * @see #getDataSet
+ *
**/
xap.data.datasource.AbstractDataSource.prototype.addDataChangeListener = function (l) {
if (! xap.util.ArrayHelper.contains(this._dataChangeListeners,l)) {
this._dataChangeListeners.push(l);
}
};
+
/**
- * @public
- * @param l{DataChangeListener}
- * @return {void}
+ * Removes a data change listener from the data source that was added via a call
+ * to <code>addDataChangeListener()</code>.
+ *
+ * @param l The listener to remove.
+ *
+ * @see #addDataChangeListener
**/
xap.data.datasource.AbstractDataSource.prototype.removeDataChangeListener = function (l) {
xap.util.ArrayHelper.removeElement(this._dataChangeListeners,l);
};
+
+
/**
- * @protected
- * @return {void}
- **/
+ * Fires the <code>onDataChanged()</code> on each data change listener.
+ *
+ * @private
+ */
xap.data.datasource.AbstractDataSource.prototype.fireDataChanged = function () {
for (var i = 0; i < this._dataChangeListeners.length; i++) {
this._dataChangeListeners[i].onDataChanged(this);
}
};
+
+
/**
- * @public
- * @param l{AsynchronousDataSourceListener}
- * @return {void}
+ * Adds an asynchronous data source listener to the data source that will have
+ * <code>onDataRequestCompleted</code> or <code>onDataRequestFailed</code> called whenever an asynchronous
+ * load of data completes successfully or fails, with this data source as the argument and
+ * an accompanying exception with <code>onDataRequestFailed</code> only.
+ *
+ * @param l The listener with the <code>onDataRequestCompleted()</code> and
+ * <code>onDataRequestFailed</code> methods to add.
+ *
+ * @see #removeAsynchronousDataSourceListener
+ * @see #loadSourceFromServer
+ *
**/
xap.data.datasource.AbstractDataSource.prototype.addAsynchronousDataSourceListener = function (l) {
if (!xap.util.ArrayHelper.contains(this._asynchronousDataSourceListeners,l)) {
this._asynchronousDataSourceListeners.push(l);
}
};
+
/**
- * @public
- * @return {void}
- * @param l{AsynchronousDataSourceListener}
+ * Removes an asynchronous data source listener from the data source that was added via a call
+ * to <code>addAsynchronousDataSourceListener()</code>.
+ *
+ * @param l The listener to remove.
+ *
+ * @see #addAsynchronousDataSourceListener
**/
xap.data.datasource.AbstractDataSource.prototype.removeAsynchronousDataSourceListener = function (l) {
xap.util.ArrayHelper.removeElement(this._asynchronousDataSourceListeners,l);
};
+
/**
- * @protected
- * @return {void}
+ * @private
+ * Fires onDataRequestCompleted() to each asynch listener.
**/
xap.data.datasource.AbstractDataSource.prototype.fireOnDataRetrieveSucess = function () {
/*for (int*/
@@ -182,10 +252,10 @@
this._asynchronousDataSourceListeners[i].onDataRequestCompleted(this);
}
};
+
/**
- * @protected
- * @param failureCause{Exception}
- * @return {void}
+ * @private
+ * Fires onDataRequestFailed() to each asynch listener.
**/
xap.data.datasource.AbstractDataSource.prototype.fireOnDataRetrieveFailure = function (failureCause) {
/*for (int*/
@@ -195,88 +265,90 @@
};
/**
- * @param container{Container}
- * @param name{String}
+ * Called when the data source is removed from the data source container, performing cleanup.
+ *
+ * @param {xap.session.Container} container The container the source was removed from.
+ * @param {String} name The name the data source was registered under in the container.
**/
xap.data.datasource.AbstractDataSource.prototype.removedFromContainer = function (container, name) {
this.destroy();
};
-//-----------------------------------------------------------------------
-// Public Methods.
-//-----------------------------------------------------------------------
+
/**
- * Requeries all bound queries notifying cached RetrievalListeners
- * with the new data.
- *
- * @throws DataAccessException
- * @throws MalformedQueryException
+ * Re-runs any queries bound to the data source. This method should be called
+ * after the source object is changed or modified.
*/
-/**
- * @public
- * @return {synchronized}
- * @throws DataAccessException, MalformedQueryException
- **/
xap.data.datasource.AbstractDataSource.prototype.refresh = function () {
this.fireDataChanged();
- this.requeryAll();
+ this.executeQueries(this._boundQueries);
+ this.executeQueries(this._postponedQueries);
+ this._postponedQueries = [];
};
+
+
-//----------------------------------------------------------------------
-// Protected Abstract Methods.
-//-----------------------------------------------------------------------
-/**
- * Subclasses are responsible for implementing this method. The query
- * details are obviously subclass specific. It is also up to the subclass
- * whether to execute the query asynchronously or not.
- *
- * @param query The query to execute
- * @param context The context for executing the query
- * @param listener The listener to notify with the results of the query
- * @throws DataAccessException
- * @throws MalformedQueryException
- * @protected
- * @param query{String}
- * @param context{ContextFrame}
- * @param listener{DataRetrievalListener}
- * @throws DataAccessException, MalformedQueryException;
+/**
+ * @private
+ *
+ * Runs a data query and calls the listener, we assume the source is valid at this point
+ * as it was checked earlier.
+ *
+ * @param {String} query The query to execute
+ * @param {xap.data.controller.ContextFrame} context An optional ContextFrame for nested iteration.
+ * @param listener A listener with a dataRetrieved() method to call back when the data is available.
**/
xap.data.datasource.AbstractDataSource.prototype.handleDataQuery = function (query, context, listener) {
+ var rawData = this.executeQuery(query, context) ;
+ listener.dataRetrieved(query, rawData, context);
};
+
/**
- * Subclasses are responsible for implementing this method. The query
- * details are obviously subclass specific. It is also up to the subclass
- * whether to execute the query asynchronously or not.
- *
- * @param query The query to execute
- * @param context The context for executing the query
- * @param listener The listener to notify with the results of the query
- * @throws DataAccessException
- * @throws MalformedQueryException
- * @protected
- * @param query{String}
- * @param context{ContextFrame}
- * @param listener{DataSetRetrievalListener }
- * @throws DataAccessException, MalformedQueryException
+ * @private
+ *
+ * Runs a data query and calls the listener, we assume the source is valid at this point
+ * as it was checked earlier.
+ *
+ * @param {String} query The query to execute
+ * @param {xap.data.controller.ContextFrame} context An optional ContextFrame for nested iteration.
+ * @param listener A listener with a dataSetRetrieved() method to call back when the data is available.
**/
xap.data.datasource.AbstractDataSource.prototype.handleDataSetQuery = function (query, context, listener) {
+ var theData = this.executeQuery(query, context) ;
+ var dataset = xap.data.datasource.AbstractDataSet.getDataSet(query, this, theData);
+ listener.dataSetRetrieved(query, dataset, context);
};
/**
- * Subclass should override to implement asynch loading of data source that comes
- * in a response body
+ * Runs a query against the data source with the given optional context. We assume the source
+ * is valid and was checked earlier. This base class implementation does nothing, subclasses
+ * should override it to run the query and return the resulting object.
+ *
+ * @param {String} queryString The string representing the query to run.
+ * @param {xap.data.controller.ContextFrame} An optional context object for nested iteration.
+ * @return The result of the query.
*/
-xap.data.datasource.AbstractDataSource.prototype.responseToDataSource = function(response){
-
+xap.data.datasource.AbstractDataSource.prototype.executeQuery =function(queryString , context){
+
}
+
/**
- * This should be overridden by subclasses to handle the asynchronous loading
- * of data.
- * @param a{String},
- * @param response{HttpResponse}
- **/
-xap.data.datasource.AbstractDataSource.prototype.requestCompleted = function (a, response) {
+ * Subclasses should override this method to support asynchronous loading of data.
+ *
+ * @param {XMLHttpRequest} response A completed request object with data that should be converted
+ * into data for the data source.
+ * @return The content of the XMLHttpRequest object parsed into an object suitable to the source object
+ * of the data source.
+ */
+xap.data.datasource.AbstractDataSource.prototype.responseToDataSource = function(response){}
+
+
+/**
+ * @private
+ * Callback method for asynchronous data loading.
+ */
+xap.data.datasource.AbstractDataSource.prototype.requestCompleted = function (url, response) {
try{
var dataSource = this.responseToDataSource( response );
this.setSource( dataSource );
@@ -286,224 +358,124 @@
//this sucess message. But we probably want them
//to be able to get the new source their listener
this.fireOnDataRetrieveSucess();
- this.executePostponedQueries();
+ this.refresh();
}
catch(e){
- this.getClientSession().handleException(e);
+ this.getSession().handleException(e);
this.fireOnDataRetrieveFailure(e);
- }
- finally {
- this.clearPostponedQueries();
- }
+ }
};
+
/**
- * This should be overridden by subclasses to handle the asynchronous loading
- * of data.
- * @param a{String}
- * @param e{NetServiceException}
- **/
+ * @private
+ * Callback method for asynchronous data loading.
+ */
xap.data.datasource.AbstractDataSource.prototype.requestFailed = function (a, e) {
- try {
- this.getClientSession().handleException(e);
- this.fireOnDataRetrieveFailure(e);
- }
- finally {
- this.clearPostponedQueries();
- }
-
+ this.getSession().handleException(e);
+ this.fireOnDataRetrieveFailure(e);
};
/**
- * @return the ClientSession this DataSource is associated with
+ * Returns the ClientSession object this data source belongs to.
+ * @return {xap.session.ClientSession} The ClientSession.
*/
-/**
- * @protected
- * @return {ClientSession}
- **/
-xap.data.datasource.AbstractDataSource.prototype.getClientSession = function () {
+xap.data.datasource.AbstractDataSource.prototype.getSession = function () {
return this._clientSession;
};
/**
- * @return the source object of the DataSource
- * @protected
- * @return {Object}
- **/
+ * Returns the object that serves as the source of this data source.
+ * @return The object that serves as the source of this data source.
+ */
xap.data.datasource.AbstractDataSource.prototype.getSource = function () {
return this._source;
};
+
/**
- * Asynchronously loads the source object using NetService
*
- * @param sourceUrl The url to the resource that is expected to return the
- * source object for this DataSource
- * @protected
- * @param sourceUri{String}
- * @return {void}
+ *
+ * Asynchronously loads a source object from a server URL. When the loading is complete
+ * the data source will refresh and any bindings will re-resolve.
+ *
+ * @param sourceUrl The url to the resource that will serve as the data source backing object.
**/
xap.data.datasource.AbstractDataSource.prototype.loadSourceFromServer = function (sourceUrl) {
+ //IMPORTANT change this to retrieve?
+
/*ClientSession*/
- var session = this.getClientSession();
+ var session = this.getSession();
/*RequestService*/
var netService = session.getRequestService();
netService.retrieveAsynchronously(sourceUrl, this);
};
+
/**
- * Sets the source object for this DataSource
+ * Sets the source object for this DataSource. This will automatically call
+ * <code>refresh()</code> after the source is set.
*
- * @param sourceObject The new source object
- * @protected
- * @param sourceObject{Object}
- * @return {void}
+ * @param sourceObject The new source object for the data source.
+ * @see #refresh
**/
xap.data.datasource.AbstractDataSource.prototype.setSource = function (sourceObject) {
this._source = sourceObject;
+
+ //TODO make conditional in some cases??
+ this.refresh();
};
/**
- * Adds a postponed query to this DataSource. This method can be used to
- * cache queries for later execution (for example if the source object is
- * loaded asynchronously, postponed queries can be executed when the object
- * finishes loading). Subclasses are responsible for clearing the posponed
- * query queue after the queries are executed.
- *
- * @param query
- * @param context
- * @param listener
- *
- * @protected
- * @return {void}
- * @param query{String}
- * @param context{ContextFrame}
- * @param listener{RetrievalListener }
+ * @private
+ * Adds a postponed query to this DataSource. A postponed query is a query
+ * that is postponed because the data is not yet available. Note that
+ * bound queries (ONE_WAY) should never be postponed as they run every time anyway.
**/
-xap.data.datasource.AbstractDataSource.prototype.addPostponedQuery = function (query, context, listener) {
- var queryRecord = new xap.data.datasource.QueryRecord(query, context, listener);
+xap.data.datasource.AbstractDataSource.prototype.addPostponedQuery = function (query, context, listener, isDataSetQuery) {
+ var queryRecord = new xap.data.datasource.QueryRecord(query, context, listener, isDataSetQuery);
this._postponedQueries.push(queryRecord);
}
/**
- * Executes all posponed queries in order they came in.
- * At the end of this method the postponed query vector is cleared
- * regardless of queries' execution result.
- *
- * @protected
- * @synchronized
+ * @private
+ * Runs all the queries in a given array of queries.
**/
-xap.data.datasource.AbstractDataSource.prototype.executePostponedQueries = function () {
- try {
- for (var i = 0; i < this._postponedQueries.length; i++) {
- /*QueryRecord*/
- var rec = this._postponedQueries[i];
- try {
- this.handleQuery(rec.getQuery(), rec.getContext(), rec.getListener());
- }
- catch (e) {
-
- //TODO instead of logging just throw this?
- this.getLog().exception(e);
- }
+xap.data.datasource.AbstractDataSource.prototype.executeQueries= function( queries ) {
+ for (var i = 0; i < queries.length; i++) {
+ /*QueryRecord*/
+ var rec = queries[i];
+ try {
+ this.handleQuery(rec.getQuery(), rec.getContext(), rec.getListener(), rec.isDataSetQuery());
+ }
+ catch (e) {
+ //TODO instead of logging just throw this?
+ this.getLog().error("Error executing databound query:" + rec.getQuery(), e);
}
- }
- finally {
- this.clearPostponedQueries();
}
}
-
/**
- * Clears the posponed query vector.
- *
- * @protected
- * @return {void}
- **/
-xap.data.datasource.AbstractDataSource.prototype.clearPostponedQueries = function () {
- this._postponedQueries = [];
-}
-
-/**
- * @return the static Log instance
- *
- * @protected
- * @return {Log}
+ * Returns the logger used to log DataSource issues.
+ * @returns {xap.log.Logger} The logger used to log DataSource issues.
**/
xap.data.datasource.AbstractDataSource.prototype.getLog = function () {
return xap.log.Logger.getLogger("DataSource");
};
-//-----------------------------------------------------------------------
-// Private Methods.
-//-----------------------------------------------------------------------
-/**
- * This method persists queries whose binding type != ONE_TIME).
- * It then delegates the call to a subclass whose responsibility is to
- * process the query in a way it sees fit (i.e. the query could be
- * executed synchronously or asynchronously).
- *
- * @param context The context for executing the query
- * @param query The query to execute
- * @param listener The listener to notify after the query finishes
- *
- * @throws DataAccessException
- * @throws MalformedQueryException
- * @throws UnsupportedBindingTypeException
- *
+
+/**
* @private
- * @return {void}
- * @param query{String}
- * @param context{ContextFrame}
- * @param listener{RetrievalListener }
- * @throws DataAccessException, MalformedQueryException,UnsupportedBindingTypeException
- **/
-xap.data.datasource.AbstractDataSource.prototype.handleGenericQuery = function (query, context, listener) {
- // take care of caching queries for later executions when the data
- // changes
- if (listener && listener.getBindingType() != xap.data.controller.BindingType.ONE_TIME) {
- var queryRecord = new xap.data.datasource.QueryRecord(query, context, listener);
- this._boundQueries.push(queryRecord);
+ * Delegates to either <code>handleDataSetQuery</code> or <code>handleDataQuery</code>
+ * that subclasses should have implemented.
+ */
+xap.data.datasource.AbstractDataSource.prototype.handleQuery = function (query, queryContext, listener, isDataSetQuery) {
+ this.getLog().trace("Executing query:" + query);
+ if (isDataSetQuery){
+ this.handleDataSetQuery(query, queryContext, listener);
}
- this.handleQuery(query, context, listener);
-};
-/**
- * A helper method for calling appropriate handleX methods
- * @private *
- * @param query
- * @param queryContextFrame
- * @param listener
- * @throws DataAccessException
- * @throws MalformedQueryException
- *
- * @param query{String}
- * @param queryContext{ContextFrame}
- * @param listener{RetrievalListener }
- **/
-xap.data.datasource.AbstractDataSource.prototype.handleQuery = function (query, queryContext, listener) {
- if (listener.isDataRetrievalListener()) {
-
+ else{
this.handleDataQuery(query, queryContext, listener);
- } else {
- if (listener.isDataSetRetrievalListener()) {
- this.handleDataSetQuery(query, queryContext, listener);
- }
- }
-};
-/**
- * Requeries all bound queries (binding type != xap.data.controller.BindingType.ONE_TIME)
- * @throws DataAccessException
- * @throws MalformedQueryException
- * @private
- * @return {void}
- * @throws DataAccessException, MalformedQueryException
- **/
-xap.data.datasource.AbstractDataSource.prototype.requeryAll = function () {
- for (var i = 0; i < this._boundQueries.length; i++) {
- /*QueryRecord*/
- var rec = this._boundQueries[i];
-
- this.handleQuery(rec.getQuery(), rec.getContext(), rec.getListener());
}
};
Modified: incubator/xap/trunk/codebase/src/xap/data/datasource/ObjectDataSource.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/xap/data/datasource/ObjectDataSource.js?view=diff&rev=509431&r1=509430&r2=509431
==============================================================================
--- incubator/xap/trunk/codebase/src/xap/data/datasource/ObjectDataSource.js (original)
+++ incubator/xap/trunk/codebase/src/xap/data/datasource/ObjectDataSource.js Mon Feb 19 22:03:05 2007
@@ -25,34 +25,53 @@
Xap.require("google.xpath");
+/**
+ * @fileoverview
+ * Implements a JavaScript object-based data source.
+ */
+
-xap.data.datasource.ObjectDataSource = function() {
- xap.data.datasource.AbstractDataSource.call(this) ;
+/**
+ * Creates a new ObjectDataSource.
+ *
+ * @class ObjectDataSource is a data source that runs JavaScript queries
+ * against a backing object. This object can be set using
+ * <code>setSource()</code> or loaded from a server-side URL that return JSON.
+ *
+ * @constructor
+ * @param {xap.session.ClientSession} session The client session this data source belongs to.
+ *
+ * @see xap.data.datasource.SimpleDocumentDataSource
+ * @see xap.data.datasource.AbstractDataSource
+ */
+xap.data.datasource.ObjectDataSource = function( session ) {
+ xap.data.datasource.AbstractDataSource.call(this, session) ;
};
+//SETUP SUBCLASS does this but we need this for doc to pick it up correctly
+xap.data.datasource.ObjectDataSource.prototype = new xap.data.datasource.AbstractDataSource();
+
Xap.setupClassAsSubclassOf("xap.data.datasource.ObjectDataSource", "xap.data.datasource.AbstractDataSource");
/**
- * Sets the source to be a document.
+ * Converts the response object into a datasource
+ * assume the response content is JSON that can be run through <code>eval</code>
+ * to return an object.
+ * This overrides the no-op version in <code>xap.data.datasource.AbstractDataSource</code>.
+ *
+ * @param {XMLHttpRequest} response A completed request object with data that should be converted
+ * into data for the data source.
+ * @return The content of the XMLHttpRequest object parsed into an object suitable to the source object
+ * of the data source.
*/
-xap.data.datasource.ObjectDataSource.prototype.setSource = function( object ) {
- this.superclass.setSource.call(this, object );
-
- //TODO this should be conditional?
- this.refresh();
-
-
-};
-
-
-
xap.data.datasource.ObjectDataSource.prototype.responseToDataSource = function(response){
var result = dj_eval( '(' + response.responseText + ')');
return result ;
}
/**
+ * @private
* Mozilla supports an eval() on object itself but IE does not. This normalizes the behavior
* against both browsers. Note that by doing this to run a string against an object you have to
* do something like 'this.employees' not just 'employees'
@@ -66,44 +85,14 @@
return object._eval(evalText);
}
-//TODO move this to a base class?
-xap.data.datasource.ObjectDataSource.prototype.handleDataQuery = function(query, context, listener) {
-
- if (!this.getSource()){
- if (listener.getBindingType() == xap.data.controller.BindingType.ONE_TIME){
- this.addPostponedQuery( query, context, listener );
- }
- }
- else{
- var rawData = this.executeQuery(context, query) ;
- listener.dataRetrieved(query, rawData, context);
- }
-};
-
-//TODO move this to a base class?
-xap.data.datasource.ObjectDataSource.prototype.handleDataSetQuery = function(query, context, listener) {
-
- if (!this.getSource()){
- if (listener.getBindingType() == xap.data.controller.BindingType.ONE_TIME){
- this.addPostponedQuery( query, context, listener );
- }
-
- }
- else{
- theData = this.executeQuery(context, query) ;
- var dataset = xap.data.datasource.AbstractDataSet.getDataSet(query, this, theData);
- listener.dataSetRetrieved(query, dataset, context);
- }
-};
-
-
-
/**
- * Execute query against a DOM
- * @see handleDataQuery
- * @see handleDataSetQuery
-**/
-xap.data.datasource.ObjectDataSource.prototype.executeQuery =function(context ,queryString){
+ * Executes the JavaScript query against the source object or context object if it is defined.
+ * This overrides the no-op version in <code>xap.data.datasource.AbstractDataSource</code>.
+ *
+ * @param {String} queryString A JavaScript string that can be run against an object.
+ * @param {xap.data.controller.ContextFrame} context An optional ContextFrame for nested iteration.
+ */
+xap.data.datasource.ObjectDataSource.prototype.executeQuery =function(queryString , context){
var contextObject = this.getSource();
if (context){
@@ -111,6 +100,5 @@
}
//eval query string relative to context object
-
return this.evalOnObject(queryString,contextObject);
}
Modified: incubator/xap/trunk/codebase/src/xap/data/datasource/QueryRecord.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/xap/data/datasource/QueryRecord.js?view=diff&rev=509431&r1=509430&r2=509431
==============================================================================
--- incubator/xap/trunk/codebase/src/xap/data/datasource/QueryRecord.js (original)
+++ incubator/xap/trunk/codebase/src/xap/data/datasource/QueryRecord.js Mon Feb 19 22:03:05 2007
@@ -27,24 +27,17 @@
* and all the listeners that get notified after the execution. Only one
* QueryRecord is created for a given query.
*/
-xap.data.datasource.QueryRecord = function(){
- /*private String*/
- this._query = null;
- /*private Context*/
- this._context = null;
- /*private RetrievalListener*/
- this._listener = null;
-}
-
+
/**
* @param query{String}
* @param context{Context}
* @param listener{RetrievalListener }
**/
-xap.data.datasource.QueryRecord = function( query, context, listener ) {
+xap.data.datasource.QueryRecord = function( query, context, listener, isDataSetQuery ) {
this._query = query;
this._context = context;
this._listener = listener;
+ this._isDataSetQuery = isDataSetQuery;
}
/**
* @return {String}
@@ -66,4 +59,10 @@
xap.data.datasource.QueryRecord.prototype.getListener = function() {
return this._listener;
}
+
+xap.data.datasource.QueryRecord.prototype.isDataSetQuery = function() {
+ return this._isDataSetQuery;
+}
+
+
Modified: incubator/xap/trunk/codebase/src/xap/data/datasource/SimpleDocumentDataSource.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/xap/data/datasource/SimpleDocumentDataSource.js?view=diff&rev=509431&r1=509430&r2=509431
==============================================================================
--- incubator/xap/trunk/codebase/src/xap/data/datasource/SimpleDocumentDataSource.js (original)
+++ incubator/xap/trunk/codebase/src/xap/data/datasource/SimpleDocumentDataSource.js Mon Feb 19 22:03:05 2007
@@ -25,18 +25,41 @@
Xap.require("google.xpath");
-
-xap.data.datasource.SimpleDocumentDataSource = function() {
- xap.data.datasource.AbstractDataSource.call(this) ;
+/**
+ * @fileoverview
+ * Implements an XML document-based data source.
+ */
+
+
+/**
+ * Creates a new SimpleDocumentDataSource.
+ *
+ * @class SimpleDocumentDataSource is a data source that runs XPath queries
+ * against a backing XML Document. This document can be set using
+ * <code>setSource()</code> or loaded from a server-side URL that return XML.
+ *
+ * @constructor
+ * @param {xap.session.ClientSession} session The client session this data source belongs to.
+ *
+ * @see xap.data.datasource.ObjectDataSource
+ * @see xap.data.datasource.AbstractDataSource
+ */
+xap.data.datasource.SimpleDocumentDataSource = function( session ) {
+ xap.data.datasource.AbstractDataSource.call(this, session) ;
};
+
+//SETUP SUBCLASS does this but we need this for doc to pick it up correctly
+xap.data.datasource.SimpleDocumentDataSource.prototype = new xap.data.datasource.AbstractDataSource();
Xap.setupClassAsSubclassOf("xap.data.datasource.SimpleDocumentDataSource", "xap.data.datasource.AbstractDataSource");
-//TODO take a name and register the document as a name?
/**
- * Sets the source to be a document.
+ * Sets the source and throws and exception if the source is not an XML document.
+ * This will automatically call
+ * <code>refresh()</code> after the source is set.
+ * @param {xap.xml.dom.Document} document The document to serve as the new source.
*/
xap.data.datasource.SimpleDocumentDataSource.prototype.setSource = function( document ) {
if (! document instanceof xap.xml.dom.Document){
@@ -45,79 +68,35 @@
throw new xap.util.Exception("Source for a document source must be a document");
}
this.superclass.setSource.call(this, document );
-
- //TODO this should be conditional if they set refreshOnStructureChange to true
- this.refresh();
-
-
};
-
+/**
+ * Converts the response object into a datasource
+ * assume the response content is XML taht can be parsed into a document.
+ * This overrides the no-op version in <code>xap.data.datasource.AbstractDataSource</code>.
+ *
+ * @param {XMLHttpRequest} response A completed request object with data that should be converted
+ * into data for the data source.
+ * @return The content of the XMLHttpRequest object parsed into an object suitable to the source object
+ * of the data source.
+ */
xap.data.datasource.SimpleDocumentDataSource.prototype.responseToDataSource = function(response){
var parser = xap.xml.ParserFactory.getParser();
var doc = parser.parse( response.responseText );
return doc;
}
-/**
- * @see AbstractDataSource#handleDataQuery( String, Context,
- * DataRetrievalListener )
- *
- * @protected
- * @param query{String}
- * @param context{Context}
- * @param listener{DataRetrievalListener}
- * @throws DataAccessException, MalformedQueryException
- * @return {void}
-**/
-xap.data.datasource.SimpleDocumentDataSource.prototype.handleDataQuery = function(query, context, listener) {
-
- if (!this.getSource()){
- if (listener.getBindingType() == xap.data.controller.BindingType.ONE_TIME){
- this.addPostponedQuery( query, context, listener );
- }
- }
- else{
- var rawData = this.executeQuery(context, query) ;
- listener.dataRetrieved(query, rawData, context);
- }
-};
-
-/**
- * @see AbstractDataSource#handleDataSetQuery( String, Context, * DataSetRetrievalListener )
- *
- * @protected
- * @return {void}
- *
- * @param query{String}
- * @param context{Context}
- * @param listener{DataSetRetrievalListener }
- * @throws DataAccessException, MalformedQueryException
-**/
-xap.data.datasource.SimpleDocumentDataSource.prototype.handleDataSetQuery = function(query, context, listener) {
-
- if (!this.getSource()){
- if (listener.getBindingType() == xap.data.controller.BindingType.ONE_TIME){
- this.addPostponedQuery( query, context, listener );
- }
-
- }
- else{
- theData = this.executeQuery(context, query) ;
- var dataset = xap.data.datasource.AbstractDataSet.getDataSet(query, this, theData);
- listener.dataSetRetrieved(query, dataset, context);
- }
-};
-
/**
- * Execute query against a DOM
- * @see handleDataQuery
- * @see handleDataSetQuery
-**/
-xap.data.datasource.SimpleDocumentDataSource.prototype.executeQuery =function(context ,queryString){
+ * Executes the XPath query against the source document or context object if it is defined.
+ * This overrides the no-op version in <code>xap.data.datasource.AbstractDataSource</code>.
+ *
+ * @param {String} queryString An XPath string that can be run against an object.
+ * @param {xap.data.controller.ContextFrame} context An optional ContextFrame for nested iteration.
+ */
+xap.data.datasource.SimpleDocumentDataSource.prototype.executeQuery =function(queryString ,context){
var contextObject = this.getSource();
if (context){