Robotlegs 2 (beta): Flickr Image Gallery

Robotlegs 2 is easy to jump in to. From a basic standpoint, the MVCS concepts of how to build your applications remain the same. There are some significant differences in the semantic changes with Robotlegs 2 (beta), and that is what I am going to cover here. This post will go over the changes required to port the Robotlegs 1 Flickr Image Gallery demo. I’m not going to cover the basics of Robotlegs MVCS, so if you are looking for that, I’d recommend checking out the book! Also keep in mind that this is covering the beta release and some of the API is likely to change for the full release, but that shouldn’t be radical either.

The full source for this example can be found on Github.

Building Your Context

Robotlegs 2 introduces the ContextBuilder. Instead of extending the concrete Context class, you utilize the builder that will configure your application’s bundle(s).

Within the bundle (which is an implementation of the IContextBuilderBundle interface) you make use of the install method, which will add any additional bundles and supply any configs that go along with your bundle. Let’s take a look at the ClassicRobotlegsBundle.

In essence, we are extending this bundle. It provides the tools we are used to seeing in Robotlegs 1 and allows us to make a composite bundle on top of it with out own configuration as you can see in GalleryAppConfig.

The config files are fairly similar to what you might be used to seeing within the startup() method of a Robotlegs 1 Context. There is a significant advantage to this approach that you will quickly recognize if you’ve ever had to create a ModularSignalCommandCrazyAssCompositeContext in your application before. With the Builder->Bundle->Config approach you are able to compose your applications with specific tools and extensions.

Changes to Mediators

Mediators, for the most part, function as expected. With the supplied MediatorMapExtension, you will no longer find the onRegister() method. Instead you will overrided the initialize() method of the Mediator class.

Mourning the Death of Actor

Actor was always an odd concrete class to include in the Framework by default. It is gone in Robotlegs 2. For this port, I create a BaseActor class of my own to supply the functionality that I needed for my services and models.

So there you have it…

Check out the source if you’d like to dig in a little deeper. It shouldn’t be a radical departure from what you’ve come to like with Robotlegs. I’m really stoked about the framework architecture that allows for complete pluggable composition of features. This is huge, and should really open up some opportunities for creating a robust ala carte framework that suits you and your team’s specific needs.

  • Anonymous

    Couldn’t be more excited to tear into this Joel. Love what you’ve done with the place.

  • Adnan Doric

    Thank you for this, I’m actually testing RL2 and so far it is even better then the RL1 which was already best MVCS framework :)

    1) In your example you have the “UpdateGalleryCommand” which is only updating the model. Is there a reason you don’t modify the model directly from the “FlickrImageService” prior to dispatching the “GalleryEvent.GALLERY_LOADED” ?

    2) Do you recommend using AS3Signals for the communication and if yes, is the recommended way of implementing it creating an extension “SignalCommandMapExtension” in order to be able to map commands to signals ?

    And happy new year of course ! :)

  • http://joelhooks.com Joel Hooks

    This example was the first thing I ever made with Robotlegs. I didn’t update it much for this revamp. Outside of the unit tests. I couldn’t let those stand. If I rewrote it, I’d update the model directly.
    I really like signals on views. The signal command map is on my short list of items to address.

  • http://twitter.com/robpenner Robert Penner

    XMLImageService is so out-of-date it extends org.robotlegs.mvcs.Service. There’s a blast from the past.

  • http://twitter.com/robpenner Robert Penner
  • http://twitter.com/robpenner Robert Penner

    It’s a bit strange how GalleryAppConfig.configure(context:IContext) ignores the context parameter. Injecting things into an IContextConfig seems like cheating and missing the point. You could have at least used context.injector. Also, contextView is injected but not used.

  • http://twitter.com/robpenner Robert Penner

    Nitpicks aside, thanks for the article; really helpful highlighting core changes in Robotlegs 2.

  • http://joelhooks.com Joel Hooks

    Haha, nice catch. I didn’t bother to update it ^^

  • http://joelhooks.com Joel Hooks

    I don’t understand the “cheating and missing the point” comment. Configuration is composed from multiple sources. This app-specific config has dependencies that are located elsewhere, but are available for injection. Unless there is some esoteric rationale for not injecting in this fashion? It is easy and familiar; following the patterns Robotlegs uses elsewhere.

    Regarding ignoring the context, I don’t need the IContext. I need the injector. I don’t see why I would query the instance for a dependency when I can use the automated DI mechanism and access the dependency directly. If anything, I would call into question the need for the method injection of the IContext. The IContext is likely available for injection as well, no? This has nothing to do with my applications configuration and relates to the interface that I am required to conform to in a configuration.

    The contextView injection was an oversight. IntelliJ doesn’t mark vars “un-used” if they have metadata over them :/

  • http://twitter.com/robpenner Robert Penner


    I don’t need the IContext. I need the injector.

    Exactly. Why then did you make it an IContextConfig? Just so Robotlegs would execute it? Better off leaving it as a command. “Cheating and missing the point” refers to GalleryAppConfig implementing an interface it promptly ignores.

  • http://twitter.com/robpenner Robert Penner

    I suspect IContextConfig may need to be replaced/supplemented with something like IInjectorConfig which supplies the injector to configure().

  • http://joelhooks.com Joel Hooks

    The interface isn’t ignored, the IContext injected by the method is ignored. It *is* configuring a context in the body of the method expressed by the interface. I don’t see how it is better off in command. Because in this simple contrived example the dependency isn’t used? Meh.

  • http://joelhooks.com Joel Hooks

    where does that lead? IMediatorMapConfig ISomeCustomCommandMapImplementationConfig? 

    I am configuring a context. Outside of preferring not to use [Inject] for supplying dependencies, I don’t get the beef. It was easy to supply the injector, and makes sense in the context (lowercase c) of a Robotlegs application.

    I never once thought that IContextConfig was referring to manipulating or interacting with an instance of an IContext. I think the interface should lose the reference to the IContext and not imply that there is a need to manipulate an instance of the Context. What is the use case for that? It would be available for injection regardless…

    IConfig with a configure() method. It *is* essentially a command, but with a targeted purpose.

  • http://twitter.com/robpenner Robert Penner

    > “I am configuring a context.”

    You said “I don’t need the IContext. I need the injector.” Which one are you configuring?

    > “I never once thought that IContextConfig was referring to manipulating or interacting with an instance of an IContext.”

    Um… what? 

    public interface IContextConfig{ function configure(context:IContext):void;}

  • http://twitter.com/robpenner Robert Penner

    It’s about using the right tool for the job. In this example, an IContextConfig is not the right tool.

  • http://joelhooks.com Joel Hooks

    As a user, I want to “configure my context” – which I take to mean setting up my views, commands, and injections for a given Context.

    In this case I needed the injector. You suggested I throw in context.injector just because the IContext is available. I’d rather have all my dependencies lined up and provided in the same fashion and prefer to access it at the “top level” without digging into a class I’m not interested in.

    I’ve never had a use for manipulating a Context directly after startup().

  • http://joelhooks.com Joel Hooks

    It works, it makes sense, and provides an effective approach to configuring the actors within a given Context.

    I’ve looked at the other configs.

    const mediatorMap:robotlegs.bender.extensions.mediatorMap.api.IMediatorMap = context.injector.getInstance(IMediatorMapV2);

    this just doesn’t make any sense to dig through the context to get at the dependency that I really want.

    or

    public function configure(context:IContext):void { if (contextView) { context.logger.info(this, ‘Adding contextView to viewManager. Note: avoid this where performance is critical.’); viewManager.addContainer(contextView); } else { context.logger.warn(this, ‘ContextViewListenerConfig was installed, but the contextView is null. Consider removing this config.’); } }

    in every case the IContext dependency is utilized, it is simply to attach to some other dependency of the IContext.

    So, in this example the tool provided is being used appropriately, but perhaps it is the tool itself that is irritating you. 

    (code formatter failure)

  • Stray

    @Robert – IConfig has a bunch of stuff like parent, logger, app domain and dispatcher which all might be useful in configuring – not just the injector. 

    You can set as well as get some of these (eg contextView). We went with withConfig(expectsAClassThatImpsIConfig). We did um and ah about whether to simply expect people to make their own and use [PostConstruct] but prescription has been something people have liked when getting started.

    Maybe pick this up on the GitHub stuff around API for the context builder? I think Shaun has his head best wrapped around the deets on this issue.

    Good to have you back :)

    Stray

  • http://twitter.com/robpenner Robert Penner

    To be clear, I was never objecting to injecting the dependencies and operating on them. But in this case, a command would be a better tool for that.

  • http://twitter.com/robpenner Robert Penner

    > “IConfig has a bunch of stuff like parent…”

    Er, IContext. =) 

  • Stray

    Yes. Sorry – 10.30 pm here and been working on a building site most of the day. I can only grunt.

  • http://twitter.com/robpenner Robert Penner

    I responded to the ContextBuilder thread here: 
    https://github.com/robotlegs/robotlegs-framework/issues/32

  • http://joelhooks.com Joel Hooks

    It effectively is a command, but with a distinct purpose (configuring a context). We can agree to disagree I guess. I always thought the “kick off a Command with an event to string Commands and configure the context” was clunky and obtuse. This I like.

  • http://joelhooks.com Joel Hooks

    Actually, I think we agree. I like using a command. I think this is a command, it just has an extraneous argument being passed in to it’s execution method.

  • http://shaun.boyblack.co.za/blog/ shaun

    Also, Commands can only be executed IF a command map extension has been installed AND the builder and context are already configured.

  • http://shaun.boyblack.co.za/blog/ shaun

    Remember that the context is not fully initialized at those points, and all dependencies have not necessarily been mapped, so automated injection into those configs is not feasible.

  • http://shaun.boyblack.co.za/blog/ shaun

    Continued over at: https://github.com/robotlegs/robotlegs-framework/issues/32

  • http://twitter.com/robpenner Robert Penner

    Or you could *gasp* execute the command manually. =) Your point is taken, though. Maybe we should make it easier to execute commands then. Or make it easier to inject into functions in general. 

  • http://twitter.com/robpenner Robert Penner

    I agree with you on the last point. Obviously making custom Events is not my favourite thing, either.

  • http://twitter.com/robpenner Robert Penner

    > “this just doesn’t make any sense to dig through the context to get at the dependency that I really want.”

    I agree. The IContextConfigs currently in Robotlegs 2 have a lot of code like:

    context.injector.getInstance(IMediatorMap)

    Using the context to get the injector to pull out a dependency from the injector–this gets my Demeter-sense tingling. I feel it would be more straightforward to just inject the IMediatorMap into something and skip the pretext of “configuring the context”.

  • Denis

    Hi Joel, 

    Is flex popup mediating properly with RL2?

  • http://joelhooks.com Joel Hooks

    That’s a good question. Give it a try ;)

  • Denis

    Hi Joel, 

    I just tried and it does not work for me. 
    Here is wjat I am doing:
    1. In the AppConfig I have added following lines:
                mediatorMap.map(TestPopupButton).toMediator(TestPopupButtonMediator); //button on popup window            mediatorMap.map(TestPopupWindow).toMediator(TestPopupWindowMediator); // and popup window itself
    2. And here I open popup:
                var w:TestPopupWindow = new TestPopupWindow();            PopUpManager.addPopUp(w, FlexGlobals.topLevelApplication as DisplayObject);

    Am I missing something?

  • http://joelhooks.com Joel Hooks

    I don’t think so. I can’t investigate until this weekend. You can ask on the http://knowledge.robotlegs.org and might get a faster collaborator.