[Arp] Arp 3 Plans

gilles Bertrand gilles at b-u.be
Sat Jan 7 02:09:57 PST 2006


This looks great aral, ill read into it later but great thinking..

Gilles
Le 07-janv.-06 à 11:00, Aral Balkan a écrit :

> Hi all,
>
> I mentioned that I had begun to think about Arp 3 in the OSFlash  
> list. I
> also fleshed out ideas and code for the next version of the framework
> and wanted to share this with you for feedback, comments, etc. I've  
> been
> talking with Christophe about his work on extensions as well as  
> Muse and
> you will find elements of both in the plan below.
>
> The most important goal, as always, is for Arp3 to simplify things  
> even
> further.
>
> The plans below detail a system that will be as easy, if not easier to
> use that Ruby on Rails for Flash/Flex/RIA development. I'm personally
> really excited about its implications and look forward to your  
> thoughts.
>
> PS. Please note: None of the code below has been tested, it's a  
> complete
> brain-dump that I wrote into SePY.
>
> /*
>
> What is Arp?
>
> Arp is a simple yet powerful structural framework for creating Rich
> Internet Applications (RIAs) on the Flash Platform. Simplicity and DRY
> (Don't Repeat Yourself) are Arp's core tenets. Arp aims to boost
> developer productivity with code generation and introspection and
> integration with major application servers and databases. Whenever
> possible, Arp uses established Software Design Patterns. These include
> core patterns such as Controller, Business Delegate and Value Object.
> Arp favors convention over configuration -- this means that it uses
> intelligent defaults and naming conventions whenever possible. The
> ultimate aim is to bring the start-up time of a new RIA project  
> close to
> zero and encourage best practices, test-first development for RIAs on
> the Flash Platform.
>
> * * *
>
> What's New in Arp 3?
>
>
> Full-stack framework:
>
> Creating and working with RIAs on the Flash Platform is now a piece of
> cake with the integration of Ruby On Rails-type functionality.
>
> Arp 3 supports cross-platform code generation developed in PHP [Using
> Cake? CakeAMFPHP?], ActiveRecord-type database introspection, etc. for
> quickly getting up and running with your RIAs. Server-side support for
> the following languages is provided based on Flash Remoting:
>
>   * PHP (AMFPHP)
>   * J2EE (OpenAMF)
>   * Ruby (on Rails)
>
> ActiveRecord-style introspection is supported for the following  
> databases:
>
>   * MySQL
>   * PostgreSQL
>
>
> DRY:
>
> One of the core tenets of Arp is simplicity. Arp is even simpler in  
> its
> third incarnation and has gone DRY (Don't Repeat Yourself). This means
> that your ARP3 applications will have less code and thus lower risk.
>
>
> Convention over configuration:
>
> As part of DRY, Arp 3 favors convention over configuration. This was
> also a cornerstone of Arp 2, but we take it further here with the
> introduction of Requests.
>
>
> Requests:
>
> When a form in the view needs to make a request that will require
> business logic to be executed, it creates a new Request instance. A
> request is a special event. It bundles the necessary data for the
> request to be carried along with the request itself and specifies
> optional success and failure handlers to be notified.
>
> The success and failure handlers *only* carry out view logic.  
> Unlike Arp
> 2, no data handling, storages, update, etc. is done there.
>
>
> Custom Controllers are now optional:
>
> For most applications you will not need to create custom  
> controllers for
> your application or for external forms. The new, DRY Arp's base
> controller class, along with the introduction of Requests will handle
> all the hard work for you.
>
>
> Explicit Commands are now optional:
>
> The new base Controller class and Requests make the explicit  
> declaration
> of Commands redundant for most cases. Of course, if you would rather
> implement explicit Commands (eg. to use as part of a Memento  
> pattern to
> implement Undo/Redo), you can.
>
>
> Business Delegates are now a central part of the framework:
>
> At the very basic implementation, a Business Delegate includes a
> reference to a remote service to which Requests will be proxied.
>
> If you would rather carry out business logic on the client side in
> response to a request, just implement the necessary method in the
> Business Delegate and it will get called in place of the remote  
> service
> (if any).
>
> In the most advanced, you can use a map to specify multiple remote
> services for methods and mix in local method implementations too.
>
>
> Data Binding and the Model:
>
> The model is updated from the Business Delegate and data bindings  
> on the
> View [based on Christophe's code] (along with custom formatter
> functions, etc.) carry out view updates automatically.
>
>
> External Forms:
>
> Easy workflow for using external forms and registering them and their
> controllers with the main application.
>
>
> Shared Libraries:
>
> Supports transparent use of shared libraries.
>
>
> Integrated unit testing:
>
> Arp 3 includes the open source ASUnit unit testing framework and
> advocates test-first development.
>
>
> Integrated logging:
>
> Arp 3 includes the open source LuminicBox logger for logging.
>
>
> IDE support:
>
> Support and documentation for creating Arp 3 projects is provided for
> the following IDEs:
>
>   * Eclipse
>   * FlashDevelop <-- Do we need anything special? (No?)
>   * SePY <-- Do we need anything special? (No?)
>   * Others????
>
>
> Compatibility:
>
> Works with Flash, Flex 1.5 and Flex 2, ActionScript 2 (AS2) *and*
> ActionScript 3 (AS3). Use the same workflow regardless of which
> technology you're using. Applications based on Arp 3 are very easy to
> port between these technologies. (Note: Since Flex 2 and AS3 are
> currently in Alpha, these features may change in the future in line  
> with
> Adobe's code changes in future alphas, betas and releases.)
>
> */
>
>
> //////////////////////////////////////////////////////////////////////
> //
> //
> // Arp 3 Base Application Class
> //
> //
> //////////////////////////////////////////////////////////////////////
>
> class org.osflash.arp3.Application
> {
>     ////////////////////////////////////////////////////////////////// 
> ////
>     //
>     // Method: registerScreen()
>     //
>     // Registers an external screen with its Controller so that the
>     // Controller can listen for System Events on the screen and
>     // map them to Commands.
>     //
>     // Also calls a handler on the Application form so that it can
>     // register to listen for View Events.
>     //
>     ////////////////////////////////////////////////////////////////// 
> ////
>     public function registerScreen ( screenName:String,  
> screenRef:Object )
>     {
>         Log.info ("Registering screen: " + screenName);
>
>         //
>         // Register the screen with its Controller
>         //
>         var ControllerClass = findControllerClass( screenName );
>
>         // Remove the controller if it has already been created
>         // since if we go back to a screen, the screen refuses
>         // to display correctly unless this is done.
>         delete ControllerClass["inst"];
>
>         var screenController:Object = ControllerClass.getInstance();
>         screenController.registerScreen ( screenRef );
>
>         //
>         // Call handler on Application form. If you want to listen for
>         // View Events on the external screen, that's the place to do
>         // it. The handler is named onRegisterScreenameScreen
>         // (eg. onRegisterLoginScreen.)
>         //
>         var localHandler:Function = this [ "onRegister" + screenName +
> "Screen" ];
>         localHandler.apply ( this, [ { target: screenRef } ] );
>     }
>
>     ////////////////////////////////////////////////////////////////// 
> ////
>     //
>     // Method: unRegisterScreen()
>     //
>     // Removes the controller for the screen so that the screen can be
>     // re-created successfully in the future.
>     //
>     ////////////////////////////////////////////////////////////////// 
> ////
>     public function unRegisterScreen ( screenName:String,  
> screenRef:Object )
>     {
>         Log.info ("Un-registering screen: " + screenName);
>
>         var ControllerClass:Object = findControllerClass 
> ( screenName );
>         var screenController:Object = ControllerClass.getInstance();
>
>         // Remove the controller since the screen is being removed -
>         // this allows us to re-open popup windows without issue.
>         //screenController.unRegisterScreen ( screenRef );
>         delete ControllerClass["inst"];
>
>         var localHandler:Function = this [ "onUnRegister" +  
> screenName +
> "Screen" ];
>         localHandler.apply ( this, [ { target: screenRef } ] );
>     }
>
>     ////////////////////////////////////////////////////////////////// 
> ////
>     //
>     // Group: Private methods
>     //
>     ////////////////////////////////////////////////////////////////// 
> ////
>
>     private function findControllerClass( screenName:String ):Object
>     {
>         //
>         // The package string must be declared in the projectPackage
> property.
>         // It can contain any number of packages. However, the
> Controller class
>         // *must* be in a package called "control"
>         //
>         var packageExploded:Array = mProjectPackage.split(".");
>         var numPackages:Number = packageExploded.length;
>         var packageRef:Object = _global;
>         for ( var i:Number = 0; i < numPackages; i++ )
>         {
>             packageRef = packageRef [ packageExploded [ i ] ];
>         }
>         return packageRef["control"][ screenName + "Controller" ];
>     }
>
> }
>
>
> //////////////////////////////////////////////////////////////////////
> //
> //
> // Arp 3 Base Controller Class
> //
> //
> //////////////////////////////////////////////////////////////////////
>
> class org.osflash.arp3.Controller
> {
>
>     private var inst:Controller;
>
>     ////////////////////////////////////////////////////////////////// 
> ////
>     //
>     // Private constructor - Singleton - Implement getInstance()
>     // abstract method in subclass.
>     //
>     ////////////////////////////////////////////////////////////////// 
> ////
>     private function Controller ()
>     {
>         // DO NOT CALL WITH new(). Singleton.
>     }
>
>
>     ////////////////////////////////////////////////////////////////// 
> ////
>     //
>     // Registers the view with the controller
>     //
>     ////////////////////////////////////////////////////////////////// 
> ////
>
>     public function registerView ( view:Object )
>     {
>         mView = view;
>
>         registerRequests();
>     }
>
>
>     ////////////////////////////////////////////////////////////////// 
> ////
>     //
>     // Registers to listen for requests on the view
>     //
>     ////////////////////////////////////////////////////////////////// 
> ////
>
>     private function registerRequests()
>     {
>         for ( var i:String in mView )
>         {
>             if (i.substring(0, 7) == "request" )
>             {
>                 mView.addEventListener ( i, this );
>             }
>         }
>     }
>
>
>
>
> ////////////////////////////////////////////////////////////////////// 
> //////
>     //
>     // Handle event instances
>     //
>
> ////////////////////////////////////////////////////////////////////// 
> //////
>     function handleEvent ( eventObj )
>     {
>         //
>         // handleEvent() is a generic event handler that gets called
> whenever
>         // an event is heard.
>         //
>
>         // Get the name of the system request
>         var requestMethodName:String = eventObj.type;
>
>         // Strip the request name while staying compatible with Arp 2
> (in which the
>         // system event would not have a "request" prefix.
>         requestMethodName = substring(requestMethodName, 0, 7) ==
> "request" ? substring(requestMethodName, 7) : requestMethodName;
>
>         // Reference to the view for this request
>         var view:Object = eventObj.target;
>
>         // Reference to the business delegate
>         var requestBusinessDelegate:Function =  
> eventObj.businessDelegate;
>
>         // Reference to the data
>         var data:Object = eventObj.data;
>
>         //
>         // Does an explicit Command exist to handle this request?
>         //
>         // Note: This behavior is different from Arp 2: You *will not*
> get an error
>         // if you forget to add a command manually to your Controller.
>         //
>         var commandNameToCheck:String = requestMethodName + "Command";
>         if ( commands [ commandNameToCheck ] != undefined )
>         {
>             //
>             // Yes: Use the explicit command
>             //
>
>             // Create a new command
>             var theCommand = new commands [ commandNameToCheck ] ();
>
>             // Execute the command
>             theCommand.execute( view );
>         }
>         else
>         {
>             //
>             // No: Use automatic mapping to call the correct business
>             //     method on the Business Delegate
>             //
>             requestBusinessDelegate [ requestMethodName ].apply (
> requestBusinessDelegate, [ view, data ] );
>         }
>     }
>
>
> ////////////////////////////////////////////////////////////////////// 
> //////
>     //
>     // Singleton accessor method: If you override the base Controller
> class,
>     // make sure your overwrite this static function with one that
> generates
>     // an instance of your subclass.
>     //
>
> ////////////////////////////////////////////////////////////////////// 
> //////
>     public static function getInstance ()
>     {
>         if ( undefined == inst ) inst = new Controller();
>         return inst;
>     }
>
> }
>
>
>
> //////////////////////////////////////////////////////////////////////
> //
> //
> // Arp 3 Base Business Delegate
> //
> //
> //////////////////////////////////////////////////////////////////////
> class org.osflash.arp3.BusinessDelegate
> {
>
>
> ////////////////////////////////////////////////////////////////////// 
> //////
>     //
>     // Use the __resolve function to get notification of methods  
> that don't
>     // exist. We try to handle these requests with automatic  
> proxying to
>     // a server-side service if one is provided.
>     //
>     // For business methods that have client-side implementations,  
> __resolve
>     // will *not* get called and thus they have highest precedence.
>     //
>
> ////////////////////////////////////////////////////////////////////// 
> //////
>     function __resolve ( functionName )
>     {
>         // Does a specific service mapping exist for this method?
>         // TODO
>
>             // Yes: Proxy the method call to the service and register
>             //      the default success and failure handlers on the  
> view
>             //      TODO
>
>         // Does a global service declaration exist for this Business
> Delegate?
>         // TODO
>
>             // Yes: Proxy the method call to the service and register
>             //      the default success and failure handlers on the  
> view
>             //      TODO
>
>             // No: Raise an error as no explicit business method  
> exists and
>             //     neither does a remote service proxy.
>     }
> }
>
> / 
> *********************************************************************/
>
> //////////////////////////////////////////////////////////////////////
> //
> //
> // Sample Application Class
> //
> //
> //////////////////////////////////////////////////////////////////////
> class com.somedomain.my.Application extends org.osflash.arp3.Form
> implements org.osflash.arp3.IView
> {
>     //
>     // Instance variables (members)
>     //
>     var mController:Controller;
>
>     //
>     // Declare requests.
>     //
>     // Controller subclasses will use these to automatically register
> themselves to listen for requests.
>     // The naming convention states that request declarations must  
> begin
> with "request". The base Controller
>     // class uses for...in (AS2) and introspection (AS3) to map these.
>     //
>     var requestA;
>     var requestB;
>     var requestOtherOne;
>
>
>     ////////////////////////////////////////////////////////////////// 
> ////
>     //
>     // Constructor.
>     //
>     // Do *not* place code here that relies on child components or  
> forms.
>     //
>     ////////////////////////////////////////////////////////////////// 
> ////
>     function Application()
>     {
>         // Nothing yet.
>     }
>
>
>     ////////////////////////////////////////////////////////////////// 
> ////
>     //
>     // viewInit() - A common initialization method that will be called
>     //              at onLoad() in Flash and onChildrenCreated() in  
> Flex.
>     //
>     ////////////////////////////////////////////////////////////////// 
> ////
>     function viewInit()
>     {
>         mController = ApplicationController.getInstance();
>         mController.registerView ( this );
>     }
>
>
>
> //////////////////////////////////////////////////////////////////////
>     //
>     // Request Example
>     //
>     ////////////////////////////////////////////////////////////////// 
> ////
>
>     // A View method
>     function someMethod()
>     {
>         // Get the value object
>         var valueObject = getValueObject();
>
>         // Make a system request: A request is really just an event by
> any other name but uses a naming convention, has a specific use,  
> bundles
> necessary data and and has expectations associated with it.
>         var myRequest:Request = new Request  
> ( "requestACommandOnModel",
> valueObject );
>     }
>
>
>
> //////////////////////////////////////////////////////////////////////
>     //
>     //
>     // Event Handlers
>     //
>     //
>
> //////////////////////////////////////////////////////////////////////
>
>
> //////////////////////////////////////////////////////////////////////
>     //
>     // Requests
>     //
>
> //////////////////////////////////////////////////////////////////////
>
>     // Success
>     function requestASuccess ()
>     {
>         // Will be called if request A completes successfully
>     }
>
>     // Failure
>     function requestAFailure ()
>     {
>         // Will be called if request A fails
>     }
>
>
>
> //////////////////////////////////////////////////////////////////////
>     //
>     // External Form Registrations
>     //
>     // To listen for events on external forms, create methods here  
> using
> the following naming convention:
>     //
>     // onRegister[Screename]Screen
>     // (eg. onRegisterLoginScreen is the place to add event listeners
> for the Login screen. The method
>     //  will be called when the external form is loaded, after its
> controller has been registered.)
>     //
>     ////////////////////////////////////////////////////////////////// 
> ////
>
>     //
>     // None
>     //
>
> }
>
>
>
> //
> // THIS IS ACTUALLY NOT NECESSARY ==>
> //
>
> //////////////////////////////////////////////////////////////////////
> //
> //
> // My Application's Controller Class
> //
> //
> //////////////////////////////////////////////////////////////////////
> class ApplicationController extends org.osflash.arp3.Controller
> {
> }
>
> //
> // <== THIS IS ACTUALLY NOT NECESSARY
> //
>
>
>
> //////////////////////////////////////////////////////////////////////
> //
> //
> // A Sample Business Delegate Class on My Application
> //
> //
> //////////////////////////////////////////////////////////////////////
> class SomeBusinessDelegate
> {
>     import org.osflash.arp3.services.IRemoteService;
>
>     import org.osflash.arp3.services.RemotingService;
>     import org.osflash.arp3.services.WebService;
>     import org.osflash.arp3.services.XmlService;
>
> `    //
>     // (Optional) If the remoteService variable is defined, it acts  
> as the
>     // global remote service for this business delegate. If no  
> remoteService
>     // is defined, the base Business Delegate class will check if a
>     // remoteServiceMap is defined and use the method to service  
> mappings in
>     // that strucuture. If that doesn't exist either, you must  
> implement
>     // all the business methods locally on the client.
>     //
>     // The precedence rules are as follows:
>     //
>     // Local business method -> Method defined in remoteServiceMap ->
> global remote service
>     //
>     // Thus if a method is defined locally, it will override any  
> custom
>     // mapping or global remote service mapping (ie., the local  
> method will
>     // be executed.)
>     //
>     var remoteService:IRemoteService = RemotingService.getInstance();
>
>     //
>     // (Optional) If multiple methods have to use different remote  
> services,
>     // you need to specify a remoteServiceMap. It is kept in this
>     // instance variable. The base Business Delegate class will call
>     // the createRemoteServiceMap() method to initialize this object.
>     //
>     var remoteServiceMap:Object;
>
>     //
>     // (Optional) Create Remote Service Map, to proxy different  
> business
>     // methods to different services (this should be very useful when
>     // migrating from, say, a legacy LoadVars or XML-based system to
>     // Remoting, allowing incremental switchover on a per-method  
> basis.)
>     //
>     var remotingService:RemotingService =  
> RemotingService.getInstance();
>     var webService:WebService = WebService.getInstance();
>     var xmlService:XmlService = XmlService.getInstance();
>
>     function createRemoteServiceMap ()
>     {
>         methodTable =
>         {
>             remotingService:
>             [
>                 "someMethod"
>             ],
>
>             webService:
>             [
>                 "aMethod", "anotherMethod", "yetAnotherMethod"
>             ],
>
>             xmlService:
>             [
>                 "anXmlServiceMethod"
>             ]
>         };
>     }
>
>     //
>     // Local methods
>     //
>     function aLocalBusinessMethod ( parameters )
>     {
>         // Business logic
>     }
> }
>
>
>
>
> _______________________________________________
> Arp mailing list
> Arp at ariaware.com
> http://ariaware.com/mailman/listinfo/arp_ariaware.com




More information about the Arp mailing list