I use commons-validator v1.2 specification-version : 1.0 whereas my spec-version for struts is : 1.1. Although everything works fine except the message display in the alert box. The alert box display case are relevant.
By instance this jsp field :
<td class="RechBlocCiel">
<input name="nom" type="text" class="inputForm" size="2" maxlength="50" />
</td>
I put in validation.xml :
<field property="nom" depends="required">
<msg name="required" key="error.nom" />
</field>
related to
<validator name="required"
classname="org.apache.struts.validator.FieldChecks"
method="validateRequired"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionMessages,
javax.servlet.http.HttpServletRequest"
msg="errors.required" />
and in struts config the plugin is declared :
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml" />
</plug-in>
<message-resources
parameter="xxx.resources.ApplicationResources" />
In xxx.resources.ApplicationResources I have the properties file : ApplicationResources.properties which contains:
errors.required = <li> Le champ [{0}] est obligatoire.</li>
error.nom = nom
It seems to me that everything is complete, so I'm not sure where to search now, except in a problem of version between validator and struts.
I 'm looking for the message : "Le champ nom est obligatoire."
I add depends = "" to
<validator name="required"
classname="org.apache.struts.validator.FieldChecks"
method="validateRequired"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionMessages,
javax.servlet.http.HttpServletRequest"
depends="" msg="errors.required" />
then the error.nom message appears in the alert box. I don't solve the problem completely yet but at least it works with
error.nom = Le champ nom est obligatoire.
Though this solutino isn't generic for all my form fields required. Instead of adding the field name to the generic message I have redondance of "Le champ" "est obligatoire" in my .properties
definitive answer :
I needed to use struts tag : html:text etc. to benefit of this mecanism.
Then, I modify the validation rules :
<field property="nom" depends="required">
<arg0 key="error.nom"/>
</field>
And it works fine!
Related
The power of Spring Roo is that it handles the difficult stuff.
Question: if there a good best practice and implementation on how to show to each user, where ever he lives on this planet, the dates in local time.
Issue:
When a user enters a date and goes to the "list all visits" page, he/she will see a total different date, if he /she is in a different timezone than the OpenShift server. For example I'm in GMT+1 (West Europe) timezone.
My situation:
Web application is developed with Spring Roo 2.0 / gvNIX 2.0
Will be hosted on OpenShift (rhcloud.com)
Like the petclinic sample: https://petclinic-gvnix.rhcloud.com/
Users can live everywhere in the world, so every timezone.
Java 8 is at this time not an option, because OpenShift has not TomCat 8 deployment yet, and, if possible, I want to keep away from creating a OpenShift DIY application.
Requirement:
Each user should see the dates in his local time.
Reproduce:
Go the the Petclinic sample and log in: https://petclinic-gvnix.rhcloud.com/
Choose Visit -> Create new visit
Choose List all Visits
When you are in a different timezone than the Openshift server you get something like above
Having thought about this problem, I think I have a clean solution for implementing Timezone support without affecting current projects.
My starting point is that the solution should be backward compatible and should not break current projects. Also the change should be as little as possible.
I tested it and it works, also when my web application runs on Openshift, where it is hosted in TimeZone GMT-5:00 and me living in West Europe, GMT +1:00
Please give me your opinions.
I will describe the solution / proposal for the show.jspx views. But in the same way it can be implemented for the other views as well.
The essense of the change is that I added timeZone to the fmt:formatDate .. statement in WEB-INF/tags/form/fields/column.tagx/display.jspx:
Old:
<fmt:formatDate value="${object[field]}" pattern="${fn:escapeXml(dateTimePattern)}" />
New:
<fmt:timeZone value="${timeZone}">
<fmt:formatDate value="${object[field]}" pattern="${fn:escapeXml(dateTimePattern)}" timeZone="${timeZone}" />
</fmt:timeZone>
For this to work I also added the declaration and a default timeZone setting when not used.
<jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:fmt="http://java.sun.com/jsp/jstl/fmt" xmlns:spring="http://www.springframework.org/tags" xmlns:form="http://www.springframework.org/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
<jsp:output omit-xml-declaration="yes" />
<jsp:directive.attribute name="id" type="java.lang.String" required="true" rtexprvalue="true" description="The identifier for this tag (do not change!)" />
<jsp:directive.attribute name="object" type="java.lang.Object" required="true" rtexprvalue="true" description="The form backing object" />
<jsp:directive.attribute name="field" type="java.lang.String" required="true" rtexprvalue="true" description="The field name" />
<jsp:directive.attribute name="label" type="java.lang.String" required="false" rtexprvalue="true" description="The label used for this field, will default to a message bundle if not supplied" />
<jsp:directive.attribute name="date" type="java.lang.Boolean" required="false" rtexprvalue="true" description="Indicate that this field is of type java.util.Date" />
<jsp:directive.attribute name="calendar" type="java.lang.Boolean" required="false" rtexprvalue="true" description="Indicate that this field is of type java.util.Calendar" />
<jsp:directive.attribute name="dateTimePattern" type="java.lang.String" required="false" rtexprvalue="true" description="The date / time pattern to use if the field is a date or calendar type" />
========== Added declaration
<jsp:directive.attribute name="timeZone" type="java.lang.String" required="false" rtexprvalue="true" description="The timezone to use if the field is a date or calendar type" />
========== End
<jsp:directive.attribute name="render" type="java.lang.Boolean" required="false" rtexprvalue="true" description="Indicate if the contents of this tag and all enclosed tags should be rendered (default 'true')" />
<jsp:directive.attribute name="z" type="java.lang.String" required="false" description="Used for checking if element has been modified (to recalculate simply provide empty string value)" />
<c:if test="${empty render or render}">
<c:if test="${not empty object and empty label}">
<spring:message code="label_${fn:toLowerCase(fn:substringAfter(id,'_'))}" var="label" htmlEscape="false" />
</c:if>
<c:if test="${empty dateTimePattern}">
<c:set value="MM/dd/yyyy" var="dateTimePattern" />
</c:if>
========== Added default setting. Taking the timezone of the server!
<c:if test="${empty timeZone}">
<jsp:scriptlet>
jspContext.setAttribute("timeZone", java.util.TimeZone.getDefault().getID());
</jsp:scriptlet>
</c:if>
========== End
<div id="_${fn:escapeXml(id)}_id">
<label for="_${fn:escapeXml(field)}_id">
<c:out value="${label}" />
:
</label>
<div class="box" id="_${fn:escapeXml(id)}_${fn:escapeXml(field)}_id">
<c:choose>
<c:when test="${date}">
<spring:escapeBody>
========== Changed: added timeZone support for Date
<fmt:timeZone value="${timeZone}">
<fmt:formatDate value="${object[field]}" pattern="${fn:escapeXml(dateTimePattern)}" timeZone="${timeZone}" />
</fmt:timeZone>
========== End
</spring:escapeBody>
</c:when>
<c:when test="${calendar}">
<spring:escapeBody>
========== Changed: added timeZone support for Calendar
<fmt:timeZone value="${timeZone}">
<fmt:formatDate value="${object[field].time}" pattern="${fn:escapeXml(dateTimePattern)}" timeZone="${timeZone}" />
</fmt:timeZone>
========== End
</spring:escapeBody>
</c:when>
<c:otherwise>
<spring:eval expression="object[field]" />
</c:otherwise>
</c:choose>
</div>
</div>
<br />
</c:if>
</jsp:root>
When adding / changing these few lines, all the old code will continue to work.
You will have to apply these changes also to the WEB-INF/tags/form/fields/column.tagx file.
I you use gvNIX JQuery the same changes should be applied there also.
This is all the change you have to do!!!!
To add timezone support in all your show.jspx files:
1) add the extra timezone option for any date.
old:
<field:display date="true" dateTimePattern="${fileUpload_uploaddate_date_format}" field="uploadDate" id="s_com_myproject_onlineviewer_domain_FileUpload_uploadDate" object="${fileupload}" z="user-managed"/>
new:
<field:display date="true" dateTimePattern="${fileUpload_uploaddate_date_format}" field="uploadDate" id="s_com_myproject_onlineviewer_domain_FileUpload_uploadDate" object="${fileupload}" timeZone="${fileUpload_uploaddate_date_timezone}" z="user-managed"/>
2) In your controller specify your timeZone like:
uiModel.addAttribute("fileUpload_uploaddate_date_timezone", "Europe/Amsterdam");
In the spirit of Spring Roo's dataformat addDateTimeFormatPatterns(uiModel); I added addTimeZone(uiModel); .
In this method you can specify the source of the timezone.
In my web application I ask the user to specify his/her timezone when they reigster. All other workaround fail somewhere.
void addTimeZone(Model uiModel) {
uiModel.addAttribute("fileUpload_uploaddate_date_timezone", UserUtils.geTimeZone());
}
BTW, an addTimeZone default method in the AspectJ controller could be as the sample below, leaving the programmer to be able to push in and alter it.
void FileUploadController.addTimeZone(Model uiModel) {
uiModel.addAttribute("fileUpload_uploaddate_date_timezone", TimeZone.getDefault().getID());
}
My VoiceXML provider, Nexmo, seems not to handle the xml:lang="es-ES" attribute in the root vxml (This is generated by Rivr with a context.setLanguage("es-ES") in my Dialog)
I want Nexmo to use a spanish TTS engine but as I am using Rivr, I can't see where I can specify that I want the "prompt" to include, for example, xml:lang="es-es-female", so it generates VoiceXML:
<prompt xml:lang="es-es-female">
Hola.
</prompt>
interaction().addPrompt() only accepts the SpeechSynthesis object which does not allow (as far as I see) language options.
I've also tried include SSML in the SpeechSynthesis object (using a DocumentFragment as I see in Rivr Javadoc) but that won't work. Probably Nexmo does not support SSML.
Any workarounds? (A part from changing to a better VoiceXML provider)
Thanks a lot!!!
If you only want to play a message without getting input from the user, use can use the Message class:
//Play a synthesis message in another language
Message message = new Message("synthesis-french-message",
new SpeechSynthesis("Ceci est un message."));
message.setLanguage("fr-CA");
DialogueUtils.doTurn(message, context);
If you need to specify the language for a prompt in an Interaction, this can be done with the InteractionBuilder. The setLanguage() method can be used before the addPrompt() method. Multiple languages can be used within the same interaction:
Interaction interaction = OutputTurns.interaction("multilingual-interaction")
.setLanguage("es-ES")
.addPrompt(new SpeechSynthesis("Holá."))
.setLanguage("fr-CA")
.addPrompt(new SpeechSynthesis("Bonjour."))
.build(new SpeechRecognition(new GrammarReference("grammar.grxml")),
Duration.seconds(2));
DialogueUtils.doTurn(interaction, context);
If you don't want to use the builder, you can do it by hand but it's much longer:
List<Interaction.Prompt> prompts = new ArrayList<Interaction.Prompt>();
Interaction.Prompt spanishPrompt = new Interaction.Prompt(new SpeechSynthesis("Holá."));
spanishPrompt.setLanguage("es-ES");
prompts.add(spanishPrompt);
Interaction.Prompt frenchPrompt = new Interaction.Prompt(new SpeechSynthesis("Bonjour."));
frenchPrompt.setLanguage("fr-CA");
prompts.add(frenchPrompt);
SpeechRecognition speechRecognition = new SpeechRecognition(new GrammarReference("grammar.grxml"));
FinalRecognitionWindow finalRecognitionWindow = new FinalRecognitionWindow(speechRecognition,
Duration.seconds(2));
Interaction interaction2 = new Interaction("multilingual-interaction2",
prompts,
finalRecognitionWindow);
DialogueUtils.doTurn(interaction2, context);
The output VoiceXML is:
<?xml version="1.0" encoding="UTF-8"?>
<vxml application="/rivr-cookbook-message-language/dialogue/root/efe10575-1766-48fb-9e13-572a771bc5f4" version="2.1"
xmlns="http://www.w3.org/2001/vxml">
<script>application.rivr.localErrorHandling = false; application.rivr.inputTurn = {};</script>
<form id="form">
<block name="prompt0">
<prompt bargein="false" xml:lang="es-ES">Holá.</prompt>
</block>
<block name="prompt1">
<prompt bargein="false" xml:lang="fr-CA">Bonjour.</prompt>
</block>
<field name="recognition">
<grammar mode="voice" src="grammar.grxml" />
<property name="timeout" value="2000ms" />
</field>
<filled mode="any">
<script>application.rivr.addRecognitionResult()</script>
<goto next="#submitForm" />
</filled>
</form>
<catch>
<if cond="_event.substring(0, 5) == "error"">
<if cond="application.rivr.localErrorHandling">
<goto next="#fatalErrorForm" />
<else />
<script>application.rivr.localErrorHandling=true</script>
</if>
</if>
<script>application.rivr.addEventResult(_event, _message)</script>
<goto next="#submitForm" />
</catch>
<form id="fatalErrorForm">
<block>
<exit />
</block>
</form>
<form id="submitForm">
<block>
<var expr="application.rivr.toJson(application.rivr.inputTurn)" name="inputTurn" />
<if cond="application.rivr.hasRecording(application.rivr.inputTurn)">
<var expr="application.rivr.inputTurn.recordingMetaData.data" name="recording" />
<assign expr="undefined" name="application.rivr.inputTurn.recordingMetaData.data" />
<submit enctype="multipart/form-data" method="post" namelist="inputTurn recording"
next="/rivr-cookbook-message-language/dialogue/efe10575-1766-48fb-9e13-572a771bc5f4/0/multilingual-interaction2" />
<else />
<submit method="post" namelist="inputTurn"
next="/rivr-cookbook-message-language/dialogue/efe10575-1766-48fb-9e13-572a771bc5f4/0/multilingual-interaction2" />
</if>
</block>
</form>
</vxml>
Starting to learn ofbiz, I am following the tutorial here:
https://cwiki.apache.org/confluence/display/OFBIZ/OFBiz+Tutorial+-+A+Beginners+Development+Guide#OFBizTutorial-ABeginnersDevelopmentGuide-SecureYourApplicationbyAuthentication
Now I am in the step to make the list form of persons editable. In this step I need to create a service which will be used for auto-fields-service. Below I give the code which I have done.
In the controller.xml of my componenent I have created a requestMaps as follows:
<request-map uri="updatePracticePerson">
<security https="true" auth="true"/>
<event type="service" invoke="updatePracticePerson"/>
<response name="success" type="view" value="personForm"/>
<response name="error" type="view" value="personForm"/>
</request-map>
Moving now to the PracticeScreens.xml i have the following for personForm:
<screen name="personForm">
<section>
<actions>
<set field="headerItem" value="personForm"/>
<set field="titleProperty" value="PageTitlePracticePersonForm"/>
<entity-condition entity-name="Person" list="persons"/>
</actions>
<widgets>
<decorator-screen name="CommonPracticeDecorator" location="${parameters.mainDecoratorLocation}">
<decorator-section name="body">
<label text="Person List" style="h2"/>
<include-form name="ListPersons" location="component://practice/widget/PracticeForms.xml"></include-form>
</decorator-section>
</decorator-screen>
</widgets>
</section>
The above includes the ListPersons from PracticeForms.xml, which I have as :
<form name="ListPersons" type="list" list-name="persons" list-entry-name="person" target="updatePracticePerson" paginate-target="personForm">
<auto-fields-service service-name="updatePracticePerson" default-field-type="edit" map-name="person"/>
<field name="partyId"><hidden/></field>
<field name="submitButton" title="Update" widget-style="smallSubmit"><submit button-type="button"/></field>
<field name="deletePracticePerson" title="Delete Person" widget-style="buttontext">
<hyperlink target="deletePracticePerson?partyId=${person.partyId}" description="${uiLabelMap.CommonDelete}" also-hidden="false"/>
</field>
<field name="submitButton" title="${uiLabelMap.CommonUpdate}"><submit button-type="button"/></field>
</form>
If you see above the ListPersons calls the service updatePracticePerson.
inside servicedef/services.xml i have the following:
<service name="updatePracticePerson" default-entity-name="Person" engine="simple"
location="component://practice/script/org/hotwax/practice/PracticeServices.xml" invoke="updatePracticePerson" auth="true">
<description>Create a Person</description>
<auto-attributes include="pk" mode="IN" optional="false"/>
<attribute name="salutation" mode="IN" type="String" optional="true"/>
<attribute name="firstName" mode="IN" type="String" optional="false"/>
<attribute name="middleName" mode="IN" type="String" optional="true"/>
<attribute name="lastName" mode="IN" type="String" optional="false"/>
<attribute name="suffix" mode="IN" type="String" optional="true"/>
</service>
In the root of my project in the file ofbiz-component.xml i have :
<service-resource type="model" loader="main" location="servicedef/services.xml"/>
this to make sure that my service is loaded.
Although all of the above seem correct to me I get the following error :
org.ofbiz.widget.screen.ScreenRenderException: Error rendering screen [component://common/widget/CommonScreens.xml#GlobalDecorator]: java.lang.RuntimeException: Error rendering included form named [ListPersons] at location [component://practice/widget/PracticeForms.xml]: java.lang.IllegalArgumentException: Error finding Service with name updatePracticePerson for auto-fields-service in a form widget (Error rendering included form named [ListPersons] at location [component://practice/widget/PracticeForms.xml]: java.lang.IllegalArgumentException: Error finding Service with name updatePracticePerson for auto-fields-service in a form widget)
Which obviously implies that everything is not ok and there is something wrong with my service. Could you please assist on this?
Thanks in advance,
gianis
Restart OFBiz and check the logs. During startup it will show you loading your component and then the services defined in your component. You should be able to see the problem in the logs
at the end i found the answer myself.
in the file on the root of my component ofbiz-component.xml i had:
<resource-loader name="personForm" type="component"/>
when I should have:
<resource-loader name="main" type="component"/>
I have a request-map in controller as follows:
<request-map uri="processFirstForm">
<event type="java" path="org.ofbiz.learning.learning.LearningEvents"
invoke="processFirstForm" />
<response name="success" type="view" value="OneFormScreen" />
</request-map>
In controller, I defined a handler for java event as follows:
<handler name="java" type="request" class="org.ofbiz.webapp.event.JavaEventHandler"/>
I have a screen form as follows:
<form name="FirstForm" type="single" target="processFirstForm">
<field name="firstName">
<text />
</field>
<field name="lastName">
<text />
</field>
<field name="submit">
<submit />
</field>
</form>
I also have file LearningEvents.class in folder /bin/org/ofbiz/learning/learning
But i still receive a exception when i submit FirstForm form as follows:
ERROR rendering error page [/error/error.jsp], but here is the error
text: org.ofbiz.webapp.event.EventHandlerException: Error invoking
event, the class org.ofbiz.learning.learning.LearningEvents was not
found
Can anyone help me? thank a lot!
Do you have other java services or events in this component that are working fine? I trying to understand whether the problem is in this event or the whole component setup is not complete. Start from comparing your build.xml and ofbiz-component.xml with an existing one.
IzPack TargetPanel lets one select one target directory. However I need to allow users to choose two (one for apps, one for data). How to do that?
You can create a UserInputPanel and get the path as a variable from the user. Then you can use variable substitution anywhere you want. You'll have to add a userInputSpec.xml file and define your own panels (as many as you want). To get a directory, use <field type="dir" ... >
Example userInputSpec.xml from an application of mine. I include mongoDB with the installer and use this to get some settings.
<userInput>
<panel order="0">
<createForPack name="MongoDB" />
<!-- Other settings like port, ip, username, password-->
<field type="staticText" align="left" txt="Select the catalogue where data will be stored." id="staticText.registry.db.data.text" />
<field type="dir" align="left" variable="mongo.data.dir">
<spec txt="Data directory" size="25" set="$INSTALL_PATH\data" mustExist="false" create="true" />
</field>
</panel>
<panel order="1">
<!-- definition of a second panel -->
</panel>
</userInput>
You also need to include the userInputSpec.xml as a resource in your main installation file and add a UserInputPanel element for each panel that you define in userInputSpec.xml
Like this (in the <installation> element:
<resources>
<!-- other resources -->
<res id="userInputSpec.xml" src="userInputSpec.xml" />
</resources>
<panels>
<panel classname="HelloPanel"/>
<panel classname="InfoPanel"/>
<panel classname="LicencePanel"/>
<panel classname="TargetPanel"/>
<panel classname="TreePacksPanel"/>
<panel classname="UserInputPanel"/>
<panel classname="UserInputPanel"/>
<panel classname="InstallPanel"/>
<panel classname="ShortcutPanel"/>
<panel classname="FinishPanel"/>
</panels>
notice the double occurence of
I have two panels defined in my userInputSpec
Make sure that your UserInputPanels appear before InstallPanel because you have to get the variables from the user before copying your files.
This is just an example from my app. See the official documentation to get the idea of what the elements and attributes I used mean. There are many features connected with user input.