2
* Copyright 2008 Flowplayer Oy
4
* This file is part of Flowplayer.
6
* Flowplayer is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* Flowplayer is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with Flowplayer. If not, see <http://www.gnu.org/licenses/>.
20
package org.flowplayer.view {
21
import flash.display.AVM1Movie;
22
import flash.system.Security;
24
import org.flowplayer.model.ErrorCode;
25
import org.flowplayer.model.Plugin;
26
import org.flowplayer.controller.NetStreamControllingStreamProvider;
28
import com.adobe.utils.StringUtil;
30
import org.flowplayer.config.ExternalInterfaceHelper;
31
import org.flowplayer.controller.StreamProvider;
32
import org.flowplayer.model.Callable;
33
import org.flowplayer.model.DisplayPluginModel;
34
import org.flowplayer.model.FontProvider;
35
import org.flowplayer.model.Loadable;
36
import org.flowplayer.model.PlayerError;
37
import org.flowplayer.model.PluginError;
38
import org.flowplayer.model.PluginEvent;
39
import org.flowplayer.model.PluginModel;
40
import org.flowplayer.model.ProviderModel;
41
import org.flowplayer.util.Log;
42
import org.flowplayer.util.URLUtil;
44
import flash.display.DisplayObject;
45
import flash.display.Loader;
46
import flash.display.LoaderInfo;
47
import flash.events.Event;
48
import flash.events.EventDispatcher;
49
import flash.events.IOErrorEvent;
50
import flash.events.ProgressEvent;
51
import flash.net.URLRequest;
52
import flash.system.ApplicationDomain;
53
import flash.system.LoaderContext;
54
import flash.system.SecurityDomain;
55
import flash.utils.Dictionary;
56
import flash.utils.getDefinitionByName;
57
import flash.utils.getQualifiedClassName;
63
public class PluginLoader extends EventDispatcher {
65
private var log:Log = new Log(this);
66
private var _loadables:Array;
67
private var _loadedPlugins:Dictionary;
68
private var _loadedCount:int;
69
private var _errorHandler:ErrorHandler;
70
private var _swiffsToLoad:Array;
71
private var _pluginRegistry:PluginRegistry;
72
private var _providers:Dictionary;
73
private var _callback:Function;
74
private var _baseUrl:String;
75
private var _useExternalInterface:Boolean;
76
private var _loadErrorListener:Function;
77
private var _loadListener:Function;
78
private var _loadComplete:Boolean;
79
private var _allPlugins:Array;
80
private var _loaderContext:LoaderContext;
81
private var _loadStartedCount:int = 0;
83
public function PluginLoader(baseUrl:String, pluginRegistry:PluginRegistry, errorHandler:ErrorHandler, useExternalInterface:Boolean) {
85
_pluginRegistry = pluginRegistry;
86
_errorHandler = errorHandler;
87
_useExternalInterface = useExternalInterface;
91
private function constructUrl(url:String):String {
92
if (url.indexOf("..") >= 0) return url;
93
if (url.indexOf("/") >= 0) return url;
94
return URLUtil.addBaseURL(_baseUrl, url);
97
public function loadPlugin(model:Loadable, callback:Function = null):void {
100
_loadErrorListener = null;
104
public function load(plugins:Array, loadListener:Function = null, loadErrorListener:Function = null):void {
106
_loadListener = loadListener;
107
_loadErrorListener = loadErrorListener;
109
Security.allowDomain("*");
111
_providers = new Dictionary();
112
_allPlugins = plugins.concat([]);
113
_loadables = plugins.filter(function(plugin:*, index:int, array:Array):Boolean {
114
return plugin.url && String(plugin.url).toLocaleLowerCase().indexOf(".swf") > 0;
116
_swiffsToLoad = getPluginSwiffUrls(plugins);
118
_loadedPlugins = new Dictionary();
120
_loadStartedCount = 0;
122
_loaderContext = new LoaderContext();
123
_loaderContext.applicationDomain = ApplicationDomain.currentDomain;
124
if (!URLUtil.localDomain(_baseUrl)) {
125
_loaderContext.securityDomain = SecurityDomain.currentDomain;
128
for (var i:Number = 0; i < _loadables.length; i++) {
129
Loadable(_loadables[i]).onError(_loadErrorListener);
132
intitializeBuiltInPlugins(plugins);
133
if (_swiffsToLoad.length == 0) {
135
dispatchEvent(new Event(Event.COMPLETE, true, false));
142
private function loadNext():Boolean {
143
if (_loadStartedCount >= _swiffsToLoad.length) {
144
log.debug("loadNext(): all plugins loaded");
148
var loader:Loader = new Loader();
149
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
150
var url:String = _swiffsToLoad[_loadStartedCount];
152
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, createIOErrorListener(url));
153
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress);
154
log.debug("starting to load plugin from url " + _swiffsToLoad[_loadStartedCount]);
155
loader.load(new URLRequest(url), _loaderContext);
160
private function getPluginSwiffUrls(plugins:Array):Array {
161
var result:Array = new Array();
162
for (var i:Number = 0; i < plugins.length; i++) {
163
var loadable:Loadable = Loadable(plugins[i]);
164
if (! loadable.isBuiltIn && loadable.url && result.indexOf(loadable.url) < 0) {
165
result.push(constructUrl(loadable.url));
171
private function intitializeBuiltInPlugins(plugins:Array):void {
172
for (var i:int = 0; i < plugins.length; i++) {
173
var loadable:Loadable = plugins[i] as Loadable;
174
log.debug("intitializeBuiltInPlugins() " + loadable);
175
if (loadable.isBuiltIn) {
176
log.info("intitializeBuiltInPlugins(), instantiating from loadable " + loadable + ", with config ", loadable.config);
177
var instance:Object = loadable.instantiate();
178
var model:PluginModel = createPluginModel(loadable, instance);
179
model.isBuiltIn = true;
180
// if (instance.hasOwnProperty("onConfig")) {
181
// instance.onConfig(model);
183
initializePlugin(model, instance);
188
private function createIOErrorListener(url:String):Function {
189
return function(event:IOErrorEvent):void {
190
log.error("onIoError " + url);
191
_loadables.forEach(function(loadable:Loadable, index:int, array:Array):void {
192
if (! loadable.loadFailed && hasSwiff(url, loadable.url)) {
193
log.debug("onIoError: this is the swf for loadable " + loadable);
194
loadable.loadFailed = true;
195
loadable.dispatchError(PluginError.INIT_FAILED);
196
incrementLoadedCountAndFireEventIfNeeded();
202
private function onProgress(event:ProgressEvent):void {
203
log.debug("load in progress");
207
public function get plugins():Dictionary {
208
return _loadedPlugins;
211
private function loaded(event:Event):void {
212
var info:LoaderInfo = event.target as LoaderInfo;
213
log.debug("loaded class name " + getQualifiedClassName(info.content));
215
var instanceUsed:Boolean = false;
216
_loadables.forEach(function(loadable:Loadable, index:int, array:Array):void {
217
if (! loadable.plugin && hasSwiff(info.url, loadable.url)) {
218
log.debug("this is the swf for loadable " + loadable);
219
if (loadable.type == "classLibrary") {
220
initializeClassLibrary(loadable, info);
222
var plugin:Object = info.content is AVM1Movie ? info.loader : createPluginInstance(instanceUsed, info.content);
223
initializePlugin(createPluginModel(loadable, plugin), plugin);
224
//initializePlugin(loadable, instanceUsed, info);
229
incrementLoadedCountAndFireEventIfNeeded();
230
if (_callback != null) {
236
private function incrementLoadedCountAndFireEventIfNeeded():void {
237
if (++_loadedCount == _swiffsToLoad.length) {
238
log.debug("all plugin SWFs loaded. loaded total " + loadedCount + " plugins");
240
dispatchEvent(new Event(Event.COMPLETE, true, false));
244
private function initializeClassLibrary(loadable:Loadable, info:LoaderInfo):void {
245
log.debug("initializing class library " + info.applicationDomain);
246
_loadedPlugins[loadable] = info.applicationDomain;
247
_pluginRegistry.registerGenericPlugin(loadable.createPlugin(info.applicationDomain));
250
private function createPluginModel(loadable:Loadable, pluginInstance:Object):PluginModel {
251
log.debug("creating model for loadable " + loadable + ", instance " + pluginInstance);
253
_loadedPlugins[loadable] = pluginInstance;
255
log.debug("pluginInstance " + pluginInstance);
256
if (pluginInstance is DisplayObject) {
257
return Loadable(loadable).createDisplayPlugin(pluginInstance as DisplayObject);
259
} else if (pluginInstance is StreamProvider) {
260
return Loadable(loadable).createProvider(pluginInstance);
262
return Loadable(loadable).createPlugin(pluginInstance);
266
private function initializePlugin(model:PluginModel, pluginInstance:Object):void {
267
if (pluginInstance is FontProvider) {
268
_pluginRegistry.registerFont(FontProvider(pluginInstance).fontFamily);
270
} else if (pluginInstance is DisplayObject) {
271
_pluginRegistry.registerDisplayPlugin(model as DisplayPluginModel, pluginInstance as DisplayObject);
273
} else if (pluginInstance is StreamProvider) {
274
_providers[model.name] = pluginInstance;
275
_pluginRegistry.registerProvider(model as ProviderModel);
277
_pluginRegistry.registerGenericPlugin(model);
279
if (pluginInstance is Plugin) {
280
if (_loadListener != null) {
281
model.onLoad(_loadListener);
283
model.onError(onPluginError);
285
if (model is Callable && _useExternalInterface) {
286
ExternalInterfaceHelper.initializeInterface(model as Callable, pluginInstance);
290
private function onPluginError(event:PluginEvent):void {
291
log.debug("onPluginError() " + event.error);
293
_errorHandler.handleError(event.error, event.info + ", " + event.info2, true);
297
private function createPluginInstance(instanceUsed:Boolean, instance:DisplayObject):Object {
298
if (instance.hasOwnProperty("newPlugin")) return instance["newPlugin"]();
300
if (! instanceUsed) {
301
log.debug("using existing instance " + instance);
304
var className:String = getQualifiedClassName(instance);
305
log.info("creating new " + className);
306
var PluginClass:Class = Class(getDefinitionByName(className));
307
return new PluginClass() as DisplayObject;
310
public function setConfigPlugins():void {
311
_allPlugins.forEach(function(loadable:Loadable, index:int, array:Array):void {
312
if (! loadable.loadFailed) {
313
var pluginInstance:Object = plugins[loadable];
314
log.info(index + ": setting config to " + pluginInstance + ", " + loadable);
315
if (pluginInstance is NetStreamControllingStreamProvider) {
316
log.debug("NetStreamControllingStreamProvider(pluginInstance).config = " +loadable.plugin);
317
NetStreamControllingStreamProvider(pluginInstance).model = ProviderModel(loadable.plugin);
319
if (pluginInstance.hasOwnProperty("onConfig")) {
320
pluginInstance.onConfig(loadable.plugin);
327
private function hasSwiff(infoUrl:String, modelUrl:String):Boolean {
328
if (! modelUrl) return false;
329
var slashPos:int = modelUrl.lastIndexOf("/");
330
var swiffUrl:String = slashPos >= 0 ? modelUrl.substr(slashPos) : modelUrl;
331
return StringUtil.endsWith(infoUrl, swiffUrl);
334
public function get providers():Dictionary {
338
public function get loadedCount():int {
342
public function get loadComplete():Boolean {
343
return _loadComplete;