Flex and Parsley Logging - apache-flex

i'm looking for a possibility to log messages in my flex 4.5 Project. This should cover errormessages in remoteClasses, errorHandler or messages typing by hand.
After reading a lot of webpages, the solution from parslay looks good. i want to switch to this framework anyway.
the benefit is the possibility to configure the logging behavior at runtime. but i don't understand the documentation. perhaps because I'm brandnew in parsley. Also google has no fitting result.
Do you have already did this and it is possible for you to give me a few code snippets.
Thanks a lot
Frank
EDIT:
Because of J_A_X justified criticism, i add my code, because i have partially succeeded.
First we need a config file, because i want to configure the logging behavior in runtime. This is a simple xml-file in the project root.
<?xml version="1.0" encoding="UTF-8"?>
<objects
xmlns="http://www.spicefactory.org/parsley"
xmlns:log="http://www.spicefactory.org/parsley/flex/logging"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.spicefactory.org/parsley
http://www.spicefactory.org/parsley/schema/2.3/parsley-core.xsd
http://www.spicefactory.org/parsley/flex/logging
http://www.spicefactory.org/parsley/schema/2.3/parsley-logging-flex.xsd"
>
<log:target level="info" type="components.SocketTarget">
</log:target>
</objects>
This is my Application:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600"
initialize="onAppInitiallize(event)"
xmlns:parsley="http://www.spicefactory.org/parsley"
>
<fx:Script>
<![CDATA[
import mx.controls.Label;
import mx.events.FlexEvent;
import mx.logging.Log;
import org.spicefactory.lib.logging.LogContext;
import org.spicefactory.parsley.flex.logging.FlexLoggingXmlSupport;
protected function onAppInitiallize(event:FlexEvent):void
{
FlexLoggingXmlSupport.initialize();
LogContext.getLogger(this);
//Log.getLogger("myCat").info("MyInfo");
}
protected function button1_clickHandler():void
{
Log.getLogger(this.toString()).info("myMessage");
Log.getLogger(this.toString()).fatal("myMessage");
}
]]>
</fx:Script>
<fx:Declarations>
<parsley:ContextBuilder>
<parsley:XmlConfig file="config.xml"/>
</parsley:ContextBuilder>
</fx:Declarations>
<s:Button click="button1_clickHandler()" label="SendLogToParsley" />
</s:Application>
At this point, the logging will work in the console of the flex builder, because parsley uses by default the TraceTarget. Now, i want to send my Logfiles to a socket. I wrote a litte rough SocketTarget.
package de.axurit.components
{
import flash.net.Socket;
import mx.logging.AbstractTarget;
import mx.logging.LogEvent;
import mx.logging.targets.LineFormattedTarget;
public class SocketTarget extends AbstractTarget
{
private var _host:String;
private var _port:int;
private var _socket:Socket;
public function SocketTarget(host:String = "localhost",port:int=8085)
{
_host = host;
_port = port;
_socket = new Socket (host,port);
super();
}
override public function logEvent (event:LogEvent):void
{
trace ("logevent" + event.message);
_socket.writeUTF(event.message + String.fromCharCode(13));
_socket.flush();
}
}
}
In the parsley documentation i can see the comment
The default target type created by this tag is a TraceTarget. You can
explicitly declare other target types:
If i add the type-attribute, i receive a Errormessage "One or more errors in BootstrapProcessor". The same as i received after a typo.
Can you give me some hints, how i can send my logs to a socket destination?

You're creating the socket, but never actually connect it. Plus, if you're going to make a log target, make your class extend trace target and override the log function.

Related

UIComponent in a test case is null

I have this App.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:Button id="bt" label="click me"/>
</s:Application>
And this test case:
package flexUnitTests
{
import flexunit.framework.Assert;
public class AppTest
{
[Test]
public function testApp():void
{
var app:App = new App();
Assert.assertNotNull(app.bt);
}
}
}
But app.bt is null. I want to access the button :(
Short Answer:
The life cycle methods have not run on app; so no createChildren() method was executed in order to create the child component of bt.
Longer Answer:
Things get slightly more complicated with the main application file, as it there is no higher level Flex component in the display hierarchy. I'm unclear on all specifics, but..
I think the Flex Compiler does some magic to set up this component--and the Flex Framework--that help makes the whole app work. You are, in essence, bypassing that work by creating your own instance of the component.

Flex Lazy Binding

Inspired by the lazy loading abilities of Hibernate I wanted to make the model part of my Flex UI request data from the server only when necessary. I thought this would be as simple as adding a public accessor that only sends server requests when the variable is accessed.
public function get tab2AC():ArrayCollection
{
if(_tab2AC == null){
//Request data from server
}
return _tab2AC;
}
Problem is that Flex seems to access all bound variables on application launch, even if the referencing component has yet to be created. So even though the DataGrid with dataProvider="{tab2AC}" has yet to be created, the server request still goes out, thus defeating the "only when required" laziness.
I do not want to place the server request inside a creationComplete handler as I want to keep my UI model ignorant of view state and my view ignorant of server requests.
Interestingly, if I add an Alert.show("anything"); inside the accessor, it works as desired.
UPDATE: Here is a full example. Set breakpoints and you'll see that Flex accesses both variables even though titleForScreen2 is not used by any created component.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
private var _titleForScreen1:String;
private var _titleForScreen2:String;
public function get titleForScreen1():String {
if(_titleForScreen1 == null){
//Server Request
}
return _titleForScreen1;
}
public function get titleForScreen2():String {
if(_titleForScreen2 == null){
//Server Request
}
return _titleForScreen2;
}
]]>
</fx:Script>
<mx:ViewStack>
<s:NavigatorContent label="Screen 1">
<s:Label text="{titleForScreen1}"/>
</s:NavigatorContent>
<s:NavigatorContent label="Screen 2">
<s:Label text="{titleForScreen2}"/>
</s:NavigatorContent>
</mx:ViewStack>
</s:Application>
Bindings in flex are pretty stupid. More of a proof of concept than an actual optimized production quality feature. What's worse is that short of modifying the compiler, there's little you can do about it without having all sorts of verification logic in your getter or (perhaps more likely) some kind of interceptive layer that makes sure that expensive calls are only made when the UI state is meaningful. At that point however, you might as well do away with bindings altogether and just implement an active controller for a passive view.
I know this is a pretty lame answer, but it's true. I've been a flex developer for several years and have had a complicated relationship with its binding feature for just as long. As well, over all this time, the only thing that has changed in the binding implementation is the ability to do two-way bindings.
By the way, syntactically I'd use a regular method rather than a property for returning a promise. Properties are often read as synchronous and cheap(-ish) operations, whereas a method (especially one that returns a promise) would have more flexible connotations.
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private var _titleForScreen1:String;
private var _titleForScreen2:String;
public function get titleForScreen1():String {
if(_titleForScreen1 == null){
//Server Request
}
return _titleForScreen1;
}
public function get titleForScreen2():String {
Alert.show("test");
if(_titleForScreen2 == null){
//Server Request
}
return _titleForScreen2;
}
]]>
</fx:Script>
<mx:ViewStack>
<s:NavigatorContent label="Screen 1">
<s:Label text="{titleForScreen1}"/>
</s:NavigatorContent>
<s:NavigatorContent label="Screen 2">
<s:Label text="{titleForScreen2}"/>
</s:NavigatorContent>
</mx:ViewStack>
</s:WindowedApplication>
Breakpoints on lines 12 and 19, check out the stack trace during each, also you can pop open Binding and take a look at wrapFunctionCall (drop a breakpoint in there too). So when it gets to lines 12 and 19, it hits them 2 times because of the preloader dispatching a complete event. I put breakpoints in every file that the stack-trace showed the execution path moving through. Unfortunately I couldn't find the point where it caused 2 calls to happen (must be in the parts I don't have the source for) it seemed every spot in the trace was only called once but I think the wrapFunctionCall was called twice during the period of those two executions. The third one that happens is due to a call to doPhasedInstantation which calls down to execute on Bindings for all the children that have the systemManager, so it would seem somehow the components have a system manager even though they may have not yet been added to the stage or created. Sorry I don't have a more concrete answer for why each of these has to happen but my guess is there's some good reason.
Ah yah almost forgot, also you'll see when the Alert is shown it causes an error but that error is captured in the wrappedFuncitonCall method in Binding.as
catch(error:Error)
{
// Certain errors are normal when executing a srcFunc or destFunc,
// so we swallow them:
// Error #1006: Call attempted on an object that is not a function.
// Error #1009: null has no properties.
// Error #1010: undefined has no properties.
// Error #1055: - has no properties.
// Error #1069: Property - not found on - and there is no default value
// We allow any other errors to be thrown.
if ((error.errorID != 1006) &&
(error.errorID != 1009) &&
(error.errorID != 1010) &&
(error.errorID != 1055) &&
(error.errorID != 1069))
{
throw error;
}
else
{
if (BindingManager.debugDestinationStrings[destString])
{
trace("Binding: destString = " + destString + ", error = " + error);
}
}
}
Your statement is not true, tab2AC getter is not accessed by Flex app on launch, as a proof here is the full application code:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
private var _tab2AC:ArrayCollection;
public function set tab2AC(value:ArrayCollection):void
{
_tab2AC = value;
}
[Bindable]
public function get tab2AC():ArrayCollection
{
if(_tab2AC == null){
trace("THIS WILL NOT BE CALLED");
}
return _tab2AC;
}
]]>
</fx:Script>
</s:Application>
As you can see, the trace will not be triggered, so your problem seems to be coming from a call to that getter from somewhere in your app, to find it, put a break-point and then "Step return" when needed.
That being said, you should not implement the lazy loading this way directly in the getter as the service call is asynchronous.
Why not return back a new ArrayCollection when the variable is null, then set the source on the ArrayCollection when the server call returns?
I think this is just wonky behavior of the debugger, rather than what would happen in ordinary execution. If you put any logic in there that will enable you to determine that the function was called that doesn't tie into the debugger (such as setting the text on a label), then the getter doesn't get called. However, if you put a trace statement in there, the getter does get called.
The conundrum is how much do you want to depend on the idea that this is only going to happen in debugging, and how critical is it to get the real behavior while you are using the debug player?
So yeah, that's just the way it is. Since Flex evaluates bindings immediately, I have to delay bindings until creation in order to prevent premature evaluation. Seems like extra work to undo Flex's weird behavior, but that's just how it goes sometimes.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.binding.utils.BindingUtils;
import mx.binding.utils.ChangeWatcher;
private var _titleForScreen1:String;
private var _titleForScreen2:String;
public function get titleForScreen1():String {
if(_titleForScreen1 == null){
//Server Request
}
return _titleForScreen1;
}
public function get titleForScreen2():String {
if(_titleForScreen2 == null){
//Server Request
}
return _titleForScreen2;
}
public function updateLabel1(value:String):void {screen1Label.text = value;}
public function updateLabel2(value:String):void {screen2Label.text = value;}
public function bindLabel1():void {
var changeWatcher:ChangeWatcher = BindingUtils.bindSetter(updateLabel1,this, "titleForScreen1");
}
public function bindLabel2():void {
var changeWatcher:ChangeWatcher = BindingUtils.bindSetter(updateLabel2,this, "titleForScreen2");
}
]]>
</fx:Script>
<mx:ViewStack>
<s:NavigatorContent label="Screen 1">
<s:Label id="screen1Label" creationComplete="bindLabel1()"/>
</s:NavigatorContent>
<s:NavigatorContent label="Screen 2">
<s:Label id="screen2Label" creationComplete="bindLabel2()"/>
</s:NavigatorContent>
</s:NavigatorContent>
</mx:ViewStack>
</s:Application>

LocalConnection: communicate between flex 4.1 and flash as2

I'm trying to communicate between a flex 4.1 application to a flash action script 2 application using LocalConnection.
flash application
contains a button called btn01 and the following code:
var a:LocalConnection = new LocalConnection();
btn01.onPress = function() {
trace("button clicked");
a.send("abcde","test");
}
you can see here that it sends a test command to the connection named 'abcde'.
flex application
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" initialize="init()">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private function init():void {
var a:LocalConnection = new LocalConnection();
a.client=this;
a.connect("abcde");
}
public function test():void {
Alert.show("test");
}
]]>
</fx:Script>
<mx:SWFLoader source="/location/as2-flash-file.swf" />
as you can see, in the flex application i connect to LocalConnection named 'abcde' and i set the client to 'this' which means that all the public functions can be executed from the LocalConnection.
the SWFLoader element loads the as2 flash file.
whenever i click the button i do see the trace message but the function test does not get executed on the flex application. any ideas?
update
both applications sit on the same domain, on the localhost actually so no need for allowDomain usage and both applications are web based.
Documentation says AS2 and AS3 LocalConnections should communicate no problems.
Do you need to look into the allowDomain method? Do you need to put a crossdomain.xml file in place? If you do have swfs on two different domains, pay special attention to the send method documentation, because you you have to add additional info to the send method's connection name.
Are they both browser based applications? I not, look into AIR
I created the LocalConnection variable within the init() scope, so when the function ended the localconnection was destroyed. the solution is just to declare the variable outside of the init function.
public var a:LocalConnection;
private function init():void {
a = new LocalConnection();
a.client=this;
a.connect("abcde");
}

How to get around Flash error 2176

In my Flex application, users need to be able to upload and download content. However, this content is access restricted, and I need to do a permissions check before allowing the upload/download. The user clicks a link, and then selects a file using the FileReference class. The FileReference class doesn't attach cookie information, so I can't use a session.
I want to implement a 2 step process where the client first pings the server to get a one-time-use token, and then does the upload or download with the one-time-use token as a parameter. However, this plan is being foiled by error #2176, which is apparently a security fix to FP10, that only allows uploads/download to be triggered during a MouseEvent propogation. Anyways around this?
I got workarround for this here.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
minWidth="955" minHeight="600"
creationComplete="creationCompleteHandler(event)">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.events.FlexEvent;
protected function creationCompleteHandler(event:FlexEvent):void
{
Alert.show("Now you can save the file!", "Test", Alert.OK|Alert.CANCEL, null, closeHandler);
}
protected function closeHandler( event:CloseEvent ):void
{
var fileReference :FileReference;
if ( event.detail == Alert.OK )
{
fileReference = new FileReference();
fileReference.save("http://www.bogdanmanate.com", "test.txt");
}
}
]]>
</mx:Script>
</mx:Application>

How can I tell if an instance implements an interface in ActionScript 3.0

I am overriding the addItem() function of an array collection and I would like to detect if the added item implements a particular interface.
Previously I used the, is operator to detect the class type, but now that I am using an interface for classes I would rather test to see if the object implements the interface.
I expect I could just try and cast the object as the interface and see if it's not null. Is this the best way to do it?
I could also just create a new addFunction() that only accepts objects of the interface type.
You can still use is to test for an interface.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo" minWidth="1024" minHeight="768" creationComplete="application1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
public var test:TestInterface = new TestInterface() //implements ITestInterface
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
trace(test is ITestInterface); //true
}
]]>
</fx:Script>
</s:Application>
To add to the answer of Joel: if you want more information about the interfaces a class implements (and its subclasses, parent classes, etc), the AS3Commons library has a ClassUtils class that has a number of convenience methods.

Resources