[OpenLayers-Commits] r10944 - in sandbox/august/trunk: lib/OpenLayers/Protocol lib/OpenLayers/Protocol/AgsFeatureAccess playground playground/ags tests/Format

commits-20090109 at openlayers.org commits-20090109 at openlayers.org
Fri Dec 3 01:58:49 EST 2010


Author: augusttown
Date: 2010-12-02 22:58:49 -0800 (Thu, 02 Dec 2010)
New Revision: 10944

Added:
   sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess.js
   sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess/
   sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess/v2.js
   sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess/v2_0.js
   sandbox/august/trunk/playground/ags/
   sandbox/august/trunk/playground/ags/agsfeatureaccess.html
   sandbox/august/trunk/playground/ags/agsfeatureaccess.js
   sandbox/august/trunk/tests/Format/AgsJsAdapter_Renderer.html
   sandbox/august/trunk/tests/Format/AgsJsAdapter_Renderer.js
Log:
Add and update ArcGIS Server Feature Service (Feature Access) support.

Added: sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess/v2.js
===================================================================
--- sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess/v2.js	                        (rev 0)
+++ sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess/v2.js	2010-12-03 06:58:49 UTC (rev 10944)
@@ -0,0 +1,486 @@
+/**
+ * @requires OpenLayers/Protocol/AgsFeatureAccess.js
+ * @requires OpenLayers/Format/AgsJsAdapter.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.AgsFeatureAccess.v2
+ * Abstract class for for v2.0 or above protocol.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Protocol>
+ */
+OpenLayers.Protocol.AgsFeatureAccess.v2 = OpenLayers.Class(OpenLayers.Protocol, {
+	
+	/**
+     * Property: version
+     * {String} AgsFeatureAccess ArcGIS JavaScript API version number.
+     */
+    version: null,
+	
+    /**
+     * Property: srsName
+     * {String} Name of spatial reference system.  Default is "EPSG:4326".
+     */
+    srsName: "EPSG:4326",
+    
+    /**
+     * Property: format
+     * {Object} the format used to parse information from features service
+     */
+    format: null,
+    
+    /**
+     * Property: formatOptions
+     * {Object} Optional options for the format.  If a format is not provided,
+     *     this property can be used to extend the default format options.
+     */
+    formatOptions: null,
+    
+    /**
+     * Property: agsFeatureLayer
+     * 
+     * 
+     */
+    agsFeatureLayer: null,
+    
+    /**
+     * 
+     */
+    isAgsFeatureLayerLoaded: false,
+    
+    /**
+     * Property: query
+     * {Object} query option used to generate esri.tasks.Query
+     */
+    _query: null,
+    
+    /**
+     * Property: defaultQuery
+     * {Object} default query option used to generate esri.tasks.Query
+     */
+    defaultQuery: {
+		outFields: [ "*" ],	// meaning all fields? didn't find it in JS API doc though
+		returnGeometry: true,
+		where: "",
+		outSpatialReference: this.srsName
+		// TODO: more default query option	
+	},
+	
+	/**
+	 * Property: style
+	 * {OpenLayers.Style}
+	 * 
+	 * Style converted from ArcGIS Server Feature Service layer's renderer
+	 */
+	style: null,
+	
+	/**
+	 * 
+	 */
+	templates: null,
+	
+	/**
+	 * 
+	 */
+	currentFeatureTemplate: null,
+	
+	/**
+	 * 
+	 */
+	layer: null,
+	
+	// TODO: feature template for inserting new features
+    	
+    /**
+     * Constructor: OpenLayers.Protocol.AgsFeatureAccess.v2
+     * A class for AgsFeatureAccess protocol.
+     *
+     * Parameters:
+     * options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     *
+     * Valid options properties:
+     *   url - {String} URL of ArcGIS Server Feature Service resource (required).
+     *
+     */
+    initialize: function(options) {
+        OpenLayers.Protocol.prototype.initialize.apply(this, [options]);        
+        if(!this.format) {
+            // initialize parser/encoder format if not provided
+        	this.format = new OpenLayers.Format.AgsJsAdapter();
+        }
+        if(this.url!=null && this.url!="") {        	
+        	// create an esri.layers.FeatureLayer to access features and do editing
+        	this.agsFeatureLayer = new esri.layers.FeatureLayer(
+        		this.url,
+        		{}	// many options are only applicable when using feature layer in JS API
+        	);    
+        	// creating feature layer is asynchronous, "onLoad" event fires when properties are loaded
+        	dojo.connect(
+        		this.agsFeatureLayer, 
+        		"onLoad",
+        		this,
+        		function(layer){
+        			OpenLayers.Console.debug("...feature layer loaded successfully...");
+        			this.isAgsFeatureLayerLoaded = true;
+        			// parse ArcGIS JS API renderer and create OpenLayers.Style out of it.
+        			var agsRendererType = layer.renderer.declaredClass;		// is 'declaredClass' a standard way to tell a class type or is it just esri thing
+        			// agsRendererType can only be one of the following three: esri.renderer.SimpleRenderer, esri.renderer.ClassBreaksRenderer, or esri.renderer.UniqueValueRenderer
+        			var agsRendererParserType = agsRendererType.split(".")[2];
+        			this.style = this.format.parseAgsRenderer[agsRendererParserType].apply(this.format, [layer.renderer]);
+        			OpenLayers.Console.debug("...feature layer renderer parsed successfully...");
+        			// TODO: feature layer metadata has both 'templates' and 'types', so which should be used for template based editing?
+        			//   I think 'templates', but by default it is empty, shall I instead use 'types'?
+        			//   e.g. http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0?f=json
+        			//   "templates" is null, but "types" has all templates, why???
+        			this.templates = this.format.parseAgsFeatureTypes.apply(this.format, [layer.types]);
+        			OpenLayers.Console.debug("...feature layer feature types parsed successfully...");
+        			
+        			this.currentFeatureTemplate = this.templates[0];	//use the first template as default; user can change it through setCurrentFeatureTemplate()
+        			// this is for template based feature editing
+        			// DrawFeature trigger this event right before a feature is inserted  
+        			// if manually insert feature then you have to call this.applyCurrentFeatureTemplate(feature) yourself before adding feature to layer
+        			if(this.currentFeatureTemplate) {
+        				var applyTemplateFunc = function(obj) {	// obj is usually an event {feature:feature} 
+    						var feature = obj.feature || obj;
+    						this.applyCurrentFeatureTemplate(feature);
+    					};
+        				this.layer.events.on({
+        					'sketchcomplete': applyTemplateFunc,	      						
+        					scope: this
+        				});
+        			}
+        		}
+        	);        	
+        } else {
+        	OpenLayers.Console.error("...fail to initialize OpenLayers.Protocol.AgsFeatureAccess.v2...invalid or null url...");
+    		throw "...fail to initialize OpenLayers.Protocol.AgsFeatureAccess.v2...invalid or null url...";
+        }
+        if(options.query) {
+        	this._query = OpenLayers.Util.extend(
+            	this.defaultQuery,
+            	options.query
+        	);
+        }
+        // anything else to do?
+    },	
+    
+    /**
+     * APIMethod: destroy
+     * Clean up the protocol.
+     */
+    destroy: function() {
+        if(this.options && !this.options.format) {
+            this.format.destroy();
+        }
+        this.format = null;
+        OpenLayers.Protocol.prototype.destroy.apply(this);
+    },
+    
+    /**
+     * Method: read
+     *   Rely on FeatureLayer of ArcGIS JS API for reading new features.  
+     */
+    read: function(options) {
+        OpenLayers.Protocol.prototype.read.apply(this, arguments);
+        options = OpenLayers.Util.extend({}, options);
+        OpenLayers.Util.applyDefaults(options, this.options || {});
+        
+        /*
+         * usually a strategy like BBOX or Fixed call read() with following options
+         *   filter - {OpenLayers.Filter}
+         *   callback - {function}
+         *   scope - {object}
+         */ 
+        if(options.filter instanceof OpenLayers.Filter.Spatial) {
+        	// set 'geometry' and 'spatialRelationship' in this.query
+        	if(options.filter.type == OpenLayers.Filter.Spatial.BBOX) {	// BBOX filter
+        		var bbox = options.filter.value;
+        		this._query.geometry = bbox;
+        		this._query.spatialRelationship = 'INTERSECTS';
+        	} else {	// other spatial filters
+        		// TODO: to be implemented 
+        	}
+        } else if(options.filter instanceof OpenLayers.Filter.FeatureId) {
+        	// simple case: set 'where' in this.query
+        	// TODO: to be implemented
+        } else if(options.filter instanceof OpenLayers.Filter.Comparison) {
+        	// simple case: set 'where' in this.query
+        	// TODO: to be implemented
+        } else {
+        	// TODO: compound filter case
+        	// TODO: need a format to convert filter object to a where clause
+        }    
+        
+        // a spatial query can be translated to a geometry plus a spatial relationship in esri.tasks.Query
+        var agsQuery = this.format.encodeAgsQuery.apply(this.format, [this._query]);        
+        // important!!!
+        options['parser'] = this.format;	// include this.format so it can be called within the single callback with other scope
+        options['layer'] = this.layer;	// include this.layer so you can set style on layer
+        if(this.style && this.style instanceof OpenLayers.Style) {
+        	options['style'] = this.style;
+        }
+        // call queryFeatures on this.agsFeatureLayer
+        if(this.isAgsFeatureLayerLoaded == true) {
+        	this.agsFeatureLayer.queryFeatures(
+                agsQuery,
+                OpenLayers.Util.AgsUtil.createSingleCallback(        		
+                	[this.handleRead],
+                	options,
+                	options.scope
+                ),
+                this.handleError
+            ); 
+        } else {
+        	OpenLayers.Console.warn("...features not loaded...");
+        	OpenLayers.Console.warn("...this.agsFeatureLayer feature layer is not loaded yet...try query feature later...");    		
+        }                    
+    },
+    
+    /**
+     * Method: handleRead
+     * Deal with response from the read request.
+     *
+     * Parameters:
+     *   response - {<esri.tasks.FeatureSet>} the response featureSet passed back by esri.layers.FeatureLayer.
+     *   options - {Object} The user options passed to the read call.
+     */
+    handleRead: function(response, options) {
+    	if(options.callback) {
+            // parseFeatures from response {<esri.tasks.FeatureSet>}
+    		// call options.callback with OpenLayers features as input
+    		var olFeatures = options.parser.parseAgsResults['featureSet'].apply(options.parser, [response]);    		
+    		// for each feature create the plain style hash object based this.style (OpenLayers.Style generated out of feature layer renderer)
+    		if(options['style']) {
+	    		if(options['layer']) {	    			
+	    			options['layer'].styleMap = new OpenLayers.StyleMap(
+	    				{
+	    					// TODO: document here how missing 'select' and 'temporary' ends up with a surprisingly good effect on picture marker symbol
+	    					'default': options['style'],	    					
+	    					//'select': new OpenLayers.Style(OpenLayers.Feature.Vector.style["select"]),	// TODO: create 'select' style based on default style
+	    					//'temporary': new OpenLayers.Style(OpenLayers.Feature.Vector.style["temporary"]),	// TODO: create 'temporary' style based on default style
+	    					//'delete': new OpenLayers.Style(OpenLayers.Feature.Vector.style["delete"]),	// TODO: create 'delete' style based on default style
+	    				},
+	    				{}
+	    			);	    			
+	    		} else {
+	    			for(var i=0; i<olFeatures.length; i++) {
+		    			//olFeatures[i].style = options['style'].createSymbolizer(olFeatures[i]);
+		    		}
+	    		}    			
+    		}
+    		options.callback.call(options.scope, {features: olFeatures});
+        }
+    },
+    
+    /**
+     * Method: commit
+     * Given a list of feature, assemble a batch request for update, create,
+     *     and delete transactions. Rely on ArcGIS JS API to commit the changes back to server
+     *     under the hood calling applyEdits(adds?, updates?, deletes?, callback?, errback?) of esri.layers.FeatureLayer 
+     *
+     * Parameters:
+     *   features - {Array(<OpenLayers.Feature.Vector>}
+     *
+     * Returns:
+     *   dojo.Deferred as ArcGIS JS API does
+     */
+    commit: function(features, options) {
+    	var deferred = null;
+    	options = OpenLayers.Util.extend({}, options);
+        OpenLayers.Util.applyDefaults(options, this.options);
+        //OpenLayers.Console.debug("...commit local changes to server...");
+        var featuresToEdit = [];
+        var featuresToAdd = [];
+        var featuresToUpdate = [];
+        var featuresToDelete = [];
+        
+        for(var i=0; i<features.length; i++) {
+        	if(features[i].state == OpenLayers.State.INSERT) {
+        		featuresToAdd.push(features[i]);
+        		featuresToEdit.push(features[i]);
+        	} else if(features[i].state == OpenLayers.State.UPDATE) {       		
+        		//OpenLayers.Console.debug("...feature id: + " + features[i].id + "...");
+            	//OpenLayers.Console.debug("...feature status: + " + features[i].state + "...");
+        		if((features[i].attributes.objectid!=null && features[i].attributes.objectid!="")
+        			|| (features[i].attributes.OBJECTID!=null && features[i].attributes.OBJECTID!="")
+        			|| (features[i].fid!=null && features[i].fid!="")) {
+        			// for ArcGIS Server Feature Service, you can only edit features with valid objectid
+        			if(features[i].fid &&(!features[i].attributes.objectid&&!features[i].attributes.OBJECTID)) {
+        				features[i].attributes.objectid = features[i].fid;
+        				features[i].attributes.OBJECTID = features[i].fid;
+        			}
+        			featuresToUpdate.push(features[i]);
+        			featuresToEdit.push(features[i]);
+        		} else {
+        			OpenLayers.Console.debug("...skip commiting changes of feature: + " + features[i].id + "...no valid objectid found...");
+        		}
+        	} else if(features[i].state == OpenLayers.State.DELETE) {
+        		//OpenLayers.Console.debug("...feature id: + " + features[i].id + "...");
+            	//OpenLayers.Console.debug("...feature status: + " + features[i].state + "...");
+        		if((features[i].attributes.objectid!=null && features[i].attributes.objectid!="")
+        			|| (features[i].attributes.OBJECTID!=null && features[i].attributes.OBJECTID!="")
+            		|| (features[i].fid!=null && features[i].fid!="")) {
+        			// for ArcGIS Server Feature Service, you can only edit features with valid objectid
+        			if(features[i].fid &&(!features[i].attributes.objectid&&!features[i].attributes.OBJECTID)) {
+        				features[i].attributes.objectid = features[i].fid;
+        				features[i].attributes.OBJECTID = features[i].fid;
+        			}
+        			featuresToDelete.push(features[i]);
+        			featuresToEdit.push(features[i]);
+        		} else {
+        			OpenLayers.Console.debug("...skip commiting changes of feature: + " + features[i].id + "...no valid objectid found...");
+        		}
+        	} else {
+        		// do nothing
+        	}
+        }    
+        options['featuresToEdit'] = featuresToEdit;
+        
+        var singleCallback = null;
+        
+        // need a variant of OpenLayers.Util.AgsUtil.createSingleCallback here
+        //   because callback of this.agsFeatureLayer.applyEdits takes three input parameters
+        if(window.dojo !== undefined) {
+        	singleCallback = dojo.hitch(
+        		this,//options.scope,
+        		function(addResults, updateResults, deleteResults) {						
+    				this.handleCommit.apply(options.scope, [addResults, updateResults, deleteResults, options]);					
+    			}
+        	);
+        } else {
+        	singleCallback = OpenLayers.Function.bind(
+        		function(addResults, updateResults, deleteResults) {						
+        			this.handleCommit.apply(options.scope, [addResults, updateResults, deleteResults, options]);					
+        		},
+        		this//options.scope
+        	);
+        }
+        
+        var agsFeaturesToAdd = this.format.encodeAgsGraphics.apply(this.format, [featuresToAdd, (this.srsName||this.layer.map.projection)]);
+        var agsFeaturesToUpdate = this.format.encodeAgsGraphics.apply(this.format, [featuresToUpdate, (this.srsName||this.layer.map.projection)]);
+        var agsFeaturesToDelete = this.format.encodeAgsGraphics.apply(this.format, [featuresToDelete, (this.srsName||this.layer.map.projection)]);
+        // call applyEdits on this.agsFeatureLayer
+        if(this.isAgsFeatureLayerLoaded == true) {
+        	deferred = this.agsFeatureLayer.applyEdits(
+        		agsFeaturesToAdd,        		
+        		agsFeaturesToUpdate,
+        		agsFeaturesToDelete,
+        		singleCallback,	// create single callback for succeeded commit
+                this.handleError	// TODO: create single callback for failed commit
+            ); 
+        } else {
+        	OpenLayers.Console.warn("...features not loaded...");
+        	OpenLayers.Console.warn("...this.agsFeatureLayer feature layer is not loaded yet...try commit changes later...");    		
+        }  
+        return deferred;
+    },
+    
+    /**
+     * Method: handleCommit
+     *   Called when the commit request returns.
+     * 
+     * Parameters: 
+     *   options - {Object} The user options passed to the commit call.
+     */
+    // only handle succeeded commits
+    handleCommit: function(addResults, updateResults, deleteResults, options) {
+    	//OpenLayers.Console.debug("...OpenLayers.Protocol.AgsFeatureAccess.v2.handleCommit is called...");
+    	if(options.callback) {   		
+    		var insertIds = [];
+    		for(var i=0; i<addResults.length; i++) {
+    			if(addResults[i].success == true) {
+    				insertIds.push(addResults[i].objectId);
+    				OpenLayers.Console.debug("...Collect objectId for inserted features...");
+    			}
+    		}
+    		// a fake OpenLayers.Protocol.Response has to be created
+    		//   pass it to OpenLayers.Strategy.Save because onCommit() is expecting a response object with
+    		//	 'code', 'reqFeatures' and 'insertIds' etc.
+    		var response = new OpenLayers.Protocol.Response({
+                requestType: "commit",
+                code: OpenLayers.Protocol.Response.SUCCESS,
+                reqFeatures: options['featuresToEdit'],
+                insertIds: insertIds
+            });    		
+    		options.callback.call(
+    			options.scope, 
+    			response
+    		);
+    	}
+    },
+    
+    /**
+     * Method: handleError
+     *   Deal with error response from the read request.
+     *
+     * Parameters:
+     *   error - {object} the error response from esri.layers.FeatureLayer.
+     *   
+     */
+    // only handle failed commits
+    handleError: function(error) {
+    	OpenLayers.Console.error(error);
+    },
+    
+    /**
+     * Method: setLayer
+     *   Point protocol to its parent vector layer
+     *
+     * Parameters:
+     *   layer - {OpenLayers.Layer.Vector}     
+     */
+    setLayer: function(layer) {
+    	this.layer = layer;
+    },
+    
+    /**
+     * Method: getFeatureTemplateByRule
+     * 
+     */
+    getFeatureTemplateByRule: function(rule) {
+    	for(var i=0; i<this.templates.length; i++) {
+    		/*
+    		 * TODO: it is a temporary solution to match rule.name to one of the templates's name  
+    		 */
+    		if(rule.name == this.templates[i].templates[0].name) {
+    			OpenLayers.Console.debug("...match a rule with a template...");
+    			OpenLayers.Console.debug("...rule name: " + rule.name + "...");
+    			OpenLayers.Console.debug("...template name: " + this.templates[i].templates[0].name + "...");    			
+    			return this.templates[i];
+    		}
+    	}
+    },
+    
+    /**
+     * Method: setCurrentFeatureTemplate
+     * 
+     * Parameters:
+     * 	 olFeatureTemplate - {} object
+     */
+    setCurrentFeatureTemplate: function(olFeatureTemplate) {
+    	if(olFeatureTemplate) {
+    		this.currentFeatureTemplate = olFeatureTemplate;
+    	} else {
+    		OpenLayers.Console.warn("...setCurrentFeatureTemplate...invalid feature template...skip setting...");
+    	}
+    },
+    
+    /**
+     * Method: applyCurrentFeatureTemplate
+     *   cast the input feature into another one using the current feature template
+     */
+    applyCurrentFeatureTemplate: function(olFeature) {
+    	if(olFeature) {
+    		// A feature template has both default values of attributes and a symbolizer too
+    		//   only apply the attributes part of template to the feature
+    		//   do not apply the symbolizer because symbolizer should be created out of layer's styleMap
+    		// TODO: to be corrected
+    		OpenLayers.Util.extend(olFeature.attributes, this.currentFeatureTemplate.templates[0].prototype.attributes);
+    		OpenLayers.Console.debug("...current feature template applied...");
+    	}
+    },
+    
+    CLASS_NAME: "OpenLayers.Protocol.AgsFeatureAccess.v2" 
+});
\ No newline at end of file

Added: sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess/v2_0.js
===================================================================
--- sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess/v2_0.js	                        (rev 0)
+++ sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess/v2_0.js	2010-12-03 06:58:49 UTC (rev 10944)
@@ -0,0 +1,31 @@
+/**
+ * @requires OpenLayers/Protocol/AgsFeatureAccess/v2.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.AgsFeatureAccess.v2_0
+ * A AgsFeatureAccess v2.0 protocol for vector layers.  Create a new instance with the
+ *     <OpenLayers.Protocol.AgsFeatureAccess.v2_0> constructor.
+ *
+ * Inherits from:
+ *  - <OpenLayers.Protocol.AgsFeatureAccess.v2>
+ */
+OpenLayers.Protocol.AgsFeatureAccess.v2_0 = OpenLayers.Class(OpenLayers.Protocol.AgsFeatureAccess.v2, {
+    
+    /**
+     * Property: version
+     * {String} ArcGIS JS API FeatureLayer version number.
+     */
+    version: "2.0",
+    
+    /**
+     * Constructor: OpenLayers.Protocol.AgsFeatureAccess.v2_0
+     *   A class for giving layers AgsFeatureAccess v2.0 protocol.
+     *
+     * Parameters:
+     *   options - {Object} Optional object whose properties will be set on the
+     *     instance.
+     */
+   
+    CLASS_NAME: "OpenLayers.Protocol.AgsFeatureAccess.v2_0" 
+});
\ No newline at end of file

Added: sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess.js
===================================================================
--- sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess.js	                        (rev 0)
+++ sandbox/august/trunk/lib/OpenLayers/Protocol/AgsFeatureAccess.js	2010-12-03 06:58:49 UTC (rev 10944)
@@ -0,0 +1,28 @@
+/**
+ * @requires OpenLayers/Protocol.js
+ */
+
+/**
+ * Function: OpenLayers.Protocol.AgsFeatureAccess
+ * Used to create a protocol to access ArcGIS Server Feature Service through ArcGIS JavaScript API.  Default version is 2.0.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol>} An AgsFeatureAccess protocol of the given version.
+ */
+OpenLayers.Protocol.AgsFeatureAccess = function(options) {
+    options = OpenLayers.Util.applyDefaults(
+        options, OpenLayers.Protocol.AgsFeatureAccess.DEFAULTS
+    );
+    var cls = OpenLayers.Protocol.AgsFeatureAccess["v"+options.version.replace(/\./g, "_")];
+    if(!cls) {
+        throw "Unsupported AgsFeatureAccess version: " + options.version;
+    }
+    return new cls(options);
+};
+
+/**
+ * Constant: OpenLayers.Protocol.WFSTWithLock.DEFAULTS
+ */
+OpenLayers.Protocol.AgsFeatureAccess.DEFAULTS = {
+    "version": "2.0"
+};

Added: sandbox/august/trunk/playground/ags/agsfeatureaccess.html
===================================================================
--- sandbox/august/trunk/playground/ags/agsfeatureaccess.html	                        (rev 0)
+++ sandbox/august/trunk/playground/ags/agsfeatureaccess.html	2010-12-03 06:58:49 UTC (rev 10944)
@@ -0,0 +1,30 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        <title>openlayers vector behavior - wfs</title>
+        <!-- reference ArcGIS JS API -->
+        <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.0/js/dojo/dijit/themes/tundra/tundra.css">
+    	<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.0"></script>
+                  
+        <link rel="stylesheet" href="../../theme/default/style.css" type="text/css"/>               
+        <script src="../../lib/Firebug/firebug.js"></script>
+        <script src="../../lib/OpenLayers.js"></script>
+        <script src="agsfeatureaccess.js"></script>
+        <script type="text/javascript">        
+        	dojo.require("esri.layers.FeatureLayer");
+        	dojo.require("esri.dijit.editing.TemplatePicker-all");
+        	esriConfig.defaults.io.proxyUrl = "../../util/ags-proxy.jsp";
+        	esriConfig.defaults.io.alwaysUseProxy = false;
+        	dojo.addOnLoad(init);
+        </script>               
+        <!--
+        <link rel="stylesheet" href="../../../patched+/theme/default/style.css" type="text/css"/>               
+        <script src="../../../patched+/Firebug/firebug.js"></script>
+        <script src="../../../patched+/OpenLayers.js"></script>
+        <script src="agsfeatureaccess.js"></script>
+        -->
+    </head>
+    <body>        
+        <div id="map" style="width: 1024px; height: 512px; margin-top: 5px; margin-left: 5px; background-color: #ffffff"></div>    		    	
+    	<input id="commit_btn" type="button" value="commit" onclick="commit();"/>
+    </body>
+</html>

Added: sandbox/august/trunk/playground/ags/agsfeatureaccess.js
===================================================================
--- sandbox/august/trunk/playground/ags/agsfeatureaccess.js	                        (rev 0)
+++ sandbox/august/trunk/playground/ags/agsfeatureaccess.js	2010-12-03 06:58:49 UTC (rev 10944)
@@ -0,0 +1,197 @@
+var map;
+var select_control, modify_control, insert_control, delete_control;
+var bbox_strategy, save_strategy;
+var agsFeatureAccessLayer;
+	
+function init() {    
+	
+	
+	// set OpenLayers proxy
+	//OpenLayers.ProxyHost= "/openlayers-trunk/ApacheProxyServlet?url=";
+	
+	OpenLayers.ProxyHost= function(url) {
+		return "/openlayers-trunk/ApacheProxyServlet?url=" + url;
+    };
+    
+	var options = 	{
+		//panMethod: null, // set 'panMethod' to null to disable animated panning
+		controls: [       		
+		    new OpenLayers.Control.LayerSwitcher(),
+		    new OpenLayers.Control.PanZoomBar(),
+       		new OpenLayers.Control.Navigation(),       		
+       		new OpenLayers.Control.MousePosition()
+       	],
+       	projection: "EPSG:900913",
+        units: "m",
+        maxResolution: 156543.0339,
+        numZoomLevels: 20,	// default allowed zoom levels is 16 so change it to 20
+        maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34)        
+   	};
+
+    map = new OpenLayers.Map('map', options);
+	    
+    var base_layer = new OpenLayers.Layer.AgsTiled( 
+		"World Topo Map", 
+		"http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/",
+    	//"World Imagery Map",
+		//"http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/",
+    	{					
+			tileSize: new OpenLayers.Size(256,256),
+			tileFormat:'jpg',
+			tileOrigin: new OpenLayers.LonLat(-20037508.342789, 20037508.342789),
+			tileFullExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
+			isBaseLayer: true,
+			singleTile: false					 					
+		}
+	);     
+    
+    map.addLayer(base_layer);
+    // add feature service from ArcGIS Server
+    // San Francisco
+    //var lon = -122.391667;
+	//var lat = 37.760628;
+    //var zoom = 16;
+    // Kuwait
+    var lon = 48.01436;
+	var lat = 29.11857;
+    var zoom = 12;
+    
+    bbox_strategy = new OpenLayers.Strategy.BBOX();
+    // add "Save" strategy to commit edits to feature layer    
+    save_strategy = new OpenLayers.Strategy.Save({
+    	auto:false
+    });
+    
+    agsFeatureAccessLayer = new OpenLayers.Layer.Vector(
+    	"arcgis server feature service", 
+    	{
+    		strategies: [
+    		    bbox_strategy,
+    		    save_strategy
+    		],
+    		protocol: new OpenLayers.Protocol.AgsFeatureAccess({
+    			//url: "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/MapServer/0",
+    			url: "http://sazabi:8399/arcgis/rest/services/playground/ihs_featureservice_mercator_auxiliary/FeatureServer/0",	// point layer
+    			//url: "http://sazabi:8399/arcgis/rest/services/playground/ihs_featureservice_mercator_auxiliary/FeatureServer/2",	// polygon layer
+    			query: {
+    				outFields: []
+    			},
+    			srsName: map.projection
+    		})    			
+    	}
+    );
+    agsFeatureAccessLayer.protocol.setLayer(agsFeatureAccessLayer);
+    agsFeatureAccessLayer.setVisibility(false);
+    map.addLayer(agsFeatureAccessLayer);    
+    
+    map.setCenter(
+    	new OpenLayers.LonLat(lon,lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()), 
+    	zoom
+    );    
+    
+    //	create, add and activate the SelectFeature control    
+    /*
+    select_control = new OpenLayers.Control.SelectFeature(
+    	agsFeatureAccessLayer,
+    	{
+    		clickout: false,
+    		toggle: true,
+			multiple: true
+    	}
+    );
+    map.addControl(select_control);
+    select_control.activate();
+    */
+    save_strategy.activate();
+    
+    agsFeatureAccessLayer.events.on({
+        //"beforefeaturemodified": report,
+        //"featuremodified": monitoring,
+        //"afterfeaturemodified": monitoring
+        //"vertexmodified": report,
+        //"sketchmodified": report,
+        //"sketchstarted": report,
+        //"sketchcomplete": report
+    });
+    
+    // to modify features create, add and activate a ModifyFeature control
+    
+    modify_control = new OpenLayers.Control.ModifyFeature(
+    	agsFeatureAccessLayer,
+        {
+        	mode: OpenLayers.Control.ModifyFeature.RESHAPE | OpenLayers.Control.ModifyFeature.ROTATE,
+    		clickout: true,		// 
+        	toggle: false	//
+        }
+    );
+    
+    map.addControl(modify_control);
+    modify_control.activate();
+    
+    
+    // to delete features temporarily create, add and activate a ModifyFeatureWithLock control
+    // TODO: create a new delete feature control
+    // extend ModifyFeature control to create a DeleteFeature control on the fly
+    //OpenLayers.Control.ModifyFeature.DELETE = 16;
+    /*
+    OpenLayers.Control.DeleteFeature = OpenLayers.Class(OpenLayers.Control.ModifyFeature, {
+    	deleteFeatureCodes: [81],	// press 'q' key to delete feature on map
+    	//
+    	selectFeature: function(feature) {
+            this.feature = feature;           		
+        },
+        //
+    	handleKeypress: function(evt) {
+	        var code = evt.keyCode;
+			//if(this.mode == OpenLayers.Control.ModifyFeature.DELETE) {
+				if(this.feature &&
+		           OpenLayers.Util.indexOf(this.deleteFeatureCodes, code) != -1) {				
+				   // delete feature at client and change state to "DELETE"				
+				   this.feature.state = OpenLayers.State.DELETE;
+				   this.layer.eraseFeatures([this.feature]);
+				   // remove feature from this.layer.selectedFeatures to avoid feature being drawn again					
+				   if(OpenLayers.Util.indexOf(this.layer.selectedFeatures, this.feature) != -1) {
+				       OpenLayers.Util.removeItem(this.layer.selectedFeatures, this.feature);						
+				   }					
+				   console.log("...delete feature at client side...");
+				   this.layer.events.triggerEvent("featuremodified", 
+                                       {feature: this.feature});				
+				} 
+			//}
+    	},
+    	CLASS_NAME: "OpenLayers.Control.DeleteFeature"
+    });
+    delete_control = new OpenLayers.Control.DeleteFeature(
+        agsFeatureAccessLayer,
+        {
+        	//mode: OpenLayers.Control.ModifyFeature.DELETE,
+    		clickout: true,		// 
+        	toggle: false	//
+        }
+    );  
+    map.addControl(delete_control);
+    delete_control.activate();
+    */
+    // create, add and activate the DrawFeature control
+	/*
+    insert_control = new OpenLayers.Control.DrawFeature(
+		agsFeatureAccessLayer,
+		OpenLayers.Handler.Point,		
+		{
+			//handlerOptions: {} 
+		}
+	);
+	map.addControl(insert_control);
+    insert_control.activate();
+    */
+}
+
+function commit() {	
+	save_strategy.save(null);
+}
+
+function monitoring(evt) {
+	OpenLayers.Console.debug(evt.type);
+	OpenLayers.Console.debug(evt.feature.id);
+	//OpenLayers.Console.debug(evt.feature.status);    
+}
\ No newline at end of file

Added: sandbox/august/trunk/tests/Format/AgsJsAdapter_Renderer.html
===================================================================
--- sandbox/august/trunk/tests/Format/AgsJsAdapter_Renderer.html	                        (rev 0)
+++ sandbox/august/trunk/tests/Format/AgsJsAdapter_Renderer.html	2010-12-03 06:58:49 UTC (rev 10944)
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+	<head>
+	    <!--  
+	    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/1.0/js/dojo/dijit/themes/tundra/tundra.css">
+	    <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=1"></script>    
+		<link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/1.1/js/dojo/dijit/themes/tundra/tundra.css">
+    	<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=1.1"></script>	    
+		<link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/1.4/js/dojo/dijit/themes/tundra/tundra.css">
+    	<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=1.4"></script>				
+		<link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/1.6/js/dojo/dijit/themes/tundra/tundra.css">
+    	<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=1.6"></script>						
+		-->		 
+		<link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.0/js/dojo/dijit/themes/tundra/tundra.css">
+    	<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.0"></script>
+    	<!--  
+    		Manually reference FeatureLayer.xd.js and iframe.xd.js which are required for support FeatureLayer in AGS JS API
+    		  You must explicitly reference those two js files here because JS API loads them dynamically when dojo.addOnLoad() is called, which
+    		  doesn't work quite friendly with TestAnotherWay
+    	-->
+    	<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/2.0/js/esri/layers/FeatureLayer.xd.js"></script>
+    	<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/2.0/js/dojo/dojo/io/iframe.xd.js"></script>
+    	    	
+	    <script type="text/javascript" src="../../lib/OpenLayers.js"></script>	    
+	    <script type="text/javascript" src="AgsJsAdapter_Renderer.js"></script>
+	    <!--
+	    <script type="text/javascript">
+	    	dojo.require("esri.map");
+      		dojo.require("esri.layers.FeatureLayer");      		     		
+	    </script>
+	    -->
+	</head>
+	<body>
+	    <div id="map" style="width:400px;height:250px;"/>
+	</body>
+</html>

Added: sandbox/august/trunk/tests/Format/AgsJsAdapter_Renderer.js
===================================================================
--- sandbox/august/trunk/tests/Format/AgsJsAdapter_Renderer.js	                        (rev 0)
+++ sandbox/august/trunk/tests/Format/AgsJsAdapter_Renderer.js	2010-12-03 06:58:49 UTC (rev 10944)
@@ -0,0 +1,514 @@
+var adapter = null;
+var _error = -99;
+
+function setUp() {
+	adapter = new OpenLayers.Format.AgsJsAdapter();
+}
+
+function tearDown() {
+	adapter = null;
+}
+
+//simple renderer example: http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Earthquakes/EarthquakesFromLastSevenDays/MapServer/0
+function test_Format_AgsJsAdapter_parseAgsRenderer_SimpleRenderer(t) {
+	//setUp();
+	t.plan(7);
+	
+	var featureLayer = new esri.layers.FeatureLayer(
+		"http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Earthquakes/EarthquakesFromLastSevenDays/MapServer/0",
+		{mode: esri.layers.FeatureLayer.MODE_SELECTION}
+	);
+	window.setTimeout(
+		function() {
+			var adapter_spec = new OpenLayers.Format.AgsJsAdapter();
+			var agsSimpleRenderer = featureLayer.renderer;
+			agsSimpleRenderer.label = "agsSimpleRenderer.label";
+			agsSimpleRenderer.description = "agsSimpleRenderer.description";
+			var olStyle = adapter_spec.parseAgsRenderer['SimpleRenderer'].apply(adapter_spec,[agsSimpleRenderer]);
+			
+			t.ok((olStyle instanceof OpenLayers.Style), "...parseAgsRenderer.SimpleRenderer returns instance of OpenLayers.Style...");
+			t.eq(olStyle.name, "SimpleRendererStyle", "...parses olStyle name...");
+			t.eq(olStyle.title, "SimpleRenderer Style", "...parses olStyle title...");
+			t.eq(olStyle.description, "An OpenLayers Style converted from an esri SimpleRenderer", "...parses olStyle description...");
+			
+			t.eq(olStyle.rules.length, 1, "...parses SimpleRender as an one rule style...");
+			t.ok((olStyle.rules[0] instanceof OpenLayers.Rule), "...olStyle.rule is an instance of OpenLayers.Rule...");
+			t.ok((olStyle.rules[0].symbolizer instanceof OpenLayers.Symbolizer), "...olStyle.rule.symbolizer is an instance of OpenLayers.Symbolizer.*...");
+		},
+		1000
+	);
+	t.wait_result(3);
+	//tearDown();
+}
+
+function test_Format_AgsJsAdapter_parseAgsRenderer_ClassBreaksRenderer(t) {
+	setUp();
+	t.plan(40);
+	
+	var defaultSymbol = new esri.symbol.SimpleFillSymbol();
+	var agsClassBreaksRenderer = new esri.renderer.ClassBreaksRenderer(defaultSymbol, "POP07_SQMI");
+	
+	agsClassBreaksRenderer.addBreak({
+		minValue: 0,
+		maxValue: 9,
+		symbol: new esri.symbol.SimpleMarkerSymbol(),
+		label: "break0_label",
+		description: "break0_description"
+	});
+	
+	agsClassBreaksRenderer.addBreak({
+		minValue: 10,
+		maxValue: 19,
+		symbol: new esri.symbol.SimpleFillSymbol(),
+		label: "break1_label",
+		description: "break1_description"
+	});
+
+	agsClassBreaksRenderer.addBreak({
+		minValue: 20,
+		maxValue: 29,
+		symbol: new esri.symbol.SimpleLineSymbol(),
+		label: "break2_label",
+		description: "break2_description"
+	});
+	
+	var olStyle = adapter.parseAgsRenderer['ClassBreaksRenderer'].apply(adapter,[agsClassBreaksRenderer]);
+	t.ok((olStyle instanceof OpenLayers.Style), "...parseAgsRenderer.ClassBreaksRenderer returns instance of OpenLayers.Style...");
+	t.eq(olStyle.name, "ClassBreaksRendererStyle", "...parses olStyle name...");
+	t.eq(olStyle.title, "ClassBreaksRenderer Style", "...parses olStyle title...");
+	t.eq(olStyle.description, "An OpenLayers Style converted from an esri ClassBreaksRenderer", "...parses olStyle description...");
+		
+	var olRule0 = olStyle.rules[0];
+	t.ok((olRule0 instanceof OpenLayers.Rule), "...olStyle.rule is an instance of OpenLayers.Rule...");
+	t.ok((olRule0.symbolizer instanceof OpenLayers.Symbolizer.Point), "...olStyle.rule is an instance of OpenLayers.Symbolizer.*...");
+	t.eq(olRule0.name, "break0_label", "...parse info.label and set to rule.name...");
+	t.eq(olRule0.title, "break0_label", "...parse info.label and set to rule.title...");
+	t.eq(olRule0.description, "break0_description", "...parse info.label and set to rule.description...");
+	t.ok((olRule0.filter instanceof OpenLayers.Filter.Comparison), "...olStyle.rule.filter is an instance of OpenLayers.Filter.Comparison...");
+	t.eq(olRule0.filter.type, OpenLayers.Filter.Comparison.BETWEEN, "...olStyle.rule.filter.type is OpenLayers.Filter.Comparison.BETWEEN...");
+	t.eq(olRule0.filter.property, "POP07_SQMI", "...parse attributeField and set to olStyle.rule.filter.property...");
+	t.eq(olRule0.filter.lowerBoundary, 0, "...parse minValue and set to olStyle.rule.filter.lowerBoundary...");
+	t.eq(olRule0.filter.upperBoundary, 9, "...parse maxValue and set to olStyle.rule.filter.upperBoundary...");
+	
+	var olRule1 = olStyle.rules[1];
+	t.ok((olRule1 instanceof OpenLayers.Rule), "...olStyle.rule is an instance of OpenLayers.Rule...");
+	t.ok((olRule1.symbolizer instanceof OpenLayers.Symbolizer.Polygon), "...olStyle.rule is an instance of OpenLayers.Symbolizer.*...");
+	t.eq(olRule1.name, "break1_label", "...parse info.label and set to rule.name...");
+	t.eq(olRule1.title, "break1_label", "...parse info.label and set to rule.title...");
+	t.eq(olRule1.description, "break1_description", "...parse info.label and set to rule.description...");
+	t.ok((olRule1.filter instanceof OpenLayers.Filter.Comparison), "...olStyle.rule.filter is an instance of OpenLayers.Filter.Comparison...");
+	t.eq(olRule1.filter.type, OpenLayers.Filter.Comparison.BETWEEN, "...olStyle.rule.filter.type is OpenLayers.Filter.Comparison.BETWEEN...");
+	t.eq(olRule1.filter.property, "POP07_SQMI", "...parse attributeField and set to olStyle.rule.filter.property...");
+	t.eq(olRule1.filter.lowerBoundary, 10, "...parse minValue and set to olStyle.rule.filter.lowerBoundary...");
+	t.eq(olRule1.filter.upperBoundary, 19, "...parse maxValue and set to olStyle.rule.filter.upperBoundary...");
+	
+	var olRule2 = olStyle.rules[2];
+	t.ok((olRule2 instanceof OpenLayers.Rule), "...olStyle.rule is an instance of OpenLayers.Rule...");
+	t.ok((olRule2.symbolizer instanceof OpenLayers.Symbolizer.Line), "...olStyle.rule is an instance of OpenLayers.Symbolizer.*...");
+	t.eq(olRule2.name, "break2_label", "...parse info.label and set to rule.name...");
+	t.eq(olRule2.title, "break2_label", "...parse info.label and set to rule.title...");
+	t.eq(olRule2.description, "break2_description", "...parse info.label and set to rule.description...");
+	t.ok((olRule2.filter instanceof OpenLayers.Filter.Comparison), "...olStyle.rule.filter is an instance of OpenLayers.Filter.Comparison...");
+	t.eq(olRule2.filter.type, OpenLayers.Filter.Comparison.BETWEEN, "...olStyle.rule.filter.type is OpenLayers.Filter.Comparison.BETWEEN...");
+	t.eq(olRule2.filter.property, "POP07_SQMI", "...parse attributeField and set to olStyle.rule.filter.property...");
+	t.eq(olRule2.filter.lowerBoundary, 20, "...parse minValue and set to olStyle.rule.filter.lowerBoundary...");
+	t.eq(olRule2.filter.upperBoundary, 29, "...parse maxValue and set to olStyle.rule.filter.upperBoundary...");
+	
+	var defaultOLRule = olStyle.rules[3];
+	t.ok((defaultOLRule instanceof OpenLayers.Rule), "...olStyle.rule is an instance of OpenLayers.Rule...");
+	t.ok((defaultOLRule.symbolizer instanceof OpenLayers.Symbolizer.Polygon), "...olStyle.rule is an instance of OpenLayers.Symbolizer.*...");
+	t.eq(defaultOLRule.name, "defaultRuleName", "...parse info.label and set to rule.name...");
+	t.eq(defaultOLRule.title, "default rule title", "...parse info.label and set to rule.title...");
+	t.eq(defaultOLRule.description, "default rule description", "...parse info.label and set to rule.description...");	
+	t.eq(defaultOLRule.elseFilter, true, "...olStyle.rule.filter.type is OpenLayers.Filter.Comparison.BETWEEN...");	
+	
+	tearDown();
+}
+
+// unique value renderer example: http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Hydrography/Watershed173811/FeatureServer//1
+/**
+ * 
+ * @param t
+ * @return
+ */
+function test_Format_AgsJsAdapter_parseAgsRenderer_UniqueValueRenderer(t) {
+	setUp();
+	t.plan(37);
+	
+	var defaultSymbol = new esri.symbol.SimpleFillSymbol();
+	var agsUniqueValueRenderer = new esri.renderer.UniqueValueRenderer(defaultSymbol, "POP07_SQMI");
+	
+	agsUniqueValueRenderer.addValue({
+		value: 0,		
+		symbol: new esri.symbol.SimpleMarkerSymbol(),
+		label: "value0_label",
+		description: "value0_description"
+	});
+	
+	agsUniqueValueRenderer.addValue({
+		value: 1,		
+		symbol: new esri.symbol.SimpleLineSymbol(),
+		label: "value1_label",
+		description: "value1_description"
+	});
+	
+	agsUniqueValueRenderer.addValue({
+		value: 2,		
+		symbol: new esri.symbol.SimpleFillSymbol(),
+		label: "value2_label",
+		description: "value2_description"
+	});
+	
+	var olStyle = adapter.parseAgsRenderer['UniqueValueRenderer'].apply(adapter,[agsUniqueValueRenderer]);
+	t.ok((olStyle instanceof OpenLayers.Style), "...parseAgsRenderer.UniqueValueRenderer returns instance of OpenLayers.Style...");
+	t.eq(olStyle.name, "UniqueValueRendererStyle", "...parses olStyle name...");
+	t.eq(olStyle.title, "UniqueValueRenderer Style", "...parses olStyle title...");
+	t.eq(olStyle.description, "An OpenLayers Style converted from an esri UniqueValueRenderer", "...parses olStyle description...");
+		
+	var olRule0 = olStyle.rules[0];
+	t.ok((olRule0 instanceof OpenLayers.Rule), "...olStyle.rule is an instance of OpenLayers.Rule...");
+	t.ok((olRule0.symbolizer instanceof OpenLayers.Symbolizer.Point), "...olStyle.rule is an instance of OpenLayers.Symbolizer.*...");
+	t.eq(olRule0.name, "value0_label", "...parse info.label and set to rule.name...");
+	t.eq(olRule0.title, "value0_label", "...parse info.label and set to rule.title...");
+	t.eq(olRule0.description, "value0_description", "...parse info.label and set to rule.description...");
+	t.ok((olRule0.filter instanceof OpenLayers.Filter.Comparison), "...olStyle.rule.filter is an instance of OpenLayers.Filter.Comparison...");
+	t.eq(olRule0.filter.type, OpenLayers.Filter.Comparison.EQUAL_TO, "...olStyle.rule.filter.type is OpenLayers.Filter.Comparison.EQUAL_TO...");
+	t.eq(olRule0.filter.property, "POP07_SQMI", "...parse attributeField and set to olStyle.rule.filter.property...");
+	t.eq(olRule0.filter.value, 0, "...parse value and set to olStyle.rule.filter.value...");	
+	
+	var olRule1 = olStyle.rules[1];
+	t.ok((olRule1 instanceof OpenLayers.Rule), "...olStyle.rule is an instance of OpenLayers.Rule...");
+	t.ok((olRule1.symbolizer instanceof OpenLayers.Symbolizer.Line), "...olStyle.rule is an instance of OpenLayers.Symbolizer.*...");
+	t.eq(olRule1.name, "value1_label", "...parse info.label and set to rule.name...");
+	t.eq(olRule1.title, "value1_label", "...parse info.label and set to rule.title...");
+	t.eq(olRule1.description, "value1_description", "...parse info.label and set to rule.description...");
+	t.ok((olRule1.filter instanceof OpenLayers.Filter.Comparison), "...olStyle.rule.filter is an instance of OpenLayers.Filter.Comparison...");
+	t.eq(olRule1.filter.type, OpenLayers.Filter.Comparison.EQUAL_TO, "...olStyle.rule.filter.type is OpenLayers.Filter.Comparison.EQUAL_TO...");
+	t.eq(olRule1.filter.property, "POP07_SQMI", "...parse attributeField and set to olStyle.rule.filter.property...");
+	t.eq(olRule1.filter.value, 1, "...parse value and set to olStyle.rule.filter.value...");
+	
+	var olRule2 = olStyle.rules[2];
+	t.ok((olRule2 instanceof OpenLayers.Rule), "...olStyle.rule is an instance of OpenLayers.Rule...");
+	t.ok((olRule2.symbolizer instanceof OpenLayers.Symbolizer.Polygon), "...olStyle.rule is an instance of OpenLayers.Symbolizer.*...");
+	t.eq(olRule2.name, "value2_label", "...parse info.label and set to rule.name...");
+	t.eq(olRule2.title, "value2_label", "...parse info.label and set to rule.title...");
+	t.eq(olRule2.description, "value2_description", "...parse info.label and set to rule.description...");
+	t.ok((olRule2.filter instanceof OpenLayers.Filter.Comparison), "...olStyle.rule.filter is an instance of OpenLayers.Filter.Comparison...");
+	t.eq(olRule2.filter.type, OpenLayers.Filter.Comparison.EQUAL_TO, "...olStyle.rule.filter.type is OpenLayers.Filter.Comparison.BETWEEN...");
+	t.eq(olRule2.filter.property, "POP07_SQMI", "...parse attributeField and set to olStyle.rule.filter.property...");
+	t.eq(olRule2.filter.value, 2, "...parse minValue and set to olStyle.rule.filter.value...");
+	
+	var defaultOLRule = olStyle.rules[3];
+	t.ok((defaultOLRule instanceof OpenLayers.Rule), "...olStyle.rule is an instance of OpenLayers.Rule...");
+	t.ok((defaultOLRule.symbolizer instanceof OpenLayers.Symbolizer.Polygon), "...olStyle.rule is an instance of OpenLayers.Symbolizer.*...");
+	t.eq(defaultOLRule.name, "defaultRuleName", "...parse info.label and set to rule.name...");
+	t.eq(defaultOLRule.title, "default rule title", "...parse info.label and set to rule.title...");
+	t.eq(defaultOLRule.description, "default rule description", "...parse info.label and set to rule.description...");	
+	t.eq(defaultOLRule.elseFilter, true, "...olStyle.rule.filter.type is OpenLayers.Filter.Comparison.BETWEEN...");	
+	
+	/*
+	// this example feature layer has a uniquevValueRenderer that has 7 different symbols for those 7 unique values
+	var featureLayer = new esri.layers.FeatureLayer(
+		"http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/MapServer/0",
+		{mode: esri.layers.FeatureLayer.MODE_SELECTION}
+	);
+	window.setTimeout(
+		function() {
+			var adapter_spec = new OpenLayers.Format.AgsJsAdapter();
+			var agsUniqueValueRenderer = featureLayer.renderer;
+			agsUniqueValueRenderer.label = "agsUniqueValueRenderer.label";
+			agsUniqueValueRenderer.description = "agsUniqueValueRenderer.description";
+			var olStyle = adapter_spec.parseAgsRenderer['UniqueValueRenderer'].apply(adapter_spec, [agsUniqueValueRenderer]);
+			
+			t.ok((olStyle instanceof OpenLayers.Style), "...parseAgsRenderer.UniqueValueRenderer returns instance of OpenLayers.Style...");
+			t.eq(olStyle.name, "UniqueValueRendererStyle", "...parses olStyle name...");
+			t.eq(olStyle.title, "UniqueValueRenderer Style", "...parses olStyle title...");
+			t.eq(olStyle.description, "An OpenLayers Style converted from an esri UniqueValueRenderer", "...parses olStyle description...");
+			
+			t.eq(olStyle.rules.length, 7, "...parses UniqueValueRenderer as a multi-rule style...");
+			
+			for(var i=0; i<olStyle.rules.length; i++) {
+				t.ok((olStyle.rules[i] instanceof OpenLayers.Rule), "...olStyle.rule is an instance of OpenLayers.Rule...");
+				t.ok((olStyle.rules[i].symbolizer instanceof OpenLayers.Symbolizer.Point), "...olStyle.rule is an instance of OpenLayers.Symbolizer.*...");
+				// TODO: test if filter is parsed correctly
+			}
+		},
+		1000
+	);
+	t.wait_result(3);
+	*/
+	
+	tearDown();
+}
+
+/**
+ * 
+ * @param t
+ * @return
+ */
+function test_Format_AgsJsAdapter_parseAgsSymbol_SimpleMarkerSymbol(t) {
+	//
+	setUp();
+	t.plan(10);	
+    var agsSimpleMarkerSymbol = new esri.symbol.SimpleMarkerSymbol(
+    	"STYLE_CIRCLE", 
+    	8,
+    	new esri.symbol.SimpleLineSymbol(
+			"STYLE_DASHDOT",
+			null, // set null for default color (0,0,0,1) 
+			2
+		),
+    	null // set null for default color (0,0,0,1)
+    );
+	//
+	//var adapter = new OpenLayers.Format.AgsJsAdapter();
+	var olSymbolizer = adapter.parseAgsSymbol['SimpleMarkerSymbol'].apply(adapter, [agsSimpleMarkerSymbol]);
+	t.ok((olSymbolizer instanceof OpenLayers.Symbolizer.Point), "...parseAgsSymbol.SimpleMarkerSymbol returns instance of OpenLayers.Symbolizer.Point...");
+	t.eq(olSymbolizer.pointRadius, 8, "...parse symbol 'size' and set to pointRadius...");
+	t.eq(olSymbolizer.fillColor, "#000000", "...parse 'color' and set to fillColor...");
+	t.eq(olSymbolizer.fillOpacity, 1, "...parse'color' and set to fillOpacity...");
+	
+	t.eq(olSymbolizer.strokeDashstyle, "dashdot", "...parse 'strokeDashstyle' and set to strokeDashstyle...");
+	t.eq(olSymbolizer.strokeWidth, 2, "...parse 'strokeWidth' and set to strokeWidth...");
+	t.eq(olSymbolizer.strokeColor, "#000000", "...parse 'strokeColor' and set to strokeColor...");
+	t.eq(olSymbolizer.strokeOpacity, 1, "...parse 'strokeOpacity' and set to strokeOpacity...");
+	
+	t.eq(olSymbolizer.graphicName, "circle", "...parse 'style' and set to graphicName...");
+	
+	try {
+		var olSymbolizer2 = adapter.parseAgsSymbol['SimpleMarkerSymbol'].apply(adapter, [{'name':"name", 'value':"value"}]);
+	} catch(e) {
+		t.ok(true, "...throws exception if input is invalid esri.symbol.SimpleMarkerSymbol...");
+	}
+	tearDown();
+}
+
+/**
+ * 
+ * @param t
+ * @return
+ */
+function test_Format_AgsJsAdapter_parseAgsSymbol_PictureMarkerSymbol(t) {
+	t.plan(9);
+	// this example feature layer has a uniquevValueRenderer that has 7 different symbols for those 7 unique values
+	var featureLayer = new esri.layers.FeatureLayer(
+		"http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/MapServer/0",
+		{mode: esri.layers.FeatureLayer.MODE_SELECTION}
+	);
+	window.setTimeout(
+		function() {
+			var adapter_spec = new OpenLayers.Format.AgsJsAdapter();
+			var agsPictureMarkerSymbol = featureLayer.renderer.infos[0].symbol;
+			// hard code some attributes of agsPictureMarkerSymbol
+			agsPictureMarkerSymbol.size = 10;
+			agsPictureMarkerSymbol.width = 32;
+			agsPictureMarkerSymbol.height = 16;
+			agsPictureMarkerSymbol.xoffset = -1;
+			agsPictureMarkerSymbol.yoffset = -5;
+			agsPictureMarkerSymbol.angle = 30;
+			
+			var olSymbolizer = adapter_spec.parseAgsSymbol['PictureMarkerSymbol'].apply(adapter_spec, [agsPictureMarkerSymbol]);	
+			t.ok((olSymbolizer instanceof OpenLayers.Symbolizer.Point), "...parseAgsSymbol.PictureMarkerSymbol returns instance of OpenLayers.Symbolizer.Point...");
+			t.eq(olSymbolizer.pointRadius, 10, "...parse symbol 'size' and set to pointRadius...");
+			t.eq(olSymbolizer.externalGraphic, "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAAXNSR0IB2cksfwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAsVJREFUSInt001IVFEUwPH/a2bewwyCCZEZMI2gBoRKSdtEROBKooyiDwqt8QNpYQmjYuIHDZGOVDM5RJAwUvRBizYFLmrXoo+F0iKklROkSOQmyrnqvNNinLHRmdcY5Kqzuvfde8/vnnN5dtYp7P+hlbFnp0uq9isCw7PaP4Oqq1zy/PY0KGDRKYGR7NhfQ2mIgoGGWSq3O+VEd2bsT5AYGChU2uHqKpcUbJpG80CkB2qrwFQGx/b+4EmnU05eW41ZQTIz85XCwoKMlWgeSK6fO2AkKpuHmt3w+LJLTt2cTsMsK6qpOYJhGCilAPA1OmWgdaldgGmaicESElf5yDwcLYVHTS45fXcZywqJCObDLchCPqZyiqNxKrW2EHKjBiBUv5Xz3nqYv59CRBlIDDpG9bR8lhVtOPON+B03xED1uzHaE5hs3oX5+QO+F4rGJgfPXsPh3cuIJ6ATjUZzap0kB7bmKeLX3cg8zHWVkOefRK8dZa6rBACHXef4oCJ2z5kVsaxI9boxehMV6B1TxDrdSAzUAx/G2QB5/knqvlxAz0u0yArJCpU6DUwFP1tK2BicBMD8rsMCLLx6inE2AMC2bdsJBm9Qd96LJ/AyK5IVevbmI83XrjISiWiENCkuLiYajS5viKTnKyoqskSyQWKacUYikdQHb0MT3V2dABogExOf8Hh2pOYOXYfEu66tolAo+PtUc9hsAtDX55eeni7iS/9PX59fABw2m1Ux2aFweIhweCh5SwA6OtoA6O6+kkRS+212x9ohEcm0Ly3Gx8fT5m2+Vm4Fw1xquZg7lEuUlZXB8nsIgK4blmdWQjI2Nk55
 eVoiAIaHR8TrreXgwUMrc2iA6Lo9ieb2Hy3GM7fO663VABkIDFJZUb4Kq/fWZTyXEervDyAST95yVbx9995yPWeovd1nmWBfZcWagYzQv4x1g34BI70ZygdCoCgAAAAASUVORK5CYII=", "...parse symbol 'url' for Linux/Unix...");
+			t.eq(olSymbolizer.graphicWidth, 32, "...parse symbol 'width' and set to 'graphicWidth'...");
+			t.eq(olSymbolizer.graphicHeight, 16, "...parse symbol 'height' and set to 'graphicheight'...");
+			
+			t.eq(olSymbolizer.graphicXOffset, -1, "...parse symbol 'graphicXOffset' and set to 'graphicXOffset'...");
+			t.eq(olSymbolizer.graphicYOffset, -5, "...parse symbol 'graphicYOffset' and set to 'graphicYOffset'...");
+			
+			t.eq(olSymbolizer.rotation, 30, "...parse symbol 'angle' and set to 'rotation'...");
+			
+			try {
+				var olSymbolizer2 = adapter.parseAgsSymbol['PictureMarkerSymbol'].apply(adapter, [{'name':"name", 'value':"value"}]);
+			} catch(e) {
+				t.ok(true, "...throws exception if input is invalid esri.symbol.PictureMarkerSymbol...");
+			}
+		},
+		1000
+	);
+	t.wait_result(3);
+}
+
+/**
+ * 
+ * @param t
+ * @return
+ */
+function test_Format_AaJsAdapter_parseAgsSymbol_SimpleLineSymbol(t) {	
+	setUp();
+	t.plan(6);	
+    var agsSimpleLineSymbol = new esri.symbol.SimpleLineSymbol(
+    	"STYLE_DASH", 
+    	null, // set null for default color (0,0,0,1)
+    	2
+    );	
+    //var adapter = new OpenLayers.Format.AgsJsAdapter();
+    var olSymbolizer = adapter.parseAgsSymbol['SimpleLineSymbol'].apply(adapter, [agsSimpleLineSymbol]);
+	
+    t.ok((olSymbolizer instanceof OpenLayers.Symbolizer.Line), "...parseAgsSymbol.SimpleLineSymbol returns instance of OpenLayers.Symbolizer.Line...");
+	t.eq(olSymbolizer.strokeDashstyle, "dash", "...parse 'strokeDashstyle' and set to strokeDashstyle...");
+	t.eq(olSymbolizer.strokeWidth, 2, "...parse 'strokeWidth' and set to strokeWidth...");
+	t.eq(olSymbolizer.strokeColor, "#000000", "...parse 'strokeColor' and set to strokeColor...");
+	t.eq(olSymbolizer.strokeOpacity, 1, "...parse 'strokeOpacity' and set to strokeColor...");
+		
+	try {
+		var olSymbolizer2 = adapter.parseAgsSymbol['SimpleLineSymbol'].apply(adapter, [{'name':"name", 'value':"value"}]);
+	} catch(e) {
+		t.ok(true, "...throws exception if input is invalid esri.symbol.SimpleLineSymbol...");
+	}	
+	tearDown();
+}
+
+/**
+ * 
+ * @param t
+ * @return
+ */
+function test_Format_AaJsAdapter_parseAgsSymbol_CartographicLineSymbol(t) {	
+	setUp();
+	t.plan(1);
+	// TODO: add real test cases when CartographicLineSymbol is supported in OpenLayers
+	try {
+		var olSymbolizer2 = adapter.parseAgsSymbol['CartographicLineSymbol'].apply(adapter, [{'name':"name", 'value':"value"}]);
+	} catch(e) {
+		t.ok(true, "...throws exception if input is invalid esri.symbol.CartographicLineSymbol...");
+	}
+	tearDown();
+}
+
+/**
+ * 
+ * @param t
+ * @return
+ */
+function test_Format_AGSJSAdapter_parseAgsSymbol_SimpleFillSymbol(t) {
+	setUp();
+	t.plan(8);
+    var agsSimpleFillSymbol = new esri.symbol.SimpleFillSymbol(
+    	"STYLE_SOLID", 
+    	new esri.symbol.SimpleLineSymbol(
+			"STYLE_DASHDOT",
+			null, // set null for default color (0,0,0,1) 
+			2
+		),
+    	new dojo.Color([255,255,255]) // set null for default color (0,0,0,1)
+    );
+    //var adapter = new OpenLayers.Format.AgsJsAdapter();
+	var olSymbolizer = adapter.parseAgsSymbol['SimpleFillSymbol'].apply(adapter, [agsSimpleFillSymbol]);
+	t.ok((olSymbolizer instanceof OpenLayers.Symbolizer.Polygon), "...parseAgsSymbol.SimpleFillSymbol returns instance of OpenLayers.Symbolizer.Polygon...");
+	t.eq(olSymbolizer.fillColor, "#ffffff", "...parse 'color' and set to fillColor...");
+	t.eq(olSymbolizer.fillOpacity, 1, "...parse'color' and set to fillOpacity...");
+	
+	t.eq(olSymbolizer.strokeDashstyle, "dashdot", "...parse 'strokeDashstyle' and set to strokeDashstyle...");
+	t.eq(olSymbolizer.strokeWidth, 2, "...parse 'strokeWidth' and set to strokeWidth...");
+	t.eq(olSymbolizer.strokeColor, "#000000", "...parse 'strokeColor' and set to strokeColor...");
+	t.eq(olSymbolizer.strokeOpacity, 1, "...parse 'strokeOpacity' and set to strokeOpacity...");
+	
+	try {
+		var olSymbolizer2 = adapter.parseAgsSymbol['SimpleFillSymbol'].apply(adapter, [{'name':"name", 'value':"value"}]);
+	} catch(e) {
+		t.ok(true, "...throws exception if input is invalid esri.symbol.SimpleFillSymbol...");
+	}
+	tearDown();
+}
+
+/**
+ * 
+ * @param t
+ * @return
+ */
+function test_Format_AaJsAdapter_parseAgsSymbol_PictureFillSymbol(t) {	
+	setUp();
+	t.plan(1);
+	// TODO: add real test cases when PictureFillSymbol is supported in OpenLayers
+	try {
+		var olSymbolizer2 = adapter.parseAgsSymbol['PictureFillSymbol'].apply(adapter, [{'name':"name", 'value':"value"}]);
+	} catch(e) {
+		t.ok(true, "...throws exception if input is invalid esri.symbol.PictureFillSymbol...");
+	}
+	tearDown();
+}
+
+/**
+ * 
+ * @param t
+ * @return
+ */
+function test_Format_AaJsAdapter_parseAgsSymbol_TextSymbol(t) {	
+	setUp();
+	t.plan(8);
+	
+	var agsTextSymbol =  new esri.symbol.TextSymbol("agsTextSymbol");
+	agsTextSymbol.setColor(new dojo.Color([128,0,0]));
+	agsTextSymbol.setAlign(esri.symbol.Font.ALIGN_START);
+	agsTextSymbol.setAngle(45);
+	var agsFont = new esri.symbol.Font();
+	agsFont.setSize("12pt");
+	agsFont.setFamily("Serif");
+	agsFont.setStyle("STYLE_ITALIC");
+	agsFont.setWeight(esri.symbol.Font.WEIGHT_BOLD);
+	agsTextSymbol.setFont(agsFont);	
+	//var adapter = new OpenLayers.Format.AgsJsAdapter();
+	var olSymbolizer = adapter.parseAgsSymbol['TextSymbol'].apply(adapter, [agsTextSymbol]);
+	t.ok((olSymbolizer instanceof OpenLayers.Symbolizer.Text), "...parseAgsSymbol.TextSymbol returns instance of OpenLayers.Symbolizer.Text...");
+	
+	t.eq(olSymbolizer.label, "agsTextSymbol", "...parse 'text' and set to label...");
+	t.eq(olSymbolizer.fontFamily, "Serif", "...parse 'font.family' and set to fontFamily...");
+	t.eq(olSymbolizer.fontSize, "12pt", "...parse 'font.size' and set to fontSize...");
+	t.eq(olSymbolizer.fontWeight, "bold", "...parse 'font.weight' and set to fontWeight...");
+	t.eq(olSymbolizer.fontStyle, "STYLE_ITALIC", "...parse 'font.style' and set to fontStyle...");
+	t.eq(olSymbolizer.color, "#800000", "...parse 'color' and set to color...");
+	
+	try {
+		var olSymbolizer2 = adapter.parseAgsSymbol['TextSymbol'].apply(adapter, [{'name':"name", 'value':"value"}]);
+	} catch(e) {
+		t.ok(true, "...throws exception if input is invalid esri.symbol.TextSymbol...");
+	}
+	tearDown();
+}
+
+/**
+ * @param t
+ * @return
+ */
+function test_Format_AaJsAdapter_parseAgsFeatureTemplate(t) {	
+	setUp();
+	t.plan(3);
+	
+	var findTask = new esri.tasks.FindTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer/");
+    findParams = new esri.tasks.FindParameters();
+    findParams.layerIds = [0];
+    findParams.searchFields = ["CITY_NAME"];
+    findParams.returnGeometry = true;
+    
+    findParams.searchText = "Los Angeles";
+    findTask.execute(
+    	findParams, 
+    	function(findResults) {
+    		var adapter = new OpenLayers.Format.AgsJsAdapter({});
+    		var agsGraphic = findResults[0].feature;    		    	
+    		var agsFeatureTemplate = {
+    			name: "template_name",
+    			description: "template_description",
+    			prototype: agsGraphic
+    		};
+    		var olFeatureTemplate = adapter.parseAgsFeatureTemplate.apply(adapter, [agsFeatureTemplate]);  
+    		t.eq(olFeatureTemplate.name, "template_name", "...feature template name is parsed and set to name...");
+    		t.eq(olFeatureTemplate.description, "template_description", "...feature template description is parsed and set to description...");
+    		t.ok(olFeatureTemplate.prototype instanceof OpenLayers.Feature.Vector, "...feature template prototype is an instance of OpenLayers.Feature.Vector...")
+    	}
+    );
+    t.wait_result(3);	
+	
+	tearDown();
+}
+
+// TODO: add test for parseAgsFeatureType
+// TODO: add test for parseAgsFeatureTypes
+// TODO: add test for parseNoGeometryAgsGraphic
+// TODO: add test for parseNoGeometryAgsGraphics
+
+
+
+



More information about the Commits mailing list