diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java index df49570d..254b0c22 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java @@ -16,7 +16,9 @@ package org.springframework.faces.webflow; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import javax.el.ELContext; import javax.faces.FactoryFinder; @@ -33,6 +35,8 @@ import javax.faces.render.RenderKit; import org.springframework.binding.message.Message; import org.springframework.binding.message.MessageBuilder; +import org.springframework.binding.message.MessageCriteria; +import org.springframework.binding.message.MessageResolver; import org.springframework.binding.message.Severity; import org.springframework.context.MessageSource; import org.springframework.util.ClassUtils; @@ -59,6 +63,16 @@ public class FlowFacesContext extends FacesContext { */ static final String RENDER_RESPONSE_KEY = "flowRenderResponse"; + /** + * Key for identifying summary messages + */ + static final String SUMMARY_MESSAGE_KEY = "_summary"; + + /** + * Key for identifying detail messages + */ + static final String DETAIL_MESSAGE_KEY = "_detail"; + /** * The key for storing the renderResponse flag */ @@ -88,25 +102,48 @@ public class FlowFacesContext extends FacesContext { * Translates a FacesMessage to an SWF Message and adds it to the current MessageContext */ public void addMessage(String clientId, FacesMessage message) { - MessageBuilder builder = new MessageBuilder(); - StringBuffer msgText = new StringBuffer(); - if (StringUtils.hasText(message.getSummary())) { - msgText.append(message.getSummary()); - } - String source = null; if (StringUtils.hasText(clientId)) { source = clientId; } - if (message.getSeverity() == FacesMessage.SEVERITY_INFO) { - builder.source(source).defaultText(msgText.toString()).info(); - } else if (message.getSeverity() == FacesMessage.SEVERITY_WARN) { - builder.source(source).defaultText(msgText.toString()).warning(); - } else { - builder.source(source).defaultText(msgText.toString()).error(); + StringBuffer summaryText = new StringBuffer(); + if (StringUtils.hasText(message.getSummary())) { + summaryText.append(message.getSummary()); } - context.getMessageContext().addMessage(builder.build()); + + String summarySource = source + SUMMARY_MESSAGE_KEY; + MessageResolver summaryResolver; + if (message.getSeverity() == FacesMessage.SEVERITY_INFO) { + summaryResolver = new MessageBuilder().source(summarySource).defaultText(summaryText.toString()).info() + .build(); + } else if (message.getSeverity() == FacesMessage.SEVERITY_WARN) { + summaryResolver = new MessageBuilder().source(summarySource).defaultText(summaryText.toString()).warning() + .build(); + } else { + summaryResolver = new MessageBuilder().source(summarySource).defaultText(summaryText.toString()).error() + .build(); + } + context.getMessageContext().addMessage(summaryResolver); + + StringBuffer detailText = new StringBuffer(); + if (StringUtils.hasText(message.getDetail())) { + detailText.append(message.getDetail()); + } + String detailSource = source + DETAIL_MESSAGE_KEY; + MessageResolver detailResolver; + if (message.getSeverity() == FacesMessage.SEVERITY_INFO) { + detailResolver = new MessageBuilder().source(detailSource).defaultText(detailText.toString()).info() + .build(); + } else if (message.getSeverity() == FacesMessage.SEVERITY_WARN) { + detailResolver = new MessageBuilder().source(detailSource).defaultText(detailText.toString()).warning() + .build(); + } else { + detailResolver = new MessageBuilder().source(detailSource).defaultText(detailText.toString()).error() + .build(); + } + context.getMessageContext().addMessage(detailResolver); + } /** @@ -237,18 +274,54 @@ public class FlowFacesContext extends FacesContext { return delegate; } + // ------------------ Private helper methods ----------------------// + + private FacesMessage toFacesMessage(Message summaryMessage, Message detailMessage) { + if (summaryMessage.getSeverity() == Severity.INFO) { + return new FacesMessage(FacesMessage.SEVERITY_INFO, summaryMessage.getText(), detailMessage.getText()); + } else if (summaryMessage.getSeverity() == Severity.WARNING) { + return new FacesMessage(FacesMessage.SEVERITY_WARN, summaryMessage.getText(), detailMessage.getText()); + } else { + return new FacesMessage(FacesMessage.SEVERITY_ERROR, summaryMessage.getText(), detailMessage.getText()); + } + } + private class FacesMessageIterator implements Iterator { - private Message[] messages; + private Object[] messages; private int currentIndex = -1; protected FacesMessageIterator() { - this.messages = context.getMessageContext().getAllMessages(); + Message[] summaryMessages = context.getMessageContext().getMessagesByCriteria(new SummaryMessageCriteria()); + Message[] detailMessages = context.getMessageContext().getMessagesByCriteria(new DetailMessageCriteria()); + Message[] userMessages = context.getMessageContext().getMessagesByCriteria(new UserMessageCriteria()); + + List translatedMessages = new ArrayList(); + for (int i = 0; i < summaryMessages.length; i++) { + translatedMessages.add(toFacesMessage(summaryMessages[i], detailMessages[i])); + } + for (int z = 0; z < userMessages.length; z++) { + translatedMessages.add(toFacesMessage(userMessages[z], userMessages[z])); + } + + this.messages = translatedMessages.toArray(); } protected FacesMessageIterator(String clientId) { - this.messages = context.getMessageContext().getMessagesBySource(clientId); + Message[] summaryMessages = context.getMessageContext().getMessagesBySource(clientId + SUMMARY_MESSAGE_KEY); + Message[] detailMessages = context.getMessageContext().getMessagesBySource(clientId + DETAIL_MESSAGE_KEY); + Message[] userMessages = context.getMessageContext().getMessagesBySource(clientId); + + List translatedMessages = new ArrayList(); + for (int i = 0; i < summaryMessages.length; i++) { + translatedMessages.add(toFacesMessage(summaryMessages[i], detailMessages[i])); + } + for (int z = 0; z < userMessages.length; z++) { + translatedMessages.add(toFacesMessage(userMessages[z], userMessages[z])); + } + + this.messages = translatedMessages.toArray(); } public boolean hasNext() { @@ -257,19 +330,7 @@ public class FlowFacesContext extends FacesContext { public Object next() { currentIndex++; - Message nextMessage = messages[currentIndex]; - FacesMessage facesMessage; - if (nextMessage.getSeverity() == Severity.INFO) { - facesMessage = new FacesMessage(FacesMessage.SEVERITY_INFO, nextMessage.getText(), nextMessage - .getText()); - } else if (nextMessage.getSeverity() == Severity.WARNING) { - facesMessage = new FacesMessage(FacesMessage.SEVERITY_WARN, nextMessage.getText(), nextMessage - .getText()); - } else { - facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, nextMessage.getText(), nextMessage - .getText()); - } - return facesMessage; + return messages[currentIndex]; } public void remove() { @@ -285,26 +346,20 @@ public class FlowFacesContext extends FacesContext { int currentIndex = -1; protected ClientIdIterator() { - this.messages = context.getMessageContext().getAllMessages(); + this.messages = context.getMessageContext().getMessagesByCriteria(new IdentifiedMessageCriteria()); } public boolean hasNext() { - while (messages.length > currentIndex + 1) { - Message next = messages[currentIndex + 1]; - if (next.getSource() != null && !"".equals(next.getSource())) { - return true; - } - currentIndex++; - } - return false; + return messages.length > currentIndex + 1; } public Object next() { Message next = messages[++currentIndex]; - while (next.getSource() == null || "".equals(next.getSource())) { - next = messages[++currentIndex]; + if (next.getSource().toString().endsWith(SUMMARY_MESSAGE_KEY)) { + return next.getSource().toString().replaceAll(SUMMARY_MESSAGE_KEY, ""); + } else { + return next.getSource().toString(); } - return next.getSource().toString(); } public void remove() { @@ -338,4 +393,48 @@ public class FlowFacesContext extends FacesContext { } + private class SummaryMessageCriteria implements MessageCriteria { + + public boolean test(Message message) { + if (message.getSource() == null) { + return false; + } + return message.getSource().toString().endsWith(SUMMARY_MESSAGE_KEY); + } + } + + private class DetailMessageCriteria implements MessageCriteria { + + public boolean test(Message message) { + if (message.getSource() == null) { + return false; + } + return message.getSource().toString().endsWith(DETAIL_MESSAGE_KEY); + } + } + + private class UserMessageCriteria implements MessageCriteria { + + public boolean test(Message message) { + if (message.getSource() == null) { + return true; + } + return !message.getSource().toString().endsWith(SUMMARY_MESSAGE_KEY) + && !message.getSource().toString().endsWith(DETAIL_MESSAGE_KEY); + } + } + + private class IdentifiedMessageCriteria implements MessageCriteria { + + String nullSummaryId = null + SUMMARY_MESSAGE_KEY; + + public boolean test(Message message) { + if (message.getSource() == null || message.getSource().equals("") + || message.getSource().equals(nullSummaryId) + || message.getSource().toString().endsWith(DETAIL_MESSAGE_KEY)) { + return false; + } + return true; + } + } } diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/FlowFacesContextTests.java b/spring-faces/src/test/java/org/springframework/faces/webflow/FlowFacesContextTests.java index 82299f7b..720d7cb0 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/FlowFacesContextTests.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/FlowFacesContextTests.java @@ -8,7 +8,9 @@ import javax.faces.context.FacesContext; import junit.framework.TestCase; import org.easymock.EasyMock; +import org.springframework.binding.message.DefaultMessageContext; import org.springframework.binding.message.Message; +import org.springframework.binding.message.MessageBuilder; import org.springframework.binding.message.MessageContext; import org.springframework.binding.message.MessageCriteria; import org.springframework.binding.message.MessageResolver; @@ -25,9 +27,13 @@ public class FlowFacesContextTests extends TestCase { MessageContext messageContext; + MessageContext prepopulatedMessageContext; + protected void setUp() throws Exception { jsf.setUp(); facesContext = new FlowFacesContext(requestContext, jsf.facesContext()); + + setupMessageContext(); } protected void tearDown() throws Exception { @@ -39,17 +45,41 @@ public class FlowFacesContextTests extends TestCase { } public final void testAddMessage() { - messageContext = new TestAddMessageContext(); + messageContext = new DefaultMessageContext(); EasyMock.expect(requestContext.getMessageContext()).andStubReturn(messageContext); EasyMock.replay(new Object[] { requestContext }); - facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "foo", "foo")); + facesContext.addMessage("foo", new FacesMessage(FacesMessage.SEVERITY_INFO, "foo", "bar")); - assertEquals("Message count is incorrect", 1, ((TestAddMessageContext) messageContext).messageCount); + assertEquals("Message count is incorrect", 2, messageContext.getAllMessages().length); + Message summaryMessage = messageContext.getMessagesBySource("foo_summary")[0]; + assertEquals("foo", summaryMessage.getText()); + Message detailMessage = messageContext.getMessagesBySource("foo_detail")[0]; + assertEquals("bar", detailMessage.getText()); + + } + + public final void testAddMessages_MultipleNullIds() { + messageContext = new DefaultMessageContext(); + EasyMock.expect(requestContext.getMessageContext()).andStubReturn(messageContext); + EasyMock.replay(new Object[] { requestContext }); + + facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "foo", "bar")); + facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "zoo", "zar")); + + assertEquals("Message count is incorrect", 4, messageContext.getAllMessages().length); + Message summaryMessage1 = messageContext.getMessagesBySource("null_summary")[0]; + assertEquals("foo", summaryMessage1.getText()); + Message detailMessage1 = messageContext.getMessagesBySource("null_detail")[0]; + assertEquals("bar", detailMessage1.getText()); + Message summaryMessage2 = messageContext.getMessagesBySource("null_summary")[1]; + assertEquals("zoo", summaryMessage2.getText()); + Message detailMessage2 = messageContext.getMessagesBySource("null_detail")[1]; + assertEquals("zar", detailMessage2.getText()); } public final void testGetMessages() { - messageContext = new TestGetMessagesContext(); + messageContext = prepopulatedMessageContext; EasyMock.expect(requestContext.getMessageContext()).andStubReturn(messageContext); EasyMock.replay(new Object[] { requestContext }); @@ -59,72 +89,94 @@ public class FlowFacesContextTests extends TestCase { assertNotNull(i.next()); iterationCount++; } - assertEquals(3, iterationCount); + assertEquals("There should be 4 messages to iterate", 4, iterationCount); } - public final void testGetMessagesByClientId() { - messageContext = new TestGetMessagesContext(); + public final void testGetMessagesByClientId_ForComponent() { + messageContext = prepopulatedMessageContext; EasyMock.expect(requestContext.getMessageContext()).andStubReturn(messageContext); EasyMock.replay(new Object[] { requestContext }); int iterationCount = 0; Iterator i = facesContext.getMessages("componentId"); while (i.hasNext()) { - assertNotNull(i.next()); + FacesMessage message = (FacesMessage) i.next(); + assertNotNull(message); + assertEquals("componentId_summary", message.getSummary()); + assertEquals("componentId_detail", message.getDetail()); iterationCount++; } assertEquals(1, iterationCount); } + public final void testGetMessagesByClientId_ForUserMessage() { + messageContext = prepopulatedMessageContext; + EasyMock.expect(requestContext.getMessageContext()).andStubReturn(messageContext); + EasyMock.replay(new Object[] { requestContext }); + + int iterationCount = 0; + Iterator i = facesContext.getMessages("userMessage"); + while (i.hasNext()) { + FacesMessage message = (FacesMessage) i.next(); + assertNotNull(message); + assertEquals("userMessage", message.getSummary()); + assertEquals("userMessage", message.getDetail()); + iterationCount++; + } + assertEquals(1, iterationCount); + } + + public final void testgetMessagesByClientId_InvalidId() { + messageContext = prepopulatedMessageContext; + EasyMock.expect(requestContext.getMessageContext()).andStubReturn(messageContext); + EasyMock.replay(new Object[] { requestContext }); + + int iterationCount = 0; + Iterator i = facesContext.getMessages("unknown"); + while (i.hasNext()) { + iterationCount++; + } + assertEquals(0, iterationCount); + } + public final void testGetClientIdsWithMessages() { - messageContext = new TestGetMessagesContext(); + messageContext = prepopulatedMessageContext; EasyMock.expect(requestContext.getMessageContext()).andStubReturn(messageContext); EasyMock.replay(new Object[] { requestContext }); int iterationCount = 0; Iterator i = facesContext.getClientIdsWithMessages(); while (i.hasNext()) { - String id = (String) i.next(); - assertEquals("componentId", id); + i.next(); iterationCount++; } - assertEquals(1, iterationCount); + assertEquals(2, iterationCount); } public final void testGetMaximumSeverity() { - messageContext = new TestGetMessagesContext(); + messageContext = prepopulatedMessageContext; EasyMock.expect(requestContext.getMessageContext()).andStubReturn(messageContext); EasyMock.replay(new Object[] { requestContext }); assertEquals(FacesMessage.SEVERITY_ERROR, facesContext.getMaximumSeverity()); } - private class TestAddMessageContext implements MessageContext { - int messageCount = 0; - - public void addMessage(MessageResolver messageResolver) { - messageCount++; - } - - public Message[] getAllMessages() { - return null; - } - - public Message[] getMessagesBySource(Object source) { - throw new UnsupportedOperationException("Auto-generated method stub"); - } - - public Message[] getMessagesByCriteria(MessageCriteria criteria) { - throw new UnsupportedOperationException("Auto-generated method stub"); - } - - public boolean hasErrorMessages() { - throw new UnsupportedOperationException("Auto-generated method stub"); - } - - public void clearMessages() { - throw new UnsupportedOperationException("Auto-generated method stub"); - } + private void setupMessageContext() { + prepopulatedMessageContext = new DefaultMessageContext(); + prepopulatedMessageContext.addMessage(new MessageBuilder().source("null_summary").defaultText("foo").info() + .build()); + prepopulatedMessageContext.addMessage(new MessageBuilder().source("null_detail").defaultText("foo").info() + .build()); + prepopulatedMessageContext.addMessage(new MessageBuilder().source("componentId_summary").defaultText( + "componentId_summary").warning().build()); + prepopulatedMessageContext.addMessage(new MessageBuilder().source("componentId_detail").defaultText( + "componentId_detail").warning().build()); + prepopulatedMessageContext.addMessage(new MessageBuilder().source("userMessage").defaultText("userMessage") + .info().build()); + prepopulatedMessageContext.addMessage(new MessageBuilder().source("null_summary").defaultText("baz").error() + .build()); + prepopulatedMessageContext.addMessage(new MessageBuilder().source("null_detail").defaultText("baz").error() + .build()); } private class TestGetMessagesContext implements MessageContext { @@ -132,10 +184,14 @@ public class FlowFacesContextTests extends TestCase { Message[] messages; TestGetMessagesContext() { - messages = new Message[3]; - messages[0] = new Message(null, "foo", Severity.INFO); - messages[1] = new Message("componentId", "bar", Severity.WARNING); - messages[2] = new Message(null, "baz", Severity.ERROR); + messages = new Message[7]; + messages[0] = new Message("null_summary", "foo", Severity.INFO); + messages[1] = new Message("null_detail", "foo", Severity.INFO); + messages[2] = new Message("componentId_summary", "bar", Severity.WARNING); + messages[3] = new Message("componentId_detail", "bar", Severity.WARNING); + messages[4] = new Message("userMessage", "userMessage", Severity.INFO); + messages[5] = new Message("null_summary", "baz", Severity.ERROR); + messages[6] = new Message("null_detail", "baz", Severity.ERROR); } public void addMessage(MessageResolver messageResolver) {