d2w stateful controllers

25
D2W Stateful Controllers Fuego Digital Media QSTP-LLC Daniel Roy

Upload: wo-community

Post on 19-May-2015

417 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: D2W Stateful Controllers

D2W Stateful ControllersFuego Digital Media QSTP-LLCDaniel Roy

Page 2: D2W Stateful Controllers

• Using WebObjects since 2004

• Work with government agencies, private companies and various foundations globally

• Fuego Content Management System & Fuego Frameworks

• Presence in North America and Middle East

Fuego History

Page 3: D2W Stateful Controllers
Page 4: D2W Stateful Controllers

• 42% of community uses D2W

• “D2W is to WebObjects apps as the assembly line is to automobiles...you provide customization directions (D2W rules) to the assembly line (D2W) to build your end products (WOComponent pages).”

• Flow is controlled by delegates that manage the actions and direction of the application

• Use ERDBranchDelegate to define the actions displayed on the page by rules or via introspection

Direct To Web

Page 5: D2W Stateful Controllers

The Basics

query select edit save

Page 6: D2W Stateful Controllers

Start/Stop

Confirm

Edit

ConfirmConfirm

saveForLater

Save

Delete

edit

Edit CommentreadyToSubmit*

readyToSubmit*

saveAndSubmit

Submit

delete*

confirmDeletion

approveDeletion

confirm

edit*

List Expense Claims

selectcancel

Notes:- Cancel is present on all pages, but onlyshown for first.- Any branches with * are optional and are shown based on business logic- Any branches with the same name, are the same page configuration, but with different branches

Needs to enter comment?

NOEdit Comment

YES

WHAT?

WHAT???

??

Page 7: D2W Stateful Controllers

Back in the day...

• Without Project Wonder, rely on nextPageDelegate and nextPage for navigation

• nextPageDelegate is checked first, and if found call nextPage()

• without nextPageDelegate, nextPage() is called on the D2WPage component directly

• Single class between each page

Page 8: D2W Stateful Controllers

Next Page Delegate

D2WPage NPD(select)

D2WPage NPD(edit)

D2WPage NPD(query)

...

Page 9: D2W Stateful Controllers

Plain WebObjects Controller Sample Code

public class ManageUserEditNextPageDelegate implements NextPageDelegate {

public WOComponent nextPage(WOComponent sender) { NSArray<User> selectedObjects = ((ERDPickPageInterface) sender).selectedObjects(); User currentUser = selectedObjects.get(0); EditPageInterface epi = (EditPageInterface) D2W.factory().pageForConfigurationNamed("ManageUsers_User_Edit_PC", sender.session()); epi.setNextPageDelegate(new ManageUserSaveNextPageDelegate()); epi.setObject(currentUser); return (WOComponent) epi; }

}

Page 10: D2W Stateful Controllers

Enter Project Wonder

• ERDBranchDelegate to the rescue!

• Now you can show multiple branch choices for a page

• Pull choices from D2W context in the method branchChoicesForContext(), using the D2W rule key “branchChoices”

• Or, use introspection to find all methods that take a single WOComponent as parameter

Page 11: D2W Stateful Controllers

ERDBranchDelegate

D2WPage ERDBD

D2WPage(search)

D2WPage(add)

D2WPage(cancel)

ERDBD

D2WPage(save)

D2WPage(cancel)

D2WPage(add)

Page 12: D2W Stateful Controllers

ERDBranchDelegate Sample Code

public class ManageUserControllerSelectBranchDelegate extends ERDBranchDelegate {

// Return an edit page for a single selected row in the pick page public WOComponent edit(WOComponent sender) { NSArray<User> selectedObjects = ((ERDPickPageInterface) sender).selectedObjects(); User currentUser = selectedObjects.get(0); EditPageInterface epi = (EditPageInterface) D2W.factory().pageForConfigurationNamed("ManageUsers_User_Edit_PC", sender.session()); epi.setNextPageDelegate(new ManageUserControllerSaveBranchDelegate()); epi.setObject(currentUser); return (WOComponent) epi; }

// From the selected items in the pick page, perform a delete public WOComponent delete(WOComponent sender) { NSArray<User> users = ((ERDPickPageInterface) sender).selectedObjects(); for (User user : users) { user.delete(); } if (users.count() > 0) { // Assuming all in same EC. users.get(0).editingContext().saveChanges(); } return sender.pageWithName("PageWrapper"); }}

Page 13: D2W Stateful Controllers

But wait...

• Must still set and get the objects on each page

• Lots of classes to write

• Why not reuse the same delegate?

Page 14: D2W Stateful Controllers

Benefits of Delegate Reuse

• Enter the controller/delegate many times (one controller for many pages)

• Reuse the stored state in editing context

• Support one or many flows within the single class

• Define the visible branches using rules

Page 15: D2W Stateful Controllers

Re-entrant Branch Delegate

D2WPageBD

queryPage

search()

edit()

editPage

selectPage

save()

Page 16: D2W Stateful Controllers

Is ERDBranchDelegate Enough?

• Yes....but...no.

• Branch choices are defined in the rules, but can lead to a complex ruleset depending on the business logic

• Introspection on the ERDBranchDelegate returns all the methods in the class

Page 17: D2W Stateful Controllers

Hello (Stateful) World!

• FDStatefulController is a re-entrant branch delegate extending ERDBranchDelegate

• Better separation of MVC

• Override branchChoicesForContext(D2WContext context)

• Reuse page configurations (define the PC in code)

• store state between pages

• editing context

• EOs, etc in subclasses

Page 18: D2W Stateful Controllers

branchChoicesForContext

public class StatefulController extends ERDBranchDelegate { private NSArray<?> branches; private EOEditingContext editingContext;

public NSArray<?> getBranches() { return branches; }

public void setBranches(NSArray<?> branches) { this.branches = branches; } public EOEditingContext editingContext() { if (this.editingContext == null) { this.editingContext = ERXEC.newEditingContext(); } return this.editingContext; }

public NSArray branchChoicesForContext(D2WContext context) { NSArray choices = getBranches(); if (choices == null) { branches = (NSArray) context.valueForKey(BRANCH_CHOICES); } else { NSMutableArray translatedChoices = new NSMutableArray(); for (Iterator iter = choices.iterator(); iter.hasNext();) {

... rest of method continues the same as ERDBranchDelegate

Page 19: D2W Stateful Controllers

StatefulController Code// Return an edit page for a single selected row in the pick pagepublic WOComponent edit(WOComponent sender) { NSArray<User> selectedObjects = ((ERDPickPageInterface) sender).selectedObjects(); User currentUser = selectedObjects.get(0); setBranches(new NSArray("save")); EditPageInterface epi = (EditPageInterface) D2W.factory().pageForConfigurationNamed("ManageUsers_User_Edit_PC", sender.session()); epi.setNextPageDelegate(this); epi.setObject(currentUser); return (WOComponent) epi;}

public WOComponent save(WOComponent sender) { editingContext().saveChanges(); return sender.pageWithName("PageWrapper");}

// From the selected items in the pick page, perform a deletepublic WOComponent delete(WOComponent sender) { setBranches(null); NSArray<User> users = ((ERDPickPageInterface) sender).selectedObjects(); ERXUtilities.deleteObjects(editingContext(), users); return save(sender);}

Page 20: D2W Stateful Controllers

Page Utility Methods

Interaction

editPage

queryPage

listPage

inspectPage

messagePage

pickPage

selectPage

Utility

editingContext()

nestedEditingContext

save()

Page 21: D2W Stateful Controllers

Utility Method Examples

protected EditPageInterface editPage(Session session, String pageConfigurationName, EOEnterpriseObject enterpriseObject) { EditPageInterface epi = (EditPageInterface) pageForConfigurationNamed(pageConfigurationName, session); epi.setNextPageDelegate(this); epi.setObject(enterpriseObject); return epi;}

protected WOComponent pageForConfigurationNamed(String pageConfigurationName, Session session) { WOComponent component = D2W.factory().pageForConfigurationNamed(pageConfigurationName, session); if (component instanceof D2WPage) { ((D2WPage) component).setNextPageDelegate(this); } return component;}

Page 22: D2W Stateful Controllers
Page 23: D2W Stateful Controllers

Summary

• Re-entrant controller provides code reusability

• Specify branch choices programmatically

• Storing the editing context allows easy access to associated objects during flows and encourages a single point of save

• Utility and convenience methods allow for simple setup and development of customized flows

Page 25: D2W Stateful Controllers

Q&A