
| Key: |
GDS-641
|
| Type: |
New Feature
|
| Status: |
Resolved
|
| Resolution: |
Fixed
|
| Priority: |
Minor
|
| Assignee: |
William Draï
|
| Reporter: |
Matt Davis
|
| Votes: |
1
|
| Watchers: |
0
|
|
If you were logged in you would be able to see more operations.
|
|
|
|
It would be useful to have events fired when a Tide client component is finished with its construction. As it stands, the constructor is called before injection takes place, so initialization that requires injection (particularly the local context) is difficult to manage.
Similarly, it would be useful to know when a client component is about to be removed from memory so that certain housekeeping or interface tasks can be handled.
Propose [PostConstruct] and [PreDestroy] Tide annotations to specify a function that should be called when these events occur.
Current workaround is to handle initialization in an event handler that is known to require client component to be instantiated. I know of no workaround for predestroy functionality, except in the case where a server conversation ends, causing the client conversational component to end. These workarounds do not cover all use cases.
|
|
Description
|
It would be useful to have events fired when a Tide client component is finished with its construction. As it stands, the constructor is called before injection takes place, so initialization that requires injection (particularly the local context) is difficult to manage.
Similarly, it would be useful to know when a client component is about to be removed from memory so that certain housekeeping or interface tasks can be handled.
Propose [PostConstruct] and [PreDestroy] Tide annotations to specify a function that should be called when these events occur.
Current workaround is to handle initialization in an event handler that is known to require client component to be instantiated. I know of no workaround for predestroy functionality, except in the case where a server conversation ends, causing the client conversational component to end. These workarounds do not cover all use cases. |
Show » |
Sort Order:
|
<code>
/*
GRANITE DATA SERVICES
Copyright (C) 2007-2008 ADEQUATE SYSTEMS SARL
This file is part of Granite Data Services.
Granite Data Services is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or (at your
option) any later version.
Granite Data Services is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
package org.granite.tide
{
import flash.utils.describeType;
import flash.utils.flash_proxy;
import mx.logging.ILogger;
import mx.logging.Log;
import mx.utils.object_proxy;
use namespace flash_proxy;
use namespace object_proxy;
/**
* ComponentFactory is a factory that handles instantiation of components and inject static dependencies
*
* @author William DRAI
*/
[ExcludeClass]
public class ComponentFactory
{
private static const log:ILogger = Log.getLogger( "org.granite.tide.ComponentFactory" );
private static const POST_CONSTRUCT_METADATA_NAME:String = 'PostConstruct';
private var _type:Class;
private var _properties:Object;
private var _useEmptyConstructor:Boolean = true;
private var _afterConstructInvokeFunctionName:String = null;
public function ComponentFactory( type:Class, properties:Object ):void
{
_type = type;
_properties = properties;
var description:XML = describeType( type );
if( description..factory..constructor..parameter.(@optional == 'false').length() == 2 )
{
_useEmptyConstructor = false;
}
// Search for post construct metadata declaration on component methods
var methods:XMLList = description..factory..method;
for each( var method:XML in methods )
{
if( method..metadata.(@name == POST_CONSTRUCT_METADATA_NAME).length() == 1 )
{
_afterConstructInvokeFunctionName = method.@name;
}
}
}
public function get type():Class
{
return _type;
}
public function describe():XML
{
return describeType( _type );
}
/**
* Instantiate component and perform injection.
*
* @param name tide component name
* @param context tide context
*
* @return new component instance.
*/
public function newInstance( name:String, context:BaseContext ):*
{
var instance:Object = instantiateComponent( name, context );
injectProperties( instance, context );
invokePostContructMethodIfExists( instance );
return instance;
}
/**
* Instantiate component.
*
* @param name Tide component name
* @param context Tide context
*
* @return new component instance if instantiation successful; <code>null</code> otherwise.
*/
private function instantiateComponent( name:String, context:BaseContext ):Object
{
var instance:Object = null;
try
{
if( !_useEmptyConstructor )
{
try
{
instance = new _type( name, context );
}
catch ( e:ArgumentError )
{
}
}
if( instance == null )
{
instance = new _type();
if( instance is IComponent )
{
IComponent( instance ).meta_init( name, context );
}
}
}
catch ( e:ArgumentError )
{
instance = null;
}
return instance;
}
/**
* Inject properties.
*
* @param instance The instance to inject.
* @param context The tide context used to lookup values.
*/
private function injectProperties( instance:Object, context:BaseContext ):void
{
if( instance != null && _properties != null )
{
for( var p:String in _properties )
{
var value:* = _properties[p];
// If properties value is a referencing tide component
if( value is String && String( value ).match( /#{.*}/ ) )
{
var val:String = String( value );
var prop:String = val.substring( 2, val.length - 1 );
var chain:Array = prop.split( "." );
value = context;
for each ( var c:String in chain )
{
value = value[c];
}
}
instance[p] = value;
}
}
}
/**
* Invoke post construct method if exists.
*/
private function invokePostContructMethodIfExists( instance:Object ):void
{
if( instance != null && _afterConstructInvokeFunctionName != null )
{
instance[ _afterConstructInvokeFunctionName ]();
}
}
}
}
</code>