Currently working on a flex AIR project based on PureMVC framework. There was a new requirement to the project, an operation is to be performed repetitively at regular interval which has some business logic. As per PureMVC this should be placed in the command, but then command would get garbage collected the moment its executed.
Given the scenario there are few doubts/confusions/clarifications...
Creating a command with business logic would be one solution ... but then who would trigger it at specific interval? (shouldn't this be done by a command as per PureMVC)
Placing the command trigger in a mediator or placing the logic in a mediator (this would make pureMVC a bit impure :) )
How do I find a solution for this kind of scenario?
You need to pull apart the async process you want to run and the repetitive triggering of said process. My advice is to create a Proxy for the async process and a separate Proxy that's a wrapper for a Timer which simply sends a notification upon timeout. The notification is coupled to a command, which in turn calls the async proxy's methods. That way you can add logic to the command for instance what to do if the process is still busy.
The benefits of creating two proxies: you adhere to SRP. You can easily swap/modify/remove the timing proxy w/o touching the async proxy. Everything is nicely separated.
depends on what the Command should do - if it updates the Model put a Timer in one of your Proxy class and send a Notification every xx seconds which is mapped to a Command that does whatever it is you want it to do.
If it should just update the View you could add the Timer to the corresponding Mediator but then you wouldn't need a Command at all.
**
Don't create more Singletons than you need. ApplicationFacade is already one - try and keep it that way.
**
If you have to do any async calls to the backend, just make sure to add the EventListener without weakReference set to true - then everything should be ok...
Try this:
Create a Singleton class - singleton class in Flex
Have a function in this class (eg. called start) that when called starts a timer, the callback function of which sends a notification, that triggers a command that does your business logic.
When you are ready to start your regular actions simply call the get instance method on your singleton, to create the singleton and then call it's start() function.
*Optionally have a stop function that cancels the timer and stops the regular notifications being sent.
package
{
import flash.events.TimerEvent;
import flash.utils.Timer;
public final class RepititiveSingleton
{
private var timer:Timer;
private static var instance:RepititiveSingleton= new RepititiveSingleton();
public function RepititiveSingleton() {
if( RepititiveSingleton.instance ) {
throw new Error(
"ReptitiveSingleton can only be accessed through Singleton.getInstance()" );
}
}
public static function getInstance():RepititiveSingleton{
return RepititiveSingleton.instance;
}
public function start(interval:Number = 1000):void {
timer = new Timer(interval);
timer.addEventListener(TimerEvent.TIMER, onTimer);
}
private function onTimer(e:TimerEvent):void {
ApplicationFacade.getInstance().sendNotification(Constants.REPTITIVE_ACTION_NOTIFICATION));
}
}
}
This code assumes that you have your Concrete facade named ApplicationFacade, and have registered a notification using a String constant that is referenced from a class called constants.
Then in an appropriate place (maybe in your startup command) you can add:
RepetitiveSingleton.getInstance().start();
Hope this helps you.
IMO, the timer belongs in a mediator. Let it- well, mediate the asynch process messaging. It will be a little state machine to make sure everything is running smoothly. Commands still do the heavy lifting, it just sits around like a 911 operator.
Related
I want to create a controller based JavaFX GUI consisting of multiple controllers.
The task I can't accomplish is to pass parameters from one Scene to another AND back.
Or in other words:
The MainController loads SubController's fxml, passes an object to SubController, switches the scene. There shall not be two open windows.
After it's work is done, the SubController shall then switch the scene back to the MainController and pass some object back.
This is where I fail.
This question is very similar to this one but still unanswered. Passing Parameters JavaFX FXML
It was also mentioned in the comments:
"This work when you pass parameter from first controller to second but how to pass parameter from second to first controller,i mean after first.fxml was loaded.
– Xlint Xms Sep 18 '17 at 23:15"
I used the first approach in the top answer of that thread.
Does anyone have a clue how to achieve this without external libs?
There are numerous ways to do this.
Here is one solution, which passes a Consumer to another controller. The other controller can invoke the consumer to accept the result once it has completed its work. The sample is based on the example code from an answer to the question that you linked.
public Stage showCustomerDialog(Customer customer) {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"customerDialog.fxml"
)
);
Stage stage = new Stage(StageStyle.DECORATED);
stage.setScene(
new Scene(
(Pane) loader.load()
)
);
Consumer<CustomerInteractionResult> onComplete = result -> {
// update main screen based upon result.
};
CustomerDialogController controller =
loader.<CustomerDialogController>getController();
controller.initData(customer, onComplete);
stage.show();
return stage;
}
...
class CustomerDialogController() {
#FXML private Label customerName;
private Consumer<CustomerInteractionResult> onComplete
void initialize() {}
void initData(Customer customer, Consumer<CustomerInteractionResult> onComplete) {
customerName.setText(customer.getName());
this.onComplete = onComplete;
}
#FXML
void onSomeInteractionLikeCloseDialog(ActionEvent event) {
onComplete.accept(new CustomerInteractionResult(someDataGatheredByDialog));
}
}
Another way to do this is to add a result property to the controller of the dialog screen and interested invokers could listen to or retrieve the result property. A result property is how the in-built JavaFX dialogs work, so you would be essentially imitating some of that functionality.
If you have a lot of this passing back and forth stuff going on, a shared dependency injection model based on something like Gluon Ignite, might assist you.
I've used AfterBurner.fx for dependency injection, which is very slick and powerful as long as you follow the conventions. It's not necessarily an external lib if you just copy the 3 classes into your structure. Although you do need the javax Inject jar, so I guess it is an eternal reference.
Alternately, if you have a central "screen" from which most of your application branches out you could use property binding probably within a singleton pattern. There are some good articles on using singleton in JavaFX, like this one. I did that for a small application that works really great, but defining all of those bindings can get out of hand if there are a lot of properties.
To pass data back, the best approach is probably to fire custom Events, which the parent controller subscribes to with Node::addEventHandler. See How to emit and handle custom events? for context.
In complex cases when the two controllers have no reference to each other, a Event Bus as #jewelsea mentioned is the superior option.
For overall architecture, this Reddit comment provides some good detail: https://www.reddit.com/r/java/comments/7c4vhv/are_there_any_canonical_javafx_design_patterns/dpnsedh/
I have a TitleWindow component. It allows me to save some data provided through 3 TextInput.
That data "fills" a DropDownList which is in another TitleWindow component, not inside the original one.
How can I call the remoteObject method that fills (or refresh) my DropDownList?
Any ideas will be appreciated!
You can simply use a Singleton as a model if you'd like, this will allow you to share data, but beware keep data only that needs to be shared in here or it will just become a global nightmare.
Using a singleton means you'll have a class that you can only ever have one instance of. If you put properties in that class any time you reference it it will be the same memory throughout the application execution.
http://blog.pixelbreaker.com/actionscript-3-0/as30-better-singletons
Marking the singleton class or individual properties as Bindable will make it so you can watch for the changes and call a function.
http://livedocs.adobe.com/flex/3/html/help.html?content=databinding_8.html
Putting this together you have something like this:
[Singleton.as]
package
{
[Bindable]
public class Singleton
{
public var myListData:Array;
public static var instance:Singleton;
public static function getInstance():Singleton
{
if( instance == null ) instance = new Singleton( new SingletonEnforcer() );
return instance;
}
public function Singleton( pvt:SingletonEnforcer )
{
// init class
}
}
}
internal class SingletonEnforcer{}
Somewhere else you want to get a handle on this
[MyTitleWindow.as]
var instance:Singleton = Singleton.getInstance();
instance.myListData = [1,2,3];
[MyTitleWindowWithAList]
var instance:Singleton = Singleton.getInstance();
BindingUtils.bindSetter(funcUpdateList, instance, "myListData");
private function funcUpdateList(data:Object)
{
myList.dataProvider = data as Array;
}
Another option is to create an event that carries your data payload, dispatch that event from the first title window, and capture it, the problem with this is you have to register the listeners on the PopUpManager or SystemManager I believe because the TitleWindow's aren't direct children of the Application I believe.
Singletons are a bad idea and you should not get in the habit of using them. Instead, just dispatch an event from the View and catch it from something else that has access to your Service object.
Note that your Service should not be part and parcel of any View--the responsibility of a View is displaying data and capturing requests from the user to change the data, not communicating with a server.
For examples of an application written with this pattern in mind, check out
[Refactoring with Mate] (http://www.developria.com/2010/05/refactoring-with-mate.html) - The example has View source enabled
The same application done with RobotLegs - again, View Source is enabled.
Note that these are written against some popular frameworks, but they are written in such a way that you can easily replace that framework code with something else, even your own code.
For reference, here is the naiive implementation, where the service layer is being called directly in the Views. You couldn't call a different service without changing the Views, though the use of the static service means you could use it from elsewhere.
That static usage survived into the later examples, though today I would never write something depending on a globally accessible object. In part this is because I discovered Test Driven Development, and it is impossible to replace the "real" static object with an object that lets you isolate what you are testing. However, the fact that most of the code in the 2 "better" examples is insulated from that static object means that it is trivial to replace it with one that is provided some other way.
The lesson here is if you're going to use static, global objects, lock them away behind as much abstraction as you can. But avoid them if you're at all interested in best practice. Note that a Singleton is a static global object of the worst kind.
I'm working with Progress 10.1c
I have a class that contains both static and non-static methods.
The class is defined with USE-WIDGET-POOL. In the destructor I say "DELETE WIDGET-POOL".
I create an instance of my class, and call a method. The method itself uses one of the static methods of the class. So if I understand it correctly, I will now have the instance of my class in its own unnamed pool, and a separate unnamed widget pool for the static members of the class.
So far so good. But I'm busy debugging and I'm making changes to the code. I recompile and run my test again. Now my non-static members work, but all the static members come from the older version of my class, that is still stored in the pool for static members, which is scoped to the session. In other words, the "DELETE WIDGET-POOL" in my destructor deleted the pool for the instance of the class, but the pool for the static members is still there.
The only way I can get it to load the new version of my class is to log off my session, and log on again. This is quite a mission in our environment. Every time I make a change, I have to stop and start my development environment.
I tried to walk the list of objects in my session, but could not find what I'm looking for. There's a good chance I'm starting at the wrong object, or I'm missing some knowledge of pools and objects in Progress.
Is there any way for me to target that unnamed pool and delete the static "instance" of my class, without destroying my session every time?
This turned out to be doable with very little coding. I can use the statement DELETE OBJECT THIS-OBJECT to delete the instance executing that statement. So if it's in a static method, it is the static instance that gets deleted.
METHOD STATIC VOID Reload () :
DELETE OBJECT THIS-OBJECT.
END METHOD.
So now when I have a new version of the class, I just use MyClass:Reload(). No need to end my session.
Thanks to Tim Kuehn for pointing me in the right direction with his suggestion of using a static method to delete the named widget-pool.
I have created this example to demonstrate how I got it to work. Below is a simple class with 3 static methods:
/* File : rtt/cls/demo.cls */
USING Progress.Lang.*.
ROUTINE-LEVEL ON ERROR UNDO, THROW.
CLASS rtt.cls.demo USE-WIDGET-POOL :
METHOD STATIC CHARACTER SayHello() :
RETURN "Good-bye".
END METHOD.
METHOD STATIC VOID ShowMessage() :
MESSAGE "This is the message." VIEW-AS ALERT-BOX.
END METHOD.
METHOD STATIC VOID Reload() :
DELETE OBJECT this-object.
END METHOD.
END CLASS.
I don't know how other people's environments are set up, but in my environment I have to log on to our system to be able to compile and run programs, in other words, I have an active session.
So I compile the file:
COMPILE VALUE(SEARCH("rtt/cls/demo.cls")) SAVE.
And then I run the following bit in Procedure Editor to test it:
USING rtt.cls.*.
demo:ShowMessage().
MESSAGE demo:SayHello().
When I run this, I get a message box that says "This is the message.", followed by a message box that says "Good-bye". Exactly as one would expect.
But there's a bug, it's supposed to say "Hello", not "Good-Bye", so I edit my class (I'm only showing the two methods I'm changing:
METHOD STATIC CHARACTER SayHello() :
RETURN "Hello".
END METHOD.
METHOD STATIC VOID ShowMessage() :
MESSAGE "That was the message." VIEW-AS ALERT-BOX.
END METHOD.
I save my changes, compile it as before, and I run the test again. What messages do you expect to see? I expect to see "This is the message." and "Good-bye", same as before. That's logical, because there is a hidden widget-pool in my current session, and it has an instance of my class loaded (from my first test). It will keep on using this instance until the instance or the pool is destroyed. So I shut down my development environment, log off and then log on again to start up a new session. So far everything is working exactly as expected.
Now I run my test again, and sure enough, I get my new version: the messages are "That was the message" and "Hello".
But now I'm told to add an exclamation after the word "Hello". so I change it:
METHOD STATIC CHARACTER SayHello() :
RETURN "Hello!".
END METHOD.
I save it and compile it. When I run the test, obviously I will get the older version that says "Hello" without the exclamation. I have to restart my session again before my changes become active. I really don't want to do that again. So I change my test as follows:
USING rtt.cls.*.
demo:Reload().
demo:ShowMessage().
MESSAGE demo:SayHello().
I run it and voilà, I get my latest changes. I change the message from "That was the message" to "It works!". I save, compile and run my test. What do I see? I see "It works!". No more restarting my session between edits. My solution works perfectly for me.
I tried all sorts of stuff, but I cannot get it to generate the error "Cannot Reference THIS-OBJECT or SUPER from a static member (15071)".
Static class elements last for the duration of the ABL session, and the only way to 'unload' them is to have a database connection go down (ie, the db server is shut down). This unloads everything, clears the client code, and leaves you in the 4GL editor.
Beyond that, the only other possible way is to create a named widget pool for the static class, then call a (static) method to delete that. I have no idea if this would work or not.
"Static members that are scoped to the class type. This unnamed widget pool is implicitly
deleted only when the ABL session in which the widget pool is created terminates."
http://documentation.progress.com/output/OpenEdge102b/pdfs/dvoop/dvoop.pdf
page 5-9
In this case make you something wrong. You should use the static members only for methods or properties, which are realy static and must be not deleted or reinitialised when is deleted the instance of class.
when you will use it anyway, you should define your own static widget-pool with name and any static dynamic objects create in this widget-pool. then can you in Reload() write:
METHOD STATIC VOID Reload () :
DELETE WIDGET-POOL XYZ.
CREATE WIDGET-POOL XYZ.
END METHOD.
other way is to use a singelton class, where are defined this 'static' objects. then anytime, when you will, you can delete the instance of this singelton and make some new fresh.
I have a method under test. Within its call stack, it calls a DAO which intern uses JDBC to chat with the DB. I am not really interested in knowing what will happen at the JDBC layer; I already have tests for that, and they work wonderfully.
I am trying to mock, using JMock, the DAO layer, so I can focus on the details this method under test. Here is a basic representation of what I have.
#Test
public void myTest()
{
context.checking(new Expectations() {
{
allowing(myDAO).getSet(with(any(Integer.class)));
will(returnValue(new HashSet<String>()));
}
});
// Used only to show the mock is working but not really part of this test.
// These asserts pass.
Set<String> temp = myDAO.getSet(Integer.valueOf(12));
Assert.assertNotNull(temp);
Assert.assertTrue(temp.isEmpty());
MyTestObject underTest = new MyTestObject();
// Deep in this call MyDAO is initialized and getSet() is called.
// The mock is failing to return the Set as desired. getSet() is run as
// normal and throws a NPE since JDBC is not (intentionally) setup. I want
// getSet() to just return an empty set at this layer.
underTest.thisTestMethod();
...
// Other assertions that would be helpful for this test if mocking
// was working.
}
It, from what I have learned creating this test, that I cannot mock indirect objects using JMock. OR I am not seeing a key point. I'm hoping for the second half to be true.
Thoughts and thank you.
From the snippet, I'm guessing that MyTestObject uses reflection, or a static method or field to get hold of the DAO, since it has no constructor parameters. JMock does not do replacement of objects by type (and any moment now, there'll be a bunch of people recommending other frameworks that do).
This is on purpose. A goal of JMock is to highlight object design weaknesses, by requiring clean dependencies and focussed behaviour. I find that burying DAO/JDBC access in the domain objects eventually gets me into trouble. It means that the domain objects have secret dependencies that make them harder to understand and change. I prefer to make those relationships explicit in the code.
So you have to get the mocked object somehow into the target code. If you can't or don't want to do that, then you'll have to use another framework.
P.S. One point of style, you can simplify this test a little:
context.checking(new Expectations() {{
allowing(myDAO).getSet(12); will(returnValue(new HashSet<String>()));
}});
within a test, you should really know what values to expect and feed that into the expectation. That makes it easier to see the flow of values between the objects.
I have a large application that needs to ensure that various items are loaded (at different times, not just at startup) before calling other routines that depend on said loaded items. What i find problematic is how my architecture ends up looking to support this: it is either littered with callbacks (and nested callbacks!), or pre populated with dozens of neat little
private function SaveUser_complete(params:ReturnType):void
{
continueOnWithTheRoutineIWasIn();
}
and so forth. Right now the codebase is only perhaps 2500 lines, but it is going to grow to probably around 10k. I just can't see any other way around this, but it seems so wrong (and laborious). Also, i've looked into pureMVC, Cairngorm, and these methods seem equally tedious,except with another layer of abstraction. Any suggestions?
Well asynchronous operations always have this affect on code bases, unfortunately there's not really a lot you can do. If your loading operations form some sort of 'Service' then it would be best to make a IService interface, along with the appropriate MVC Style architecture and use data tokens. Briefly:
//In your command or whatever
var service:IService = model.getService();
var asyncToken:Token = service.someAsyncOperation(commandParams);
//some messaging is used here, 'sendMessage' would be 'sendNotification' in PureMVC
var autoCallBack:Function = function(event:TokenEvent):void
{
sendMessage(workOutMessageNameHere(commandParams), event.token.getResult());
//tidy up listeners and dispose token here
}
asyncToken.addEventListener(TokenEvent.RESULT, autoCallBack, false, 0, true);
Where I have written the words 'workOutMessageNameHere()' I assume is the part you want to automate, you could either have some sort of huge switch, or a map of commandParams (urls or whatever) to message names, either way best get this info from a model (in the same command):
private function workOutMessageNameHere(commandParams):String
{
var model:CallbackModel = frameworkMethodOfRetrivingModels();
return model.getMessageNameForAsyncCommand(commandParams);
}
This should hopefully just leave you with calling the command 'callService' or however you are triggering it, you can configure the callbackMap / switch in code or possibly via parsed XML.
Hope this gets you started, and as I've just realized, is relevant?
EDIT:
Hi, just had another read through of the problem you are trying to solve, and I think you are describing a series of finite states, i.e. a state machine.
It seems as if roughly your sequences are FunctionState -> LoadingState -> ResultState. This might be a better general approach to managing loads of little async 'chains'.
Agreeing with enzuguri. You'll need lots of callbacks no matter what, but if you can define a single interface for all of them and shove the code into controller classes or a service manager and have it all in one place, it won't become overwhelming.
I know what you are going through. Unfortunately I have never seen a good solution. Basically asynchronous code just kind of ends up this way.
One solution algorithm:
static var resourcesNeededAreLoaded:Boolean = false;
static var shouldDoItOnLoad:Boolean = false;
function doSomething()
{
if(resourcesNeededAreLoaded)
{
actuallyDoIt();
}
else
{
shouldDoItOnLoad = true;
loadNeededResource();
}
}
function loadNeededResource()
{
startLoadOfResource(callBackWhenResourceLoaded);
}
function callBackWhenResourceLoaded()
{
resourcesNeededAreLoaded = true;
if(shouldDoItOnLoad)
{
doSomething();
}
}
This kind of pattern allows you to do lazy loading, but you can also force a load when necessary. This general pattern can be abstracted and it tends to work alright. Note: an important part is calling doSomething() from the load callback and not actuallyDoIt() for reasons which will be obvious if you don't want your code to become out-of-sync.
How you abstract the above pattern depends on your specific use case. You could have a single class that manages all resource loading and acquisition and uses a map to manage what is loaded and what isn't and allows the caller to set a callback if the resource isn't available. e.g.
public class ResourceManager
{
private var isResourceLoaded:Object = {};
private var callbackOnLoad:Object = {};
private var resources:Object = {};
public function getResource(resourceId:String, callBack:Function):void
{
if(isResourceLoaded[resourceId])
{
callback(resources[resourceId]);
}
else
{
callbackOnLoad[resourceId] = callBack;
loadResource(resourceId);
}
}
// ... snip the rest since you can work it out ...
}
I would probably use events and not callbacks but that is up to you. Sometimes a central class managing all resources isn't possible in which case you might want to pass a loading proxy to an object that is capable of managing the algorithm.
public class NeedsToLoad
{
public var asyncLoader:AsyncLoaderClass;
public function doSomething():void
{
asyncLoader.execute(resourceId, actuallyDoIt);
}
public function actuallyDoIt ():void { }
}
public class AsyncLoaderClass
{
/* vars like original algorithm */
public function execute(resourceId:String, callback:Function):void
{
if(isResourceLoaded)
{
callback();
}
else
{
loadResource(resourceId);
}
}
/* implements the rest of the original algorithm */
}
Again, it isn't hard to change the above from working with callbacks to events (which I would prefer in practise but it is harder to write short example code for that).
It is important to see how the above two abstract approaches merely encapsulate the original algorithm. That way you can tailor an approach that suites your needs.
The main determinants in your final abstraction will depend on:
Who knows the state of resources ... the calling context or the service abstraction?
Do you need a central place to acquire resources from ... and the hassle of making this central place available all throughout your program (ugh ... Singletons)
How complicated really is the loading necessities of your program? (e.g. it is possible to write this abstraction in such a way that a function will not be executed until a list of resources are available).
In one of my project, I build custom loader which was basically wrapper class. I was sending it Array of elements to load and wait for either complete or failed event(further I modified it and added priority also). So I didn't have to add so many handlers for all resources.
You just need to monitor which all resources has been downloaded and when all resources complete, dispatch a custom event-resourceDownloaded or else resourcesFailed.
You can also put a flag with every resource saying it is necessary or compulsory or not, If not compulsory, don't throw failed event on failing of that resource and continue monitoring other resources!
Now with priority, you can have bunch of file which you want to display first, display and continue loading other resources in background.
You can do this same and believe me you'll enjoy using it!!
You can check the Masapi framework to see if it fulfills your needs.
You can also investigate the source code to learn how they approached the problem.
http://code.google.com/p/masapi/
It's well written and maintained. I used it successfully in a desktop RSS client I developed with Air.
It worked very well assuming you pay attention to the overhead while loading too many resources in parallel.