 		/**
 		 * @return true if data was loaded from cache
 		 */
-		private static function loadCache(source:WeaveAnalystDataSource):Boolean
-		{
-			var currentState:Object = getSessionState(source);
-			var sourceName:String = WeaveAPI.globalHashMap.getName(source);
+		private function loadCache():Boolean
+		{
+			var currentState:Object = getSessionState(this);
+			var sourceName:String = WeaveAPI.globalHashMap.getName(this);
 			if (cache && cache[sourceName])
 			{
 				if (WeaveAPI.SessionManager.computeDiff(currentState, cache[sourceName][CACHE_STATE]) === undefined)
 				{
-					setSessionState(source.outputCSV, cache[sourceName][CACHE_OUTPUT_STATE]);
+					setSessionState(this.outputCSV, cache[sourceName][CACHE_OUTPUT_STATE]);
 					return true;
 				}
 			}
 			return false;
 		}
-		private static function saveCache(source:WeaveAnalystDataSource):void
-		{
-			var name:String = WeaveAPI.globalHashMap.getName(source);
+		private function saveCache():void
+		{
+			// don't cache if something is still in progress
+			if (linkableObjectIsBusy(this))
+				return;
+			
+			var newCacheValue:Object = null;
+			// if there is no output data, cache value should be removed
+			if (outputCSV.csvData.getSessionState() != null)
+			{
+				newCacheValue = {};
+				newCacheValue[CACHE_STATE] = getSessionState(this);
+				newCacheValue[CACHE_OUTPUT_STATE] = getSessionState(this.outputCSV);
+			}
+			
 			if (!cache)
 				cache = {};
-			cache[name] = {};
-			cache[name][CACHE_STATE] = getSessionState(source);
-			cache[name][CACHE_OUTPUT_STATE] = getSessionState(source.outputCSV);
-			var bytes:ByteArray = new ByteArray();
-			bytes.writeObject(cache);
-			WeaveAPI.URLRequestUtils.saveLocalFile(CACHE_FILE_NAME, bytes);
+			var name:String = WeaveAPI.globalHashMap.getName(this);
+			// only update cache if something changed
+			if (StandardLib.compare(cache[name], newCacheValue) != 0)
+			{
+				cache[name] = newCacheValue;
+				var bytes:ByteArray = new ByteArray();
+				bytes.writeObject(cache);
+				WeaveAPI.URLRequestUtils.saveLocalFile(CACHE_FILE_NAME, bytes);
+			}
 		}
 		
 		public const url:LinkableString = registerLinkableChild(this, new LinkableString('/WeaveAnalystServices/ComputationalServlet'), handleURLChange);
 		public const scriptName:LinkableString = newLinkableChild(this, LinkableString);
 		public const inputs:LinkableHashMap = newLinkableChild(this, LinkableHashMap);
 		public const inputKeyFilter:LinkableDynamicObject = registerLinkableChild(this, new LinkableDynamicObject(IKeyFilter));
+		public function get outputKeyType():LinkableString
+		{
+			return outputCSV.keyType;
+		}
+		public function get outputKeyColumn():LinkableString
+		{
+			return outputCSV.keyColName;
+		}
 		
 		private const promise:LinkablePromise = registerLinkableChild(this, new LinkablePromise(runScript, describePromise, true));
 		private function describePromise():String { return lang("Running script {0}", scriptName.value); }


package weave.data.DataSources
{
	import avmplus.getQualifiedClassName;
	
	import flash.utils.ByteArray;
	
	import flashx.textLayout.tlf_internal;
	
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;

		public function WeaveAnalystDataSource()
		{
			promise.depend(url, scriptName, inputs, hierarchyRefresh);
			registerLinkableChild(this, outputCSV.keyType);
			registerLinkableChild(this, outputCSV.keyColName);
			if (!cacheFile)
			{
				// register static LinkableFile as a child of the globalHashMap so it will not be disposed when an instance of this data source is disposed.
				cacheFile = registerLinkableChild(WeaveAPI.globalHashMap, new LinkableFile(URLRequestUtils.LOCAL_FILE_URL_SCHEME + CACHE_FILE_NAME), parseCacheFile);
			}
			registerLinkableChild(this, cacheFile, runScript);
			getCallbackCollection(this).addGroupedCallback(this, saveCache);
		}
		
		private static const CACHE_STATE:String = 'sessionState';
