| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| package UnitTest.Fixtures |
| { |
| import flash.events.Event; |
| import flash.events.IOErrorEvent; |
| import flash.events.SecurityErrorEvent; |
| import flash.net.URLLoader; |
| import flash.net.URLRequest; |
| import flash.net.URLRequestMethod; |
| |
| import mx.utils.LoaderUtil; |
| |
| /** Gateway class for reading and caching files used by the test harness code. |
| */ |
| public class FileRepository |
| { |
| /** Get the named file. |
| * @param fileName name of the file we're looking for |
| * @return String that contains the content of the file |
| */ |
| static public function getFile(baseURL:String, fileName:String):String |
| { |
| return CustomURLLoader.getFile(LoaderUtil.createAbsoluteURL(baseURL,fileName)); |
| } |
| |
| /** Get the named file as an XML object. |
| * File will be converted assuming whitespace is significant. |
| * @param fileName of the file we're looking for |
| * @return String that contains the content of the file |
| */ |
| static public function getFileAsXML(baseURL:String, fileName:String):XML |
| { |
| var xmlData:XML = null; |
| var sourceString:String = getFile(baseURL,fileName); |
| return sourceString ? convertToXML(sourceString) : null; |
| } |
| |
| /** Convert from string to XML */ |
| static private function convertToXML(sourceString:String):XML |
| { |
| var xmlData:XML = null; |
| |
| // Convert string data to XML |
| var originalSettings:Object = XML.settings(); |
| try |
| { |
| XML.ignoreProcessingInstructions = false; |
| XML.ignoreWhitespace = false; |
| xmlData = new XML(sourceString); |
| } |
| finally |
| { |
| XML.setSettings(originalSettings); |
| } |
| return xmlData; |
| } |
| |
| /** |
| * Reads in a file and set up a handler for when the file read is complete |
| */ |
| static public function readFile(baseURL:String, fileName:String, handler:Function = null, errorHandler:Function = null, securityHandler:Function = null, ignoreWhitespace:Boolean = false): void |
| { |
| if (fileName == null || fileName.length <= 0) |
| return; |
| |
| var tcURL:URLRequest = new URLRequest(LoaderUtil.createAbsoluteURL(baseURL,fileName)); |
| tcURL.method = URLRequestMethod.GET; |
| var tcLoader:URLLoader = new CustomURLLoader(handler, errorHandler, securityHandler); |
| tcLoader.load(tcURL); |
| } |
| |
| /** |
| * Returns true if there are pending requests, false if not |
| */ |
| static public function pendingRequests(): Boolean |
| { |
| return (CustomURLLoader.requestsPending != 0); |
| } |
| } |
| } |
| import flash.net.URLLoader; |
| import flash.net.URLRequest; |
| import flash.events.Event; |
| import flash.events.SecurityErrorEvent; |
| import flash.events.IOErrorEvent; |
| import flashx.textLayout.debug.assert; |
| |
| /** Serves as a single bottleneck for all requests that go through |
| * FileRepository. Requests come in as URLLoader.load calls, and we |
| * always listen for completion, error, and security error. If a handler |
| * for any of these is passed in when the CustomURLLoader is constructed, |
| * we will in addition call the handler. |
| * |
| * Override URLLoader so we can get the request back when we're |
| * in a completion function. Also tracks outstanding requests so we |
| * can block until results are complete. |
| */ |
| class CustomURLLoader extends URLLoader |
| { |
| public var request: URLRequest; // original request for file load |
| public var completeHandler:Function; // custom completion handler |
| public var ioErrorHandler:Function; // custom i/o error handler |
| public var securityErrorHandler:Function; // custom security error handler |
| |
| /** Cache containing all files that have been requested. |
| * The key is the name of the file as given in the original request, and the |
| * value is the contents of the file as a string. */ |
| static private var _fileCache:Object; |
| |
| /** Number of file read requests that are pending -- i.e., that have neither |
| * completed successfully nor returned errors. |
| */ |
| static private var _requestsPending:int = 0; |
| |
| static private var FILE_ERROR:String = "$$$NOT_FOUNDXXX" // unique string to signal file read error |
| |
| /** Constructor |
| * Note that if you specify all three handlers, one will be called depending on the outcome of the |
| * read. |
| * |
| * @param completeHandler - custom handler called on successful completion of file read |
| * @param ioErrorHandler - custom handler called on i/o error of file read |
| * @param securityErrorHandler - custom handler called on security error of file read |
| */ |
| public function CustomURLLoader(completeHandler:Function, ioErrorHandler:Function = null, securityErrorHandler:Function = null) |
| { |
| this.completeHandler = completeHandler; |
| this.ioErrorHandler = ioErrorHandler; |
| this.securityErrorHandler = securityErrorHandler; |
| |
| if (!_fileCache) |
| _fileCache = new Object(); |
| } |
| |
| /** Returns number of file read requests that are pending -- i.e., that have neither |
| * completed successfully nor returned errors. |
| */ |
| static public function get requestsPending():int |
| { |
| return _requestsPending; |
| } |
| |
| /** Given the name of a file, look it up in the cache and return the contents as a string. */ |
| static public function getFile(fileName:String):String |
| { |
| // If it's in the cache, just return it |
| if (_fileCache[fileName] != null) |
| return _fileCache[fileName]; |
| |
| // We have a request out, and we're waiting for the result. Unfortunately, there's no |
| // way we know to wait and still handle the events that would cause the pending status |
| // to complete. So we return failure here as well. |
| if (_fileCache.hasOwnProperty(fileName)) |
| return null; |
| |
| // We've never seen this file |
| return null; |
| } |
| |
| /** Add a new file to the cache. Takes the name of the file, as given in the URLRequest, |
| * and the file contents as a string. */ |
| static private function addToCache(urlLoader:CustomURLLoader, data:String):void |
| { |
| CONFIG::debug { assert(_fileCache[getFileKey(urlLoader)] == null, "Adding over existing cache entry!"); } |
| _fileCache[getFileKey(urlLoader)] = data; |
| } |
| |
| /** Default handler. This will get called on every successful completion of a read that goes |
| * through CustomURLLoader. It's job is to add the file to the file cache, and call the |
| * custom completion handler, if one was specified. |
| */ |
| static private function defaultCompleteHandler(event:Event):void |
| { |
| // Remove the event listener that was attached so this function could get called. |
| if (event) |
| event.target.removeEventListener(Event.COMPLETE, defaultCompleteHandler); |
| |
| // This request handled; is no longer pending |
| --_requestsPending; |
| |
| // Add the new file to the cache |
| var urlLoader:CustomURLLoader = CustomURLLoader(event.target); |
| addToCache(urlLoader, urlLoader.data); |
| |
| // Call the custom completion handler |
| if (urlLoader.completeHandler != null) |
| urlLoader.completeHandler(event); |
| urlLoader.close(); |
| } |
| |
| /** Default handler. This will get called on every security error of a read that goes |
| * through CustomURLLoader. It's job is to update the file cache, and call the |
| * custom security error handler, if one was specified. |
| */ |
| static private function defaultSecurityErrorHandler(event:SecurityErrorEvent):void |
| { |
| if (event) |
| event.target.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, defaultSecurityErrorHandler); |
| |
| --_requestsPending; |
| var urlLoader:CustomURLLoader = CustomURLLoader(event.target); |
| addToCache(urlLoader, FILE_ERROR); |
| if (urlLoader.securityErrorHandler != null) |
| urlLoader.securityErrorHandler(event); |
| } |
| |
| /** Default handler. This will get called on every i/o error of a read that goes |
| * through CustomURLLoader. It's job is to update the file cache, and call the |
| * custom i/o error handler, if one was specified. |
| */ |
| static private function defaultIOErrorHandler(event:IOErrorEvent):void |
| { |
| if (event) |
| event.target.removeEventListener(IOErrorEvent.IO_ERROR, defaultIOErrorHandler); |
| |
| --_requestsPending; |
| var urlLoader:CustomURLLoader = CustomURLLoader(event.target); |
| addToCache(urlLoader, FILE_ERROR); |
| if (urlLoader.ioErrorHandler != null) |
| urlLoader.ioErrorHandler(event); |
| } |
| |
| /* Start a file read. |
| * @param request - URL request for the read |
| */ |
| override public function load(request:URLRequest):void |
| { |
| this.request = request; |
| |
| // If we have already read this file in, or we are already in the middle of reading it in, don't make another request |
| if (_fileCache.hasOwnProperty(getFileKey(this))) |
| { |
| CONFIG::debug { assert (completeHandler == null, "Load has file cached, won't be calling completeHandler! You should call get() before calling readFile()"); } |
| return; |
| } |
| |
| // Add it to the cache as a null entry, to signal there's a request pending on it |
| _fileCache[getFileKey(this)] = null; |
| |
| // Attach listeners so the default handlers get called. |
| addEventListener(Event.COMPLETE,defaultCompleteHandler, false, 0, true); |
| addEventListener(SecurityErrorEvent.SECURITY_ERROR,defaultSecurityErrorHandler, false, 0, true); |
| addEventListener(IOErrorEvent.IO_ERROR, defaultIOErrorHandler, false, 0, true); |
| |
| ++_requestsPending; |
| super.load(request); |
| } |
| |
| /** Given a URLLoader, return the key for access the file cache. Right now, we |
| * just use the file name for this. |
| */ |
| static private function getFileKey(urlLoader:CustomURLLoader):String |
| { |
| return urlLoader.request.url; |
| } |
| } |