I had a doubt regarding Messages being set in the custom validator in JSF 2.0.
here is the code
public void validate(FacesContext context, UIComponent component,
Object value) throws ValidatorException {
matcher = pattern.matcher(value.toString());
if(!matcher.matches()){
FacesMessage msg =
new FacesMessage("E-mail validation failed.",
"Invalid E-mail format.");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg);
}
}
Now here I am curious about how is it actually working, since we haven't written the part of the code
context.add(msg)
SO without adding these messages in the FacesContext how does it manage to retrieve it on the UI???
JSF does that in the UIInput#validateValue() method. It just calls your validator inside a try-catch block, catches the ValidatorException, extracts the FacesMessage from it and finally adds it to the FacesContext on component's client ID.
JSF implementations are open source. In Mojarra 2.1.3 source code you can find the following starting at line 1143 of the UIInput class:
// If our value is valid and not empty or empty w/ validate empty fields enabled, call all validators
if (isValid() && (!isEmpty(newValue) || validateEmptyFields(context))) {
if (validators != null) {
Validator[] validators = this.validators.asArray(Validator.class);
for (Validator validator : validators) {
try {
validator.validate(context, this, newValue);
}
catch (ValidatorException ve) {
// If the validator throws an exception, we're
// invalid, and we need to add a message
setValid(false);
FacesMessage message;
String validatorMessageString = getValidatorMessage();
if (null != validatorMessageString) {
message =
new FacesMessage(FacesMessage.SEVERITY_ERROR,
validatorMessageString,
validatorMessageString);
message.setSeverity(FacesMessage.SEVERITY_ERROR);
} else {
Collection<FacesMessage> messages = ve.getFacesMessages();
if (null != messages) {
message = null;
String cid = getClientId(context);
for (FacesMessage m : messages) {
/* Here --> */ context.addMessage(cid, m);
}
} else {
message = ve.getFacesMessage();
}
}
if (message != null) {
/* And here --> */ context.addMessage(getClientId(context), message);
}
}
}
}
}
jsf has a catch exception in back and he is retrieving your message..
If this doesn't answer your question I don't understand your question...
maybe this link will help you:
http://java.dzone.com/articles/jsf-validation-tutorial-error
You have to set a place for errors in jsf as well..
Related
I'm trying to implement a kick command for my bot, but Guild.kick(Member member) doesn't actually kick the specified user. IntelliJ simply says "Result of Guild.kick(Member member) is ignored". Here's my implementation (with non-relevant code removed):
public void onGuildMessageReceived(#Nonnull GuildMessageReceivedEvent e) {
// other code
g = e.getGuild();
// other code
if (args[0].equalsIgnoreCase("kick")) {
// other code
String target = getConnectedName(args, 1, 0); // gets name of target from message
List<Member> nameList = g.getMembersByEffectiveName(target, true);
try {
target = nameList.get(0).getAsMention();
c.sendMessage("Target: "+target).queue();
} catch (IndexOutOfBoundsException e) {
c.sendMessage("No user found with the name \"target\" in this guild.").queue();
}
Member targetM = null;
if (!nameList.isEmpty()) {
targetM = nameList.get(0);
c.sendMessage(targetM.toString()).queue();
try {
g.kick(targetM);
} catch (HierarchyException e) {
error403MissingPermission(); // sends a message that user is missing permission to use !kick
}
}
}
}
Does anyone know why this won't work / what's wrong with my implementation?
SOLVED:
Guild.kick(Member member) has to be queued like TextChannel.sendMessage(String text) , so the correct usage is g.kick(Member member).queue();. Credit to #Minn
I am implementing a SOAP service in Mule ESB version 3.8 using the HTTP and CXF component. Please see attached image for the flow design.
The Mule flow is :
HTTP and CXF component exposes the web service which gives sum of two integers. The object send in request is :
public class AddValues{
private int a;
private int b;
public setA(int a)
{
this.a =a;
}
public getA()
{
return a;
}
public setB(int b)
{
this.b =b;
}
public getB()
{
return b;
}
}
Save the SOAP action using a variable.
Based on the SOAP Action route the Flow control.
Using a JAVA transformer to receive the payload and throw Custom Web fault exception as follows:
public class AddValuesBusinessLogic extends AbstractMessageTransformer
{
#Override
public Object transformMessage(MuleMessage message, String outputEncoding) throws TransformerException {
MuleMessage muleMessage = message;
AddValues addValues = (AddValues) muleMessage.getPayload();
if (addValues.getA() == null || addValues.getB() == null ) {
//Make an AddValueException object
throw new Exception("Add value exception");
}
return null;
}
}
But i am getting the error "Surround with try/catch"
My question is if I surround and handle the exception, how am I going to send the SOAP Fault to end user?
Can someone please suggest what is the best way to send a custom SOAP Fault from JAVA Transformer in Mule ESB?
I found a solution using TransformerException and CXF OutFaultInterceptor.
My approach is as follows:
Write a custom transformer class inside which add the validation rules. For example, if I want to throw Error for Integer a or b being null, I will add a Custom Transformer AddValuesBusinessLogic.class with the following code:
public class AddValuesBusinessLogic extends AbstractMessageTransformer
{
#Override
public Object transformMessage(MuleMessage message, String outputEncoding) throws
TransformerException
{
MuleMessage muleMessage = message;
AddValues addValues = (AddValues) muleMessage.getPayload();
if (addValues.getA() == null || addValues.getB() == null ) {
//Make an AddValueException object
throw new TransformerException(this,new AddValueException("BAD REQUEST"));
}
return "ALL OK";}
This exception will then propagate to CXF where I am writing an OutFaultInterceptor like follows:
public class AddValuesFaultInterceptor extends AbstractSoapInterceptor {
private static final Logger logger = LoggerFactory.getLogger(AddValuesFaultInterceptor.class);
public AddValuesFaultInterceptor() {
super(Phase.MARSHAL);
}
public void handleMessage(SoapMessage soapMessage) throws Fault {
Fault fault = (Fault) soapMessage.getContent(Exception.class);
if (fault.getCause() instanceof org.mule.api.transformer.TransformerMessagingException) {
Element detail = fault.getOrCreateDetail();
Element errorDetail = detail.getOwnerDocument().createElement("addValuesError");
Element errorCode = errorDetail.getOwnerDocument().createElement("errorCode");
Element message = errorDetail.getOwnerDocument().createElement("message");
errorCode.setTextContent("400");
message.setTextContent("BAD REQUEST");
errorDetail.appendChild(errorCode);
errorDetail.appendChild(message);
detail.appendChild(errorDetail);
}
}
private Throwable getOriginalCause(Throwable t) {
if (t instanceof ComponentException && t.getCause() != null) {
return t.getCause();
} else {
return t;
}
}
}
Now when I make a call using either SOAPUI or jaxws client, I get the custom fault exception in the SOAP response.
To extract the values of errorCode and errorMessage in JAXWS client I am doing the following in the catch block of try-catch:
catch (com.sun.xml.ws.fault.ServerSOAPFaultException soapFaultException) {
javax.xml.soap.SOAPFault fault = soapFaultException.getFault(); // <Fault> node
javax.xml.soap.Detail detail = fault.getDetail(); // <detail> node
java.util.Iterator detailEntries = detail.getDetailEntries(); // nodes under <detail>'
while(detailEntries.hasNext()) {
javax.xml.soap.DetailEntry detailEntry = (DetailEntry) detailEntries.next();
System.out.println(detailEntry.getFirstChild().getTextContent());
System.out.println(detailEntry.getLastChild().getTextContent());
}
}
This is working for me as of now.
However I will request suggestionsto improve on this workaound or if there are any better solutions.
Thanks everyone.
You should create your own SOAP Fault (plain Java String) and return it as a message. If you want, you can also create a transformer and put it in your catch-exception-strategy like this:
#Override
public Object transformMessage(MuleMessage message, String outputEncoding)
throws TransformerException {
String exceptionMessage = message.getExceptionPayload().getException().getCause().getMessage();
String outputMessage = "<soap:Fault xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"> " +
" <faultcode>soap:Server</faultcode> " +
"<faultstring>" + exceptionMessage + "</faultstring>" +
"</soap:Fault>";
return outputMessage;
}
Mule always expects Exceptions to be encapsulated in a TransformerException, so you should throw a new TransformerException setting your own Exception as the cause.
How to read a message from WebSphere MQ without deleting the original message from queue?
I have spring application which reads the message from the WebSphere MQ.
After reading, I have a process method which will process the data retrieved from queue.
Step 1:
response = jmsTemplate.receive();
//Message automatically removed from queue.
Step 2:
process(response);
There are chances of throwing exceptions in process method. In case of exceptions, I need to retain the message in the queue.
Is it possible? Is their any way to delete the message only on user acknowledgement?
I tried adding the following:
jmsTemplate.setSessionAcknowledgeMode(javax.jms.Session.CLIENT_ACKNOWLEDGE);
...but still the message is getting deleted.
JmsTemplate creating code snippet:
JndiConnectionFactorySupport connectionFactoryBean = new JndiConnectionFactorySupport();
connectionFactoryBean.setBindingsDir(this.bindingDir);
connectionFactoryBean
.setConnectionFactoryName(connectionFactoryName);
connectionFactoryBean.afterPropertiesSet();
jmsTemplate.setConnectionFactory(connectionFactoryBean.getObject());
JndiDestinationResolver destinationResolver = new JndiDestinationResolver();
destinationResolver.setJndiTemplate(connectionFactoryBean
.getJndiTemplate());
jmsTemplate.setDestinationResolver(destinationResolver);
jmsTemplate.setReceiveTimeout(20000);
jmsTemplate.setDefaultDestinationName(this.defaultDestinationName);
Tried the jmsTemplate.execute() method as below:
#SuppressWarnings({ "unused", "unchecked" })
Message responseMessage = (Message) jmsTemplate.execute(
new SessionCallback() {
public Object doInJms(Session session)
throws JMSException {
MessageConsumer consumer = session
.createConsumer(jmsTemplate.getDestinationResolver().resolveDestinationName(session, "QUEUE_NAME", false));
Message response = consumer.receive(1);
try {
testMethod();//this method will throw exception.
response.acknowledge();
consumer.close();
} catch(Exception e){
consumer.close();//control will come here.
}
return response;
}
}, true);
You can't do that with receive() methods because the operation is complete (from the session perspective) when the receive method returns.
You need to run the code that might fail within the scope of the session; e.g. with a JmsTemplate.execute() with a SessionCallback - something like this...
this.jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
this.jmsTemplate.convertAndSend("foo", "bar");
try {
String value = this.jmsTemplate.execute(session -> {
MessageConsumer consumer = session.createConsumer(
this.jmsTemplate.getDestinationResolver().resolveDestinationName(session, "foo", false));
String result;
try {
Message received = consumer.receive(5000);
result = (String) this.jmsTemplate.getMessageConverter().fromMessage(received);
// Do some stuff that might throw an exception
received.acknowledge();
}
finally {
consumer.close();
}
return result;
}, true);
System.out.println(value);
}
catch (Exception e) {
e.printStackTrace();
}
You have to browse the queue.
Example of real code that was executed making usage of Websphere MQ
public void browseMessagesAndJiraCreation(String jiraUserName, String jiraPassword) {
int counterMessages = jmsTemplate.browse(destinationQueueName, new BrowserCallback<Integer>() {
#Override
public Integer doInJms(final Session session, final QueueBrowser queueBrowser) throws JMSException {
Enumeration<TextMessage> enumeration = queueBrowser.getEnumeration();
int counterMessages = 0;
while (enumeration.hasMoreElements()) {
counterMessages += 1;
TextMessage msg = enumeration.nextElement();
logger.info("Found : {}", msg.getText());
JiraId jiraId = jiraManager.createIssue(jiraUserName, jiraPassword);
jiraManager.attachFileToJira(jiraId, msg.getText(), jiraUserName, jiraPassword);
}
return counterMessages;
}
});
logger.info("{}:messages were browsed and processed from queue:{}.", counterMessages, destinationQueueName);
}
Explanations:
usage of the Spring Framework JmsTemplate
you pass the String gestinationQueueName (example destinationQueueName=QL.PREFCNTR.USER.REPLY)
Java enumeration of Text messages
counterMessages is the counter of messages that were processed
messages are NOT consumed!
You can add transactional processing of JMS messages. See the example
Your listener should be "transacted". Like this
<jms:listener-container connection-factory="connectionFactory" acknowledge="transacted">
<jms:listener ref="notificationProcessor" destination="incoming.queue"/>
</jms:listener-container>
I am using struts-2.3.16 and I have to suppress exceptions from Freemarker template globally in our application. This means that, instead of the yellow screen with the stacktrace from Freemarker, I have to forward to a global jsp that displays a generic message, so preventing the display of stacktraces to the user. For generic exceptions in struts we mapped a global-results in struts.xml, but it's not working for Freemarker exceptions.
So far I have implemented the solution from What are different ways to handle error in FreeMarker template?. So I created a CustomFreemarkerManager and a CustomTemplateExceptionHandler.
My CustomFreemarkerManager looks like this:
#Override
public void init(ServletContext servletContext) throws TemplateException {
super.config = super.createConfiguration(servletContext);
super.config.setTemplateExceptionHandler(new CustomTemplateExceptionHandler(servletContext));
super.contentType = "text/html";
super.wrapper = super.createObjectWrapper(servletContext);
if (LOG.isDebugEnabled()) {
LOG.debug("Using object wrapper of class " + super.wrapper.getClass().getName(), new String[0]);
}
super.config.setObjectWrapper(super.wrapper);
super.templatePath = servletContext.getInitParameter("TemplatePath");
if (super.templatePath == null) {
super.templatePath = servletContext.getInitParameter("templatePath");
}
super.configureTemplateLoader(super.createTemplateLoader(servletContext, super.templatePath));
super.loadSettings(servletContext);
}
#Override
protected Configuration createConfiguration(ServletContext servletContext) throws TemplateException {
Configuration configuration = new Configuration();
configuration.setTemplateExceptionHandler(new CustomTemplateExceptionHandler(servletContext));
if (super.mruMaxStrongSize > 0) {
configuration.setSetting("cache_storage", "strong:" + super.mruMaxStrongSize);
}
if (super.templateUpdateDelay != null) {
configuration.setSetting("template_update_delay", super.templateUpdateDelay);
}
if (super.encoding != null) {
configuration.setDefaultEncoding(super.encoding);
}
configuration.setLocalizedLookup(false);
configuration.setWhitespaceStripping(true);
return configuration;
}
From here I send the ServletContext to my CustomTemplateExceptionHandler so I can create a RequestDispatcher to forward to my exception.jsp. The problem is that in the exception handler I don't have the request and the response and I can't forward to my jsp.
The class CustomTemplateExceptionHandler looks like this so far:
private ServletContext servletContext;
public CustomTemplateExceptionHandler(ServletContext servletContext) {
this.servletContext = servletContext;
}
public void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException {
if (servletContext != null) {
RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/resources/exception.jsp");
//HERE I have to forward to my jsp
}
}
Anybody knows how can I do that? I want the stacktrace to be logged only on the server, and in the UI to replace the stacktrace with a generic message.
Ok, so my solution for this problem was to print on the PrintWriter that comes in my CustomTemplateExceptionHandler a response similar with the standard HTML_DEBUG_HANDLER offered by Freemarker. Check out this link:
https://github.com/apache/incubator-freemarker/blob/2.3-gae/src/main/java/freemarker/template/TemplateExceptionHandler.java#L98
Here you can see how HTML_DEBUG_HANDLER is managed. I replaced printing the stacktrace with a general message. The Freemarker documentation advise you to use RETHROW_HANDLER and catch the exception later in your application after the call of Template.process(). See here:
http://freemarker.org/docs/app_faq.html#misc.faq.niceErrorPage
But because Struts2 is working with Freemarker backstage, and the Freemarker methods are executed after the action was executed, I couldn't figure it out how and where to catch the exception. I have managed to get the HttpServlet response and request in the method handleTemplateException() (see the question), but I could not forward to my exception.jsp because the response was already committed and so it was giving me an exception.
The final code looks like this:
Class CustomFreemarkerManager:
#Override
public void init(ServletContext servletContext) throws TemplateException {
super.config = super.createConfiguration(servletContext);
super.config.setTemplateExceptionHandler(new CustomTemplateExceptionHandler());
super.contentType = "text/html";
super.wrapper = super.createObjectWrapper(servletContext);
if (LOG.isDebugEnabled()) {
LOG.debug("Using object wrapper of class " + super.wrapper.getClass().getName(), new String[0]);
}
super.config.setObjectWrapper(super.wrapper);
super.templatePath = servletContext.getInitParameter("TemplatePath");
if (super.templatePath == null) {
super.templatePath = servletContext.getInitParameter("templatePath");
}
super.configureTemplateLoader(super.createTemplateLoader(servletContext, super.templatePath));
super.loadSettings(servletContext);
}
#Override
protected Configuration createConfiguration(ServletContext servletContext) throws TemplateException {
Configuration configuration = new Configuration();
configuration.setTemplateExceptionHandler(new CustomTemplateExceptionHandler());
if (super.mruMaxStrongSize > 0) {
configuration.setSetting("cache_storage", "strong:" + super.mruMaxStrongSize);
}
if (super.templateUpdateDelay != null) {
configuration.setSetting("template_update_delay", super.templateUpdateDelay);
}
if (super.encoding != null) {
configuration.setDefaultEncoding(super.encoding);
}
configuration.setLocalizedLookup(false);
configuration.setWhitespaceStripping(true);
return configuration;
}
Class CustomTemplateExceptionHandler:
public void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException {
boolean externalPw = out instanceof PrintWriter;
PrintWriter pw = externalPw ? (PrintWriter) out : new PrintWriter(out);
try {
pw.print("<!-- ERROR MESSAGE STARTS HERE -->"
+ "<!-- ]]> -->"
+ "</table></table></table>"
+ "<div align='left' style='"
+ "background-color:#FFFF7C; "
+ "display:block; "
+ "border-top:double; "
+ "padding:10px; "
+ "'>");
pw.print("<b style='"
+ "color: red; "
+ "font-size:14px; "
+ "font-style:normal; "
+ "font-weight:bold; "
+ "'>"
+ "Oops! We have encountered a problem. Please try again!"
+ "</b>");
pw.println("</div></html>");
pw.flush(); // To commit the HTTP response
} finally {
if (!externalPw) pw.close();
}
throw te;
}
If anyone finds a better response to this please post your answer!
It should be easier. If you don't want the yellow debug template error you have to switch the TemplateExceptionHandler from HTML_DEBUG_HANDLER to RETHROW_HANDLER (as the freemarker message on the top suggest: FreeMarker template error DEBUG mode; use RETHROW in production!)
Now, I prefer to do it programmatically (as you did) because I want to choose the TemplateExceptionHandler depending on the environment (PRO, TEST, DEVEL), my solution is to put environment information in the context.
public class CustomFreemarkerManager extends FreemarkerManager {
public CustomFreemarkerManager(){
super();
}
#Override
public void init(ServletContext servletContext) throws TemplateException {
//important!
super.init(servletContext);
//other stuff maybe you want to tune...
//Getting environmentInfo object from the context, it's a personal solution
EnvironmentInfo environmentInfo = (EnvironmentInfo)servletContext.getAttribute(EnvironmentInfo.CONTEXT_NAME);
if (environment.isPro()) {
config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
}else{
config.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
}
}
}
and tell struts to use your manager in struts.properties
struts.freemarker.manager.classname=com.jobisjob.northpole.web.core.CustomFreemarkerManager
Hope this helps.
I'm looking for a way to return non-fatal validation "warning" messages for display on a JSP form (in addition to the usual validation "error" messages). These would be messages that allow processing to continue instead of blocking the completion of a task.
I'd like to use the existing Spring 4 MVC plumbing for this: The BindingResult object, the Spring Validator interface, and the Spring <form:errors /> tag. But so far I haven't been able to work out the details of returning a second BindingResult object and getting the messages to display.
Here's what I've got so far:
myFormValidator.validate(myForm, bindingResult);
myFormValidator.validateWarnings(myForm, warnings);
model.addAttribute("warnings",warnings);
return new ModelAndView(FORM_VIEW, "myForm", myForm);
But I have no idea how to tie the free-floating BindingResult object warnings to a <form:errors /> tag on the JSP side. Can anyone help with this?
It doesn't look like there's an easy way to do this using the existing <form:errors /> tag. What I wound up doing was creating a custom tag, based off of ErrorsTag.java and its superclasses.
Here is how the tag looks:
<mytag:warnings bind="${warnings}" path="myFieldName" />
This will list all the warnings for myForm.myFieldName in a nicely styled block.
Here are the guts (boilerplate can be obtained from http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/tags/form/AbstractHtmlElementTag.html ):
protected boolean shouldRender() throws JspException {
try {
if (this.getPath() != null &&
this.getPath() != "") {
// Field errors
return (this.bind.hasFieldErrors(this.getPath()));
} else {
// Global errors
return this.bind.hasGlobalErrors();
}
} catch (IllegalStateException ex) {
// Neither BindingResult nor target object available.
return false;
}
}
protected int writeTagContent(TagWriter tagWriter) throws JspException{
if (shouldRender()) {
return doWrite(tagWriter);
}
return BodyTag.SKIP_BODY;
}
protected int doWrite(TagWriter tagWriter) throws JspException {
try {
tagWriter.startTag(getElement());
writeDefaultAttributes(tagWriter);
String delimiter = ObjectUtils.getDisplayString(evaluate("delimiter", getDelimiter()));
List<String> errorMessages = null;
if (this.getPath() != null) {
errorMessages = getFieldErrorMessages(bind.getFieldErrors(this.getPath()));
} else {
errorMessages = getGlobalErrorMessages(bind.getGlobalErrors());
}
tagWriter.appendValue("<ul>");
for (int i = 0; i < errorMessages.size(); i++) {
String errorMessage = errorMessages.get(i);
tagWriter.appendValue("<li>");
tagWriter.appendValue(getDisplayString(errorMessage));
tagWriter.appendValue("</li>");
}
tagWriter.appendValue("</ul>");
tagWriter.forceBlock();
tagWriter.endTag();
} catch (NullPointerException ex) {
ex.printStackTrace();
}
return BodyTag.EVAL_BODY_INCLUDE;
}