GWT@Jazoon08 - Part 3/6 - Personalization & Customization

Post on 02-Dec-2014

2.856 views 0 download

description

A presentation about GWT which I presentaed at Jazoon '08Part 3/6 - Personalization and Customization

Transcript of GWT@Jazoon08 - Part 3/6 - Personalization & Customization

LOGO SPEAKER‘S COMPANY

# 3

personalizationand customization.

LOGO SPEAKER‘S COMPANY

identify yourself with the product ...

LOGO SPEAKER‘S COMPANY

the barmaid remembering your favourite drink ...

LOGO SPEAKER‘S COMPANY

customize your drink at Starbucks ...

LOGO SPEAKER‘S COMPANY

+6.6 billion people can’t all be the same ...

LOGO SPEAKER‘S COMPANY

+/- 191 currencies ...

LOGO SPEAKER‘S COMPANY

let’s meet on 01/02/2008 ...

LOGO SPEAKER‘S COMPANYcan you pick me up at 9 o’clock ...

LOGO SPEAKER‘S COMPANY

annoying.

my favourite application doesn’t run in an OpenSocial container nor on my IPhone nor does it have offline access

LOGO SPEAKER‘S COMPANY

linker.[ overview ]

LOGO SPEAKER‘S COMPANY

linker.“In computer science, a linker is a program

that takes one or more objects generated by the compiler and assembles them into a single executable program.”

- Wikipedia

LOGO SPEAKER‘S COMPANY

objectobject objectobject objectobject

linker

iPhoneiPhoneAdobe Air

Adobe Air AndroidAndroidGearsGearsOpen

Social

OpenSocial

LOGO SPEAKER‘S COMPANY

PRIMARY LINKERS

the primary linker is responsible for module bootstrap

pre- and post-linkers run before and after the primary Linker

linkers are only run during web-mode compile

SelectionScriptLinker // Bootstrap is an external script

HostedModeLinker // Only for hosted mode

XSLinker // Cross site linker

SingleScriptLinker // Provides single JS file

IFrameLinker [default] // Loads JS in Iframe

@LinkerOrder(Order.PRIMARY)

public class IFrameLinker extends SelectionScriptLinker { … }

LOGO SPEAKER‘S COMPANY

ENABLE AN EXISTING LINKER

<add-linker name=“std”/> IFrame linker

<add-linker name=“xs”/> Cross site linker

<add-linker name=“sso”/> Single script linker

LOGO SPEAKER‘S COMPANY

ARTIFACTS

Linker operate on a set of Artifacts:

CompilationResult // unique chunk of JavaScript permutation

EmittedArtifact // emitted to output directory

GeneratedSource // GeneratorContext.tryCreateResource

PublicResource // files in public path

SyntheticArtifact // created by Linker

ScriptReference // external script ref. in .gwt.xml

StylesheetReference // external CSS ref. in .gwt.xml

Communicate with Linker stack via GeneratorContext.commitArtifact();

Linkers can transform one ArtifactSet into another

LinkerContext contains global data (module name, selection properties…)

LOGO SPEAKER‘S COMPANY

linker.[ build your own linker ]

LOGO SPEAKER‘S COMPANY

customize.synthesize additional output-dependent files Google Gears ManagedResourceStore manifest file

integrate with other environments iGoogle, OpenSocial …

provide an alternate bootstrap or packaging Gadgets and single stage bootstraps

generally solve “GWT and … “ integration

LOGO SPEAKER‘S COMPANY

BUILD YOUR OWN LINKER (1/2)

@LinkerOrder(Order.POST)

public class FileListLinker extends AbstractLinker {

public ArtifactSet link(TreeLogger logger, LinkerContext context,

ArtifactSet artifacts) throws UnableToCompleteException {

ArtifactSet toReturn = new ArtifactSet(artifacts);

toReturn.add(createFileListArtifact(toReturn));

return toReturn;

}

LOGO SPEAKER‘S COMPANY

BUILD YOUR OWN LINKER (2/2)

public Artifact createFileListArtifact(ArtifactSet toReturn) {

SortedSet<EmittedArtifact> emitted = toReturn.find(EmittedArtifact.class);

StringBuffer fileList = new StringBuffer(“<html><body>”);

for (EmittedArtifact artifact : emitted) {

fileList.append(artifact.toString() + “<br/>”);

}

fileList.append(“</body></html>”);

return emitBytes(logger, Util.getBytes(fileList.toString()), "fileList.html“));

}

LOGO SPEAKER‘S COMPANY

DEFINE THE NEW LINKER

<define-linker name=“fileListLinker" class=“com.FileListLinker" />

ENABLE THE NEW LINKER

<add-linker name=“fileListLinker”/>

LOGO SPEAKER‘S COMPANY

LOGO SPEAKER‘S COMPANY

linker.[ advanced use case ]

LOGO SPEAKER‘S COMPANY

INLINE SELECTION SCRIPT INTO HOST PAGE (1/2)

public ArtifactSet link(TreeLogger logger, LinkerContext

context, ArtifactSet artifacts) throws UnableToCompleteException {

artifacts = new ArtifactSet(artifacts);

EmittedArtifact script = getSelectionScript(artifacts); artifacts.remove(script);

for (EmittedArtifact e : artifacts.find(EmittedArtifact.class)) {

if (e.getPartialPath().toLowerCase().endsWith(".html")) {

EmittedArtifact newArtifact = replaceScripts(logger, e, script);

artifacts.replace(newArtifact); } } return artifacts;

}

LOGO SPEAKER‘S COMPANY

INLINE SELECTION SCRIPT INTO HOST PAGE (2/2)

private EmittedArtifact replaceScript(TreeLogger logger,

EmittedArtifact e, EmittedArtifact script) throws

UnableToCompleteException {

String page = Util.readStreamAsString(e.getContents(logger));

// ... replacements happen ... EmittedArtifact toReturn = emitString(logger, page,

e.getPartialPath()); return toReturn;

}

LOGO SPEAKER‘S COMPANY

localization.[ for dummies ]

LOGO SPEAKER‘S COMPANY

CREATE INTERFACE TO DEFINE TYPE-SAFE TEMPLATES

public interface ErrorMessages extends Messages {

String accessDenied(int code, String userName);

}

CREATE CORRESPONDING PROPERTY FILE

accessDenied=Error {0}: {1} cannot access {2}

LOGO SPEAKER‘S COMPANY

ADD LOCALE CHOICES TO A MODULE

<module> <inherits name=“com.google.gwt.i18n.I18N”/> <extend-property name=“locale” values=“fr”/> </module>

APPLY MESSAGE

ErrorMessages msgs = GWT.create(ErrorMessages.class);

Window.alert(msgs.accessDenied(502, username));

LOGO SPEAKER‘S COMPANY

CHOOSE A LOCALE AT RUNTIME

url based: http://localhost:808/example?locale=nl meta tag: <meta name=“gwt:property” content=“locale=fr”>

OTHER LOCALE OPTIONS

messages = templated messages constants = simple messages withLookup = extra lookup functionality dictionary = for locale data encapsulated in the page [runtime]

LOGO SPEAKER‘S COMPANY

localization.[ demystified ]

LOGO SPEAKER‘S COMPANY

CODE GENERATION

a Java source file is generated for each defined language generation is based upon the Localizable interface at runtime a property provider determines the locale based upon the ‘locale=nl’ URL argument or Meta property

no data structure in the middle no runtime loading or resolution they work because they passed the compiler format must be UTF-8 locale fallback mechanism en_US -> en -> default DateTime and NumberFormat have local backend-in

LOGO SPEAKER‘S COMPANY

COMPILER OPTIMIZATION

MyConstants constants = GWT.create(MyConstants.class); String hello = constants.hello(); Window.alert(hello);

compiles into:

$intern_2 = ‘hello’; $wnd.alert($intern_2);

and not into:

$wnd.alert(‘hello’); // some browsers actually create a new literal object

LOGO SPEAKER‘S COMPANY

localization.[ real life issues ]

LOGO SPEAKER‘S COMPANY

DYNAMIC LOCALES

locales tend to change many use cases include database driven locales

so how do we deal with runtime changing locales????

options

- locale data stored in project locale files recompile

- locale data stored in database extract to project locale files + recompile (Thread changes as bugs)

reload page + embed new locales in HTML file + Dictionary support runtime locales in the client

LOGO SPEAKER‘S COMPANY

DYNAMIC LOCALES

runtime locales in the client

Label aLabel = new Label(); // HasText

LocaleSupport.addListener(aLabel); // Updates all HasText on locale change

there goes the lazy developer .. let’s think …

But how does the LocaleSupport know that a locale has been updated? - server needs to figure out what to do ??? state on the server - poll at regular interval - piggy bagging - do I lock the client while I update all the labels ??? - or do I only update the current labels and updates the others later ??? - so the client needs to download this complete update mechanism

LOGO SPEAKER‘S COMPANY

MAARTENVOLDERS.comPASSIONATE ABOUT PEOPLE AND TECHNOLOGY