Hidden Treasures in Project Wonder


Published on

Published in: Technology, Design
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Hidden Treasures in Project Wonder

  1. 1. Hidden Treasures inProject WonderSpirit of Mike SchragWhereabouts UnknownChanneled By Chuck HillGlobal Village Consulting
  2. 2. What You See• Mike’s Step 1: Look at every damn method in Wonder.• Mike’s Step 1a: Seriously. Every one.• Mike’s Step 2: “Cool” = Chosen
  3. 3. What You Get• Notification of existence• Nothing in-depth
  4. 4. Type-safe pageWithName• <T extends WOComponent> T pageWithName(Class<T> componentClass)• ERXApplication, ERXDirectAction, ERXComponent• less typing• refactoring updates them• compiler errors for speeling errors
  5. 5. Type-safe pageWithNameold wayMyPage page = (MyPage)pageWithName(“MyPage”);new wayMyPage page = (MyPage)pageWithName(MyPage.class.getName());cool wayMyPage page = pageWithName(MyPage.class);
  6. 6. IVersionManager• better control of static resource caching • infinite expiration in Apache • change resource url when resource changes• pluggable versioning schemes • “default” = WebObjects default • “properties” = specify version numbers in properties • your own
  7. 7. PropertiesVersionManagerpropertieser.extensions.ERXResourceManager.versionManager=propertieser.extensions.ERXResourceManager.versionManager.default=10er.extensions.ERXResourceManager.versionManager.bundleName.resourceName=20produces/WebObjects/YourApp.woa/WebServerResources/awesomeImage.png?10/WebObjects/bundleName/WebServerResources/resourceName?20
  8. 8. ERXDirectAction / log4jurl/wa/ERXDirectAction/log4j?pw=somepwpropertieser.extensions.ERXLog4JPassword=somepw
  9. 9. ERXDirectAction / log4j
  10. 10. ERXDirectAction / eoAdaptorDebuggingurl/wa/ERXDirectAction/eoAdaptorDebugging?debug=on&pw=somepw/wa/ERXDirectAction/eoAdaptorDebugging?debug=off&pw=somepwpropertieser.extensions.ERXEOAdaptorDebuggingPassword=somepw
  11. 11. ERXMainRunner• initializes all of Wonder• runs “main” method inside of an Application context• java -classpath ... er.extensions.appserver.ERXMainRunner -mainClass YourClass
  12. 12. ERXApplication._rewriteURL• Pretty URLs• One generator method to rule them all
  13. 13. ERXApplication._rewriteURL (simple method)propertieser.extensions.ERXApplication.replaceApplicationPath.pattern= ↵/cgi-bin/WebObjects/YourApp.woaer.extensions.ERXApplication.replaceApplicationPath.replace= ↵/yourappproduceshttp://server.com/yourapp/wa/defaultapache rewrite ruleRewriteRule ^/yourapp(.*)$ /cgi-bin/WebObjects/YourApp.woa$1 [PT,L]
  14. 14. ERXApplication._rewriteURL (complex method)Application subclass@Overridepublic String _rewriteURL(String url) { return convertURLWithFancyRegexOrSomething(url);}apache rewrite rulerewrite rule has to be an inverse of your _rewriteURL implementation
  15. 15. ERXRedirect• drop-in replacement for WORedirect• can redirect to a component instance rather than a direct action• generates document.location.href=... in Ajax request• https support• api for setting query parameters
  16. 16. ERXRedirectpublic WOActionResults doSomething() { ERXRedirect redirect = pageWithName(ERXRedirect.class); NextPage nextPage = pageWithName(NextPage.class); nextPage.setState(someStateFromThisPage); redirect.setComponent(nextPage); return redirect;}
  17. 17. ERXSession.useSecureSessionCookies• secure cookies are only sent across https requests• wosid and woinst are not secure cookies by default (and thus vulnerable to sniffing off a non-https url)
  18. 18. ERXSession.useSecureSessionCookies@Overridepublic boolean useSecureSessionCookies() { return true;}orer.extensions.ERXSession.useSecureSessionCookies=true
  19. 19. ERXFlickrBatchNavigation• WOBatchNavigationBar looks like ass• ERXFlickrBatchNavigation does not• Drop-in replacement of WOBatchNavigationBar
  20. 20. ERXDataHyperlink• Like WOHyperlink but with object-based attribute passing• Automagically calls accessor methods on pageName component• Safe ... doesn’t leak data to user• An example will make more sense
  21. 21. ERXDataHyperlinkPersonList page<wo:ERXDataHyperlink pageName=”PersonEdit” ↵ person=”$currentPerson”> edit person</wo:ERXDataHyperlink>PersonEdit pagepublic class PersonEdit extends WOComponent { ... public void setPerson(Person person) { _person = person; }}
  22. 22. ERXInlineTemplate• Generate a WOComponent on-the-fly• Generate a WOComponent from a database (i.e. a CMS)• Take over the world?
  23. 23. ERXInlineTemplatebasic<wo:ERXInlineTemplate html=”$someHtmlString” wod=”$someWodString”/>(using woognl doesn’t require a wod)cache generated component<wo:ERXInlineTemplate html=”$someHtmlString” wod=”$someWodString” cacheKey=”MyCacheKey” cacheVersion=”$computedVersionObject”/>(when cacheVersion changes, regenerate)
  24. 24. ERXWOComponentContent / ERXWOTemplate• WOComponentContent but with multiple content areas• example: a DialogComponent has a “title” area and a “content” area
  25. 25. ERXWOComponentContent / ERXWOTemplateDialogComponent<div> <div><wo:ERXWOComponentContent templateName=”title”/></div> <div><wo:ERXWOComponentContent templateName=”content”/></div></div>CallingComponent<wo:DialogComponent> <wo:ERXWOTemplate templateName=”title”> this is the title and you can put real components in here </wo:ERXWOTemplate> <wo:ERXWOTemplate templateName=”content”> this is the content of the dialog </wo:ERXWOTemplate></wo:DialogComponent>
  26. 26. ERXLoremIpsumGenerator• sometimes you just need fake content (test cases, load tests, mockups)• “Lorem ipsum dolor sit amet, ...”• ERXLoremIpsumGenerator.paragraph(3) = 3 paragraphs• ERXLoremIpsumGenerator.sentence(1) = 1 sentence• ERXLoremIpsumGenerator.words(10) = 10 words
  27. 27. Captchas and Spam Checks• ERXSimpleSpamCheck (ERExtensions.framework) sets a hidden field with javascript• ERReCaptcha (ERCaptcha.framework) reCAPTCHA wrapper (http:// www.google.com/recaptcha)• ERAkismet (ERCaptcha.framework) Akismet wrapper (http://akismet.com); spam checks blog comments
  28. 28. Captchas and Spam Checks• calls validationFailedWithException on failure• sets “valid” binding accordingly
  29. 29. Captchas and Spam Checks<wo:form> <wo:ERXSimpleSpamCheck /> <wo:WOTextField value=”$firstName” /> <wo:WOSubmitButton action=”$doSomething” /></wo:form>
  30. 30. ERXRssPage• quickly produce RSS feeds• feedTitle, feedUrl, feedDescription• list : list of items to show in the feed• item : repetition item• itemGuid, itemTitle, itemLink, itemPubDate, itemAuthor• description from WOComponentContent
  31. 31. ERXRssPage<wo:ERXRssPage feedTitle=”RSS of People” feedUrl=”http://yourhost.com” feedDescription=”This is my list of people!” list=”$people” item=”$person” itemGuid=”$person.primaryKey” itemTitle=”$person.fullName” itemLink=”$someURLToThePerson” itemPubDate=”$person.creationDate” />
  32. 32. ERXWORepetition• WORepetition relies on repetition item indexes• changing item order = you just clicked “delete” on the wrong row ... whoops• uses key instead of index• small risk of collision, but unlikely in tests (use uniqueKey binding to prevent)
  33. 33. ERXWORepetitionproperties# use hash codes of objects instead of indexer.extensions.ERXWORepetition.checkHashCodes=true# throw an exception if a match isn’t founder.extensions.ERXWORepetition.raiseOnUnmatchedObject=trueunique keys# use item PKs instead of hash codes<wo:ERXWORepetition uniqueKey=”$person.primaryKey”> ...
  34. 34. External Services• ERXGoogleSpell.correct(String) • spelling correction like Google’s “did you mean”• ERXYahooContentAnalysisService.termExtra ction(..) • extracts important terms from text • useful for guessing ERTaggable tags• Access keys required, read Javadoc for details
  35. 35. ERXEnterpriseObjectCache• caches EO’s based on a keypath• optionally filter with qualifier (dynamically updates!) example: two caches -- published=true, published=false• optional timed expiration
  36. 36. ERXEnterpriseObjectCache• use this constructor and shouldRetainObjects=true! public ERXEnterpriseObjectCache( String entityName, String keyPath, EOQualifier qualifier, long timeout, boolean shouldRetainObjects, boolean shouldFetchInitialValues)
  37. 37. ERXEnterpriseObjectCache# cache any CMSPage objects by their “name” key# that are published=true# expire them after 60 secondsERXEnterpriseObjectCache cache = new ERXEnterpriseObjectCache( CMSPage.ENTITY_NAME, CMSPage.NAME_KEY, CMSPage.PUBLISHED.isTrue(), 60 * 1000);EOEditingContext editingContext = ERXEC.newEditingContext();CMSPage homePage = cache.objectForKey(editingContext, “HomePage”);homePage.setPublished(false);editingContext.saveChanges();# published = false, so it is dynamically removed from the cache
  38. 38. ERXEOControlUtilities• ERXEOControlUtilities.convertEOtoGID / convertGIDtoEO recursively convert data structures from EO’s to GID’s (NSDictionary of String to NSArray of EO’s becomes NSDictionary of String to NSArray of GID’s, etc) and the corresponding inverse method
  39. 39. ERXEOControlUtilities• ERXEOControlUtilities.eoEquals compare two EO’s, returning true if their GID’s match, regardless of the EOEditingContext that contains both of them• ERXEOControlUtilities.aggregateFunctionWith Qualifier perform MIN/MAX/AVG/etc database functions on attributes of an entity without writing custom SQL
  40. 40. Automatic Batch Faulting• Common problem: Fetch array of Person objects, show them in a table, for each row, show the person.company().name()• Common solution: Manually batch fetch “company.name” on the Person objects.• Bad-ass solution: er.extensions.ERXDatabaseContextDelegate. autoBatchFetchSize=50• Automatically batch fetches faulted relationships on all EO’s that were fetched from the same query
  41. 41. Automatic Batch FaultingNSArray<Person> people = ec.objectsWithFetchSpecification(fspec);# this automatically faults all the companies for# the person objects in the “people” array (up to# your 50 max specified in the property)Company comp = people.objectAtIndex(0).company();String name = comp.name();# this automatically faults all the employees for# all the companies that were just batch fetched# above -- it’s magic and recursiveNSArray<Person> employees = comp.employees();# restricts to only the visible objects if attached# to a display group
  42. 42. ERXUnitAwareDecimalFormat• automatically format bytes/meters/grams/ seconds in metric decimal form• scales to appropriate unit based on size• 1234567890 bytes becomes “1.15GB”NumberFormat formatter = new ERXUnitAwareDecimalFormat(ERXUnitAwareDecimalFormat.BYTE);formatter.setMaximumFractionDigits(2);formatter.format(1234567890.0);
  43. 43. ERXJDBCAdaptor• fixes double connection bug from jdbcInfo• should just be the default• er.extensions.ERXJDBCAdaptor.className = er.extensions.jdbc.ERXJDBCAdaptor
  44. 44. ERXMutableURL• java.net.URL is garbage. ERXMutableURL is not.• mutable interface to a URL object• add query parameters one-by-one• supports weird “urls” like “javascript:” and incomplete “/wa/something”
  45. 45. ERXMutableURLERXMutableURL url = new ERXMutableURL( "http://yourhost.com:80/tutorial/index.html?key1=value1#someref");url.setRef(null);url.removeQueryParameter("key1");url.addQueryParameter("key2", “value2”);url.addQueryParameters(“key3=value3&key4=value4”);java.net.URL javaneturl = url.toURL();String urlString = url.toExternalForm();
  46. 46. ERXThreadStorage• a ThreadLocal dictionary that resets for each request• Object obj = ERXThreadStorage.valueForKey (String)• ERXThreadStorage.takeValueForKey(Object, String)• common uses: current user, current session, current context
  47. 47. ERXValueUtilities• convert objects to various common types including “default” form• example: booleanValue(Object) / booleanValueWithDefault(Object, boolean def)• supports boolean, Boolean, int, Integer, float, Float, double, Double, long, Long, array, set, dictionary, data, bigDecimal, enum• converts from every possible form for you -- handy for bindings
  48. 48. ERMemoryAdaptor• acts like a database, but just talking to dictionaries• great for test cases• no SQL support -- don’t try to get tricky• Include JavaMemoryAdaptor.framework• dbConnectAdaptorGLOBAL=Memory or [ModelName].adaptor=Memory
  49. 49. ERPDFWrapper• Turn any HTML+CSS page into a PDF• Include ERPDFGeneration.framework• <wo:ERPDFWrapper> <html> ... </wo:ERPDFWrapper>• Done. That’s just cool.
  50. 50. PFProfiler / SESnapshotExplorer• These are in another talk.• They’re cool, though.• Pay attention during that talk.
  51. 51. ERXResponseRewriter.Delegate• intercept all resource insertions, optionally replacing (or denying) them• example: you have your own prototype.js and you want to replace Ajax.framework’s version with yours• via properties (for simple cases) or via custom delegate• responseRewriterWillAddResource
  52. 52. ERXResponseRewriter.Delegatepropertieser.extensions.ERXResponseRewriter.resource.[framework].[filename]=[newFramework].[newFileName]er.extensions.ERXResponseRewriter.resource.Ajax.prototype.js=app.myprototype.jsdelegate (example replaces EVERY file with myfile.png -- be smarter)ERXResponseRewriter.setDelegate(new ERXResponseRewriter.Delegate() { public boolean responseRewriterShouldAddResource( String framework, String fileName) { return true; } public ERXResponseRewriter.Resource responseRewriterWillAddResource( String framework, String fileName) { return new ERXResponseRewriter.Resource(“app”, “myfile.png”);});
  53. 53. applyRestrictingQualifierOnInsert• er.extensions.ERXEnterpriseObject.applyRest rictingQualifierOnInsert=true• makes new objects automatically match their entity’s restricting qualifier• i.e. if Employee is “personType = 5”, a new Employee will automatically have personType = 5 set on it• no more awakeFromInsertion junk
  54. 54. secureDisabled• You use DirectConnect• You don’t have SSL in dev• You want to run your app• er.extensions.ERXRequest.secureDisabled=tr ue• Turns off all https URL generation -- only works in dev
  55. 55. ERXAdaptorChannelDelegate• conditionally log slow SQL execution (and some other cool debugging stuff)• took 100ms, log.info the expression• took 1000ms, log.warn the expression• etc ...
  56. 56. ERXAdaptorChannelDelegatepropertieser.extensions.ERXAdaptorChannelDelegate.enabled=trueer.extensions.ERXAdaptorChannelDelegate.trace.milliSeconds.debug=0er.extensions.ERXAdaptorChannelDelegate.trace.milliSeconds.info=100er.extensions.ERXAdaptorChannelDelegate.trace.milliSeconds.warn=1000er.extensions.ERXAdaptorChannelDelegate.trace.milliSeconds.error=5000
  57. 57. Q&ASpirit of Mike SchragWhereabouts UnknownChanneled By Chuck HillGlobal Village Consulting