using afConcurrent** (Service) - ** Creates a map of messages by merging together property files. ** Property files are looked for in the following locations:** ** - 'FormBean.props' in pod 'afFormBean'** - 'FormBean.props' in pod '<pod>'** - '<bean>.props' in pod '<pod>'** ** Messages override those defined previously.** ** Note that message maps are cached on the given bean type, so hit of collating '.props' files is ** only taken once per bean type. ** ** 'Messages' also takes contributions of string Maps:** ** pre>** syntax: fantom** @Contribute { serviceType=Messages# }** Void contributeMessages(Configuration config) {** config.add([** "loginDetails.username.label" : "Username:",** "loginDetails.password.label" : "Password:"** ])** }** <preconstmixin Messages {** Returns messages for the given bean. @Operatorabstract Str:Str getMessages(Type beanType)** Clears the message cache.abstract Void clear()}internalconstclass MessagesImpl : Messages {privateconst AtomicMap messages privateconst Str:Str defaultMsgsprivateconst Str:Str contributedMsgsnew make([Str:Str][] msgs){ contributedMsgs := Str:Str[:]{ caseInsensitive=true} msgs.each { contributedMsgs.setAll(it)}this.contributedMsgs = contributedMsgsthis.defaultMsgs = this.typeof.pod.files.find { matches(it, "FormBean")} .readPropsthis.messages = AtomicMap { keyType=Type#; valType=[Str:Str]# }} @Operatoroverride Str:Str getMessages(Type beanType){((Str:Str) messages.getOrAdd(beanType) |->Str:Str| { msgs := Str:Str[:]{ caseInsensitive = true}try{// TODO use Fantom's locale lookup... somehow, see http://fantom.org/doc/sys/Env#locale// can only get single props, not the whole file, so add locale to getMessage// or just look for more files using the same rules (better)// pass in Locale locale := Locale.cur() formBeanMsgs := beanType.pod.files.find { matches(it, "FormBean")}?.readProps ?: [:] beanTypeMsgs := beanType.pod.files.find { matches(it, beanType.name)}?.readProps ?: [:] tempMsgs := Str:Str[:]{ caseInsensitive=true} .setAll(defaultMsgs) .setAll(contributedMsgs) .setAll(formBeanMsgs) .setAll(beanTypeMsgs) beanName := beanType.name.lower + "." tempMsgs.each |Str v, Str k| {if(k.lower.startsWith(beanName)){ msgs[k[beanName.size..-1]] = vreturn}// don't overwrite a keys set via beanName aboveif(!msgs.containsKey(k)) msgs[k] = v}return msgs}catch(Err err){// Guard against being run in a script - an Err is thrown when not backed by a pod fileif(err.msg.startsWith("Not backed by pod file"))return Str:Str[:]{ caseInsensitive = true}.addAll(defaultMsgs)throw err}}).rw}override Void clear(){ messages.clear}private Bool matches(File file, Str baseName){ file.basename.equalsIgnoreCase(baseName) && file.ext != null && (file.ext.equalsIgnoreCase("props") || file.ext.equalsIgnoreCase("properties"))}}