how to capture trace output of flex application? - actionscript-3

I have an Air application. It consist of an HTML component. I create a flex application and launch this application in HTML component of Air Application. I am able to capture the trace output of Air application but I can not capture trace output of flex application. As this flex application is launched in Air application's HTML component. I use vizy that output the log prints. How can I capture the trace output of flex web application. Thanks

One possible solution, use mx.logging.Log for debug traces and custom LogTarget to capture them.
It would go something like this. Declare the necessary objects:
private var logTarget:MyLogTarget= new MyLogTarget();
private var myLog:ILogger;
Set up logging where you initialize the application:
myLog=Log.getLogger("MyApp");
Log.addTarget(logTarget);
Log stuff:
myLog.info("Something something.");
myLog.warn("This is weird!");
myLog.error("This shouldn't happen!");
The meat of the solution is the custom log target, MyLogTarget.as:
package
{
import mx.logging.LogEvent;
import mx.logging.targets.LineFormattedTarget;
public class MyLogTarget extends LineFormattedTarget
{
public var log:Vector.<String>=new Vector.<String>;
public function MyLogTarget()
{
super();
}
override public function logEvent(event:LogEvent):void
{
trace(event.message);
log.push(event.message+"\n");
}
}
}
This particular implementation just stores all traces in a vector of Strings, but you can modify it to save the log to disk, send it to a service, trace it on screen or whatever works for you.

Related

AS3 using Workers

IDE: FLASH CS6 Professional
SDK: AIR 18 for Android
I'm trying to use Workers for my app.
The problem is, it doesn't work that it suppose to be.
public class Main extends Sprite {
private var worker:Worker;
public function Main() {
var ba:ByteArray = this.loaderInfo.bytes;
if(Worker.current.isPrimordial){
worker = WorkerDomain.current.createWorker(ba);
worker.start();
trace("Created Main");
}else{
trace("Created Worker");
}
}
}
It should output
Created Main
Created Worker
but i'm only getting
[SWF] Test.swf - 2831 bytes after decompression
Created Main
[UnloadSWF] Test.swf
Test Movie terminated.
EDIT:
Ok i tried to publish the app and ran it. It works like it should be. But why doesn't it work when i try to ran it with Adobe Debug Launcher ?
This is what it looks like on Android Debug Launcher (ADL)
ADL
This is what it looks like when Published.
Published
EDIT 2:
Tried it with Flash Professional CC 2015. Upgraded to AIR SDK 19.0.0.213.
Still the same result. What a pain Adobe.
It should work, but Flash Pro CS6 doesn't show the worker's trace statements. Check flashlog.txt or send messages from the worker to the main SWF over a MessageChannel.
I made a lib to support use of Workers, if you want use you can check it in GitHub, it is open source project.. hope help ASWorker Link
The implementation is like this
package
{
import com.tavernari.asworker.ASWorker;
import com.tavernari.asworker.notification.NotificationCenter;
import com.tavernari.asworker.notification.NotificationCenterEvent;
import flash.display.Sprite;
public class ASWorkerDemo extends Sprite
{
private var asWorker:ASWorker;
//BOTH AREA
public function ASWorkerDemo()
{
//important know, all class start here will be replicated in all works.
asWorker = new ASWorker(this.stage, uiWorkerStartedHandler, backWorkerStartedHandler);
}
//BOTH AREA END
//UI AREA START
private function uiWorkerStartedHandler():void{
//implement all class or calls for your UI
NotificationCenter.addEventListener("FROM_BACK_EVENT_MESSAGE", onFromBackEventMessageHandler );
}
private function onFromBackEventMessageHandler(e:NotificationCenterEvent):void
{
trace(e.data);
if(e.data == "completed job"){
NotificationCenter.dispatchEventBetweenWorkers( new NotificationCenterEvent("NEXT_MESSAGE") );
}
}
//UI AREA END
//BACK AREA START
private function backWorkerStartedHandler():void{
//implement all class or calls for your BACK operations
NotificationCenter.addEventListener("NEXT_MESSAGE", uiCallForNextMessageHandler );
}
private function uiCallForNextMessageHandler():void
{
for(var i:int = 0; i < 15; ++i){
NotificationCenter.dispatchEventBetweenWorkers( new NotificationCenterEvent("FROM_BACK_EVENT_MESSAGE", false, i) );
}
NotificationCenter.dispatchEventBetweenWorkers( new NotificationCenterEvent("FROM_BACK_EVENT_MESSAGE", false, "completed job") );
}
// BACK AREA END
}
}
Good luck with Workers
Air 20.0.0.204 ADL is also not enjoying anything worker related (from my limited experimentation), however the desktop Flash Player seems to work just fine. This makes debugging convoluted and problematic when you are using Air specific libraries in your project and prefer not to wildcard variable types.
At the moment, workers are only supported on desktop platform. This Adobe developer's guide page specifically mentions "for desktop platforms".
Meanwhile, there is an AS3-Worker-Compat library by Jeff Ward that enables you to write code with Workers that will still work correctly in an environment that doesn't support Workers (of course, in this case your code will run in single-threaded mode).
I think many people are waiting for Adobe to implement workers for mobile, hopefully it will come in the future.

axon event handler in another class

I am using axon 2.3.1 , I have one aggregate class
public class MyAggregate extends AbstractAnnotatedAggregateRoot<MBAggregate> {
#AggregateIdentifier
private MyId Id;
private Circle circle;
EventDispatcher a=new EventDispatcher();
public MyAggregate() {
}
#CommandHandler
public MyAggregate(NewCommand command ) {
apply(new SmallEvent(command.getId(), command.getCircle()));
}
#CommandHandler
public MyAggregate( StoreDestinationsCommand command ) {
apply(new BigEvent(command.getId(), command.getCircle()));
}
//And some event handlers like
#EventHandler
public void onSmallEvent(SmallEvent event)
{
//Some logic here
}
#EventHandler
public void onBigEvent(BigEvent event)
{
//Some logic here
}
Now i want these event handlers to be contained in some other class and be called when that event get triggered
public class EventContainer {
private static final long serialVersionUID = -6640657879730853388L;
#EventHandler
public void onSmallEvent(SmallEvent event)
{
//Some logic here
}
#EventHandler
public void onBigEvent(BigEvent event)
{
//Some logic here
}
I tried putting them in another class but those events are not triggered.
Any idea how can i achieve this in AXON.
Thanks,
Short Answer: You need to tell Axon that your EventContainer class can handle events published to an Event Bus.
AnnotationEventListenerAdapter.subscribe(new EventContainer(), eventBus);
Longer Answer:
To achieve what you want to do, taking a step back to understand the building blocks provided by Axon to build a CQRS application would be of help...
Axon Framework is a framework that provides you with the building blocks to build a CQRS application. And a CQRS application, in layman's term is just an architecture that allows you to separate the part of your application that executes actions (write) and the part that display your application state (read).
To do this Axon provide a couple of building blocks.
1) CommandBus
The Command Bus is the component within Axon Framework that provides the mechanism of having commands routed to their respective Command Handlers. For example from your code sample, the #CommandHandler annotation on MyAggregate means that when NewCommand is created, your MyAggregate method would be called. The Command Bus is the component that makes this possible.
2) CommandGateway
Command GateWay is a component that exposes a more friendly API to the CommnadBus. While you are not required to use a Gateway to dispatch Commands, it is generally the easiest option to do so.
3) EventBus
The EventBus handles the dispatching mechanism for events. Much like the Command Bus does for Commands. So when you have apply(new BigEvent(command.getId(), command.getCircle())); which fires a BigEvent it is the Event Bus that is responsibly for making sure the necessary event handler is called. And in your case, the question you are asking is how to have the Event handlers defined in a separate Class and still have Axon be able to route the events to them.
This is quite straight forward. I would assume you are not using Spring and that you are manually setting up the Axon components together by hand and creating the NewCommand that triggers the SmallEvent that you want to handle in EventContainer#onSmallEvent method. A way to get this done may look like this:
public class FireCommandAndCaptureEventInAnotherClass {
public static void main(String[] args) {
// We use the simple Command Bus.
// There are different implementation available. For example axon provides a distributed command bus that can be used to distribute commands over multiple nodes
CommandBus commandBus = new SimpleCommandBus();
// The friendlier API to send commands with
CommandGateway commandGateway = new DefaultCommandGateway(commandBus);
// You may skip this as it may not pertain to your question but since we are using event sourcing, we need a place to store the events. we'll store Events on the FileSystem, in the "events" folder
EventStore eventStore = new FileSystemEventStore(new SimpleEventFileResolver(new File("./events")));
// a Simple Event Bus will do
EventBus eventBus = new SimpleEventBus();
// You may skip this as it may not pertain to your question but since event sourcing is used in this example we need to configure the repository: an event sourcing repository.
EventSourcingRepository<MyAggregate> repository = new EventSourcingRepository<MyAggregate>(MyAggregate.class,
eventStore);
// Sets the event bus to which newly stored events should be published
repository.setEventBus(eventBus);
// Tells Axon that MyAggregate can handle commands
AggregateAnnotationCommandHandler.subscribe(MyAggregate.class, repository, commandBus);
// This is the part you need. With this We register an event listener to be able to handle events published on to an event bus. In this case EventContainer.
AnnotationEventListenerAdapter.subscribe(new EventContainer(), eventBus);
// and let's send some Commands on the CommandBus.
commandGateway.send(id, circle);
}
}
With this setup, the handlers in the EventContainer would be able to react to events triggered from MyAggregate

Can I still create Global variables in AS3

Following the answer here, I have created a file called MyGlobals.as and placed some global variables and functions so that I can access it from anywhere within my project just like AS3 buil-in functions such as trace() method.
This is MyGlobals.as which is located in the src folder (top level folder)
package {
public var MessageQueue:Array = new Array();
public var main:Main;
public var BOOKING_STATUS_DATA:Object;
public function postMessage(msg:Object):void {
MessageQueue.push(msg);
}
public function processMessage():void {
var msg:Object = MessageQueue.pop();
if (msg) {
switch (msg.type) {
}
}
}
Looks like my IDE (FD4) is also recognizing all these functions and variables and also highlighting the varibles and functions just like any other built-in global functions. However, I am getting compilation errors "Accessing possibly undefined variable xxx". The code is as simple as trace(MessageQueue) inside my Main (or another classe).
I am wondering if there was any change Adboe has done recently that it can't be done now or am I missing something? I am not sure if I need to give any special instructions to FD to include this MyGlobals.as?
I am using FD4, Flex SKD 3.1, FP12.0
I am aware of the best practices which suggests to avoid using this type of method for creating global variables but I really need it for my project for my comfort which I feel best way (right now) when compared to take any other path which involves daunting task of code refactoring. I just want do something which can be done in AS3 which I guess is not a hack.
I've done some playing around; it looks like you can only define one (1) property or method at package level per .as file. It must be the same name (case-sensitive) as the .as file it is contained in.
So no, nothing has changed since the older Flash Versions.
In your case that would mean you need five separate ActionScript files along the lines of:
MessageQueue.as:
package
{
public var MessageQueue:Array;
}
main.as:
package
{
public var main:Main;
}
...etc. As you can see this is very cumbersome, another downside to the many others when using this approach. I suggest using the singleton pattern in this scenario instead.
package{
public class Singleton{
private static var _instance:Singleton=null;
private var _score:Number=0;
public function Singleton(e:SingletonEnforcer){
trace(‘new instance of singleton created’);
}
public static function getInstance():Singleton{
if(_instance==null){
_instance=new Singleton(new SingletonEnforcer());
}
return _instance;
}
public function get score():Number{
return _score;
}
public function set score(newScore:Number):void{
_score=newScore;
}
}
}
then iin your any as3 class if you import the singleton class
import Singleton
thn where u need to update the global var_score
use for example
var s:Singleton=Singleton.getInstance();
s.score=50;
trace(s.score);
same thing to display the 50 from another class
var wawa:Singleton=Singleton.getInstance();
trace(wawa.score)

mvvmcross: NavigationService.Navigate throws an MvxException "Unable to find incoming mvxviewmodelrequest"

In my WP8 app, I have MainView referencing MainViewModel. MainView is a menu where users can navigate to other views to do some tasks. Navigating from MainView works perfectly as I use ShowViewModel. However, navigating from other views when user completes a task, back to MainView using NavigationService.Navigate(URI) throws an exception "Unable to find incoming mvxviewmodelrequest".
To avoid this exception, I have construct the URI like below
var req = "{\"ViewModelType\":\"MyApp.Core.ViewModels.MainViewModel, MyApp.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\",\"ClearTop\":\"true\",\"ParameterValues\":null,\"RequestedBy\":null}";
NavigationService.Navigate(new Uri("/MainView.xaml?ApplicationUrl=" + Uri.EscapeDataString(req), UriKind.Relative));
Does anyone have a better way to use NavigationService.Navigate?
Most navigations in the MvvmCross samples are initiated by either MvxAppStart objects or by MvxViewModels. Both of these classes inherit from MvxNavigatingObject and use the ShowViewModel methods exposed there - see https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross/ViewModels/MvxNavigatingObject.cs
From MvxNavigatingObject, you can see that MvvmCross routes the navigation call to the IMvxViewDispatcher which in WindowsPhone is a very thin object - all it does is marshall all calls to the UI thread and to pass them on to the IMvxViewPresenter - see https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/MvxPhoneViewDispatcher.cs
The presenter is an object created in Setup - and the default implementation uses an IMvxPhoneViewModelRequestTranslator to convert the navigation call into a uri-based navigation - see https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/MvxPhoneViewPresenter.cs
Silverlight/WindowsPhone then uses this uri for navigation, creates the necessary Xaml page, and then calls OnNavigatedTo on this page. As part of the base.OnNavigatedTo(); handing in MvxPhonePage, MvvmCross then calls the OnViewCreated extension method. This method checks if there is already a ViewModel - if there isn't one then it attempts to locate one using the information in the uri - see https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/MvxPhoneExtensionMethods.cs
With this explanation in mind, if any app ever wants to initiate an MvvmCross navigation from a class which doesn't already inherit from MvxNavigatingObject - e.g. from some Service or from some other class, then there are several options:
You can provide a shim object to do the navigation - e.g.:
public class MyNavigator : MvxNavigatingObject {
public void DoIt() {
ShowViewModel<MyViewModel>();
}
}
// used as:
var m = new MyNavigator();
m.DoIt();
You can instead use IoC to locate the IMvxViewDispatcher or IMvxViewPresenter and can call their Show methods directly
var request = MvxViewModelRequest<MyViewModel>.GetDefaultRequest();
var presenter = Mvx.Resolve<IMvxViewPresenter>();
presenter.Show(request);
You can write manual code which mimics what the IMvxViewPresenter does - exactly as you have in your code - although it might be "safer" to use the IMvxPhoneViewModelRequestTranslator.cs to assist with generate the url - see https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/IMvxPhoneViewModelRequestTranslator.cs
var request = MvxViewModelRequest<MyViewModel>.GetDefaultRequest();
var translator = Mvx.Resolve<IMvxPhoneViewModelRequestTranslator>();
var uri = translator.GetXamlUriFor(request);
One other option that Views always have is that they don't have to use the standard MvvmCross navigation and ViewModel location. In WindowsPhone, your code can easily set the ViewModel directly using your own logic like:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (ViewModel == null) {
ViewModel = // something I locate
}
// if you are doing your own logic then `base.OnNavigatedTo` isn't really needed in winphone
// but I always call it anyway
base.OnNavigatedTo(e);
}
Alternatively in WindowsPhone, you can even replace MvxPhonePage with a different base class that uses it's own logic for viewmodel location. This is easy to do in WindowsPhone as all Xaml pages have built-in data-binding support.

Worker getting null when retrieving shared property

For some reason, when I try to receive a shared property from a Worker (in AS3), the result is always null. That is, I send a value to a Worker using setSharedProperty(), when I retrieve it using getSharedProperty(), it always returns undefined/null.
Here's a simple test I set up:
package
{
import flash.display.Sprite;
import flash.system.Worker;
import flash.system.WorkerDomain;
public class Main extends Sprite
{
private var _worker:Worker;
public function Main():void
{
if (Worker.current.isPrimordial)
{
initMain();
}
else
{
initWorker();
}
}
private function initMain():void
{
_worker = WorkerDomain.current.createWorker(this.loaderInfo.bytes);
_worker.setSharedProperty("message", "test");
_worker.start();
}
private function initWorker():void
{
_worker = Worker.current;
var message:String = _worker.getSharedProperty("message");
trace(message);
}
}
}
When I trace message, the result is null. Although my main goal is to make an AIR app, I get the same result whether I'm compiling for AIR (3.7) or Flash Player (11.6, for some reason 11.7 doesn't recognise flash.system.Worker as a valid class).
I'm compiling using the Flex SDK, through FlashDevelop. Does anybody know what's wrong, maybe I've missed something in my code?
FlashDevelop now seems to have complete support for debugging workers which really wasn't the case on older versions (you could neither break, or trace inside workers). AIR SDK workers support has also progressed (I remember things working in release would break in debug version)
I just recompiled your sample with AIR SDK 14 release (14.0.0.110)
air14_sdk_win/bin/mxmlc -swf-version=25 -debug=true Main.as
and debugged it with Shockwave Flash Debugger 14,0,0,125 and FlashDevelop 4.6.1.30 and got the expected result:
[Starting debug session with FDB]
Created Worker 2
test
Beware that any element not up-to-date in your debugging chain (sdk/player/debugger) could result in problems for debugging workers