UI message system initial commit; support for adding UI messages of different severities INFO, WARNING, ERROR, FATAL
This commit is contained in:
@@ -3,13 +3,38 @@ package org.springframework.ui.binding;
|
||||
import java.util.Map;
|
||||
|
||||
public interface BindingFailure {
|
||||
|
||||
|
||||
/**
|
||||
* The code identifying the type of failure.
|
||||
* This code can be used to resolve the failure message if no explicit {@link #getMessage() message} is configured.
|
||||
*/
|
||||
String getCode();
|
||||
|
||||
String getSeverity();
|
||||
|
||||
// TODO - where does arg formatting occur
|
||||
Map<String, Object> getArgs();
|
||||
/**
|
||||
* The severity of the failure, which measures the impact of the failure on the user.
|
||||
*/
|
||||
Severity getSeverity();
|
||||
|
||||
/**
|
||||
* An map of arguments that can be used as named parameters in resolvable messages associated with this failure.
|
||||
* Each constraint defines a set of arguments that are specific to it. For example, a length
|
||||
* constraint might define arguments of "min" and "max" of Integer values. In the message bundle, you then might see
|
||||
* "length=The ${label} field value must be between ${min} and ${max}". Returns an empty map if no arguments are present.
|
||||
*/
|
||||
Map<String, Object> getArguments();
|
||||
|
||||
/**
|
||||
* The message summarizing this failure. May be a literal string or a resolvable message code. Can be null.
|
||||
* If null, the failure message will be resolved using the failure code.
|
||||
*/
|
||||
String getDefaultMessage();
|
||||
|
||||
/**
|
||||
* A map of details providing additional information about this failure. Each entry in this map is a failure detail
|
||||
* item that has a name and value. The name uniquely identifies the failure detail and describes its purpose;
|
||||
* for example, a "cause" or "recommendedAction". The value is the failure detail message, either a literal string or
|
||||
* resolvable code. If resolvable, the detail code is resolved relative to this failure.
|
||||
* Returns an empty map if no details are present.
|
||||
*/
|
||||
Map<String, String> getDetails();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ui.message;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
class DefaultMessageResolver implements MessageResolver, MessageSourceResolvable {
|
||||
|
||||
private Severity severity;
|
||||
|
||||
private String[] codes;
|
||||
|
||||
private Object[] args;
|
||||
|
||||
private String defaultText;
|
||||
|
||||
public DefaultMessageResolver(Severity severity, String[] codes, Object[] args, String defaultText) {
|
||||
this.severity = severity;
|
||||
this.codes = codes;
|
||||
this.args = args;
|
||||
this.defaultText = defaultText;
|
||||
}
|
||||
|
||||
// implementing MessageResolver
|
||||
|
||||
public Message resolveMessage(MessageSource messageSource, Locale locale) {
|
||||
String text = messageSource.getMessage(this, locale);
|
||||
return new TextMessage(severity, text);
|
||||
}
|
||||
|
||||
// implementing MessageSourceResolver
|
||||
|
||||
public String[] getCodes() {
|
||||
return codes;
|
||||
}
|
||||
|
||||
public Object[] getArguments() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public String getDefaultMessage() {
|
||||
return defaultText;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("severity", severity).append("codes", codes).append("args", args).append("defaultText", defaultText).toString();
|
||||
}
|
||||
|
||||
static class TextMessage implements Message {
|
||||
|
||||
private Severity severity;
|
||||
|
||||
private String text;
|
||||
|
||||
public TextMessage(Severity severity, String text) {
|
||||
this.severity = severity;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public Severity getSeverity() {
|
||||
return severity;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2004-2009 the original author oimport java.io.Serializable;
|
||||
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
ou may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ui.message;
|
||||
|
||||
/**
|
||||
* Communicates information about an event to the user.
|
||||
* For example, a validation message may inform a web application user a business rule was violated.
|
||||
* A message is attached to a receiving element, has text providing the basis for communication,
|
||||
* and has severity indicating the priority or intensity of the message for its receiver.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface Message {
|
||||
|
||||
/**
|
||||
* The severity of this message.
|
||||
* The severity indicates the intensity or priority of the communication.
|
||||
* @return the message severity
|
||||
*/
|
||||
public Severity getSeverity();
|
||||
|
||||
/**
|
||||
* The message text.
|
||||
* The text is the message's communication payload.
|
||||
* @return the message text
|
||||
*/
|
||||
public String getText();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ui.message;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
/**
|
||||
* A convenient builder for building {@link MessageResolver} objects programmatically.
|
||||
* Often used by model code such as validation logic to conveniently record validation messages.
|
||||
* Supports the production of message resolvers that hard-code their message text,
|
||||
* as well as message resolvers that retrieve their text from a {@link MessageSource}.
|
||||
*
|
||||
* Usage example:
|
||||
* <p>
|
||||
* <pre>
|
||||
* new MessageBuilder().
|
||||
* severity(Severity.ERROR).
|
||||
* code("invalidFormat").
|
||||
* arg("mathForm.decimalField").
|
||||
* arg("#,###.##").
|
||||
* defaultText("The decimal field must be in format #,####.##").
|
||||
* build();
|
||||
* </pre>
|
||||
* </p>
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class MessageBuilder {
|
||||
|
||||
private Set<String> codes = new LinkedHashSet<String>();
|
||||
|
||||
private Severity severity;
|
||||
|
||||
private List<Object> args = new ArrayList<Object>();
|
||||
|
||||
private String defaultText;
|
||||
|
||||
/**
|
||||
* Records the severity of the message.
|
||||
* @return this, for fluent API usage
|
||||
*/
|
||||
public MessageBuilder severity(Severity severity) {
|
||||
this.severity = severity;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the message being built should try and resolve its text using the code provided.
|
||||
* Adds the code to the codes list. Successive calls to this method add additional codes.
|
||||
* Codes are applied in the order they are added.
|
||||
* @param code the message code
|
||||
* @return this, for fluent API usage
|
||||
*/
|
||||
public MessageBuilder code(String code) {
|
||||
codes.add(code);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the message being built has a variable argument.
|
||||
* Adds the arg to the args list. Successive calls to this method add additional args.
|
||||
* Args are applied in the order they are added.
|
||||
* @param arg the message argument value
|
||||
* @return this, for fluent API usage
|
||||
*/
|
||||
public MessageBuilder arg(Object arg) {
|
||||
args.add(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the message being built has a variable argument, whose display value is also {@link MessageSourceResolvable}.
|
||||
* Adds the arg to the args list. Successive calls to this method add additional resolvable args.
|
||||
* Args are applied in the order they are added.
|
||||
* @param arg the resolvable message argument
|
||||
* @return this, for fluent API usage
|
||||
*/
|
||||
public MessageBuilder resolvableArg(Object arg) {
|
||||
args.add(new ResolvableArgument(arg));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the fallback text of the message being built.
|
||||
* If the message has no codes, this will always be used as the text.
|
||||
* If the message has codes but none can be resolved, this will always be used as the text.
|
||||
* @param text the default text
|
||||
* @return this, for fluent API usage
|
||||
*/
|
||||
public MessageBuilder defaultText(String text) {
|
||||
defaultText = text;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the message that will be resolved.
|
||||
* Call after recording builder instructions.
|
||||
* @return the built message resolver
|
||||
*/
|
||||
public MessageResolver build() {
|
||||
if (severity == null) {
|
||||
severity = Severity.INFO;
|
||||
}
|
||||
if (codes == null && defaultText == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"A message code or the message text is required to build this message resolver");
|
||||
}
|
||||
String[] codesArray = (String[]) codes.toArray(new String[codes.size()]);
|
||||
Object[] argsArray = args.toArray(new Object[args.size()]);
|
||||
return new DefaultMessageResolver(severity, codesArray, argsArray, defaultText);
|
||||
}
|
||||
|
||||
private static class ResolvableArgument implements MessageSourceResolvable {
|
||||
|
||||
private Object arg;
|
||||
|
||||
public ResolvableArgument(Object arg) {
|
||||
this.arg = arg;
|
||||
}
|
||||
|
||||
public Object[] getArguments() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] getCodes() {
|
||||
return new String[] { arg.toString() };
|
||||
}
|
||||
|
||||
public String getDefaultMessage() {
|
||||
return arg.toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("arg", arg).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ui.message;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A context for recording and retrieving messages for display in a user interface.
|
||||
*/
|
||||
public interface MessageContext {
|
||||
|
||||
/**
|
||||
* Return all messages in this context indexed by the UI element they are associated with.
|
||||
* @return the message map
|
||||
*/
|
||||
public Map<String, List<Message>> getMessages();
|
||||
|
||||
/**
|
||||
* Get all messages on the UI element provided.
|
||||
* Returns an empty list if no messages have been recorded against the element.
|
||||
* Messages are returned in the order they were added.
|
||||
* @param element the id of the element to lookup messages against
|
||||
*/
|
||||
public List<Message> getMessages(String element);
|
||||
|
||||
/**
|
||||
* Add a new message to this context.
|
||||
* @param element the id of the UI element the message should be associated with
|
||||
* @param messageResolver the resolver that will resolve the message to be added
|
||||
*/
|
||||
public void addMessage(String element, MessageResolver messageResolver);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ui.message;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
|
||||
/**
|
||||
* A factory for a Message. Allows a Message to be internationalized and to be resolved from a
|
||||
* {@link MessageSource message resource bundle}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @see Message
|
||||
* @see MessageSource
|
||||
*/
|
||||
public interface MessageResolver {
|
||||
|
||||
/**
|
||||
* Resolve the message from the message source using the current locale.
|
||||
* @param messageSource the message source, an abstraction for a resource bundle
|
||||
* @param locale the current locale of this request
|
||||
* @return the resolved message
|
||||
*/
|
||||
public Message resolveMessage(MessageSource messageSource, Locale locale);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ui.message;
|
||||
|
||||
/**
|
||||
* Enum exposing supported message severities.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Jeremy Grelle
|
||||
* @see Message
|
||||
*/
|
||||
public enum Severity {
|
||||
|
||||
/**
|
||||
* The "Informational" severity. Used to indicate a successful operation or result.
|
||||
*/
|
||||
INFO,
|
||||
|
||||
/**
|
||||
* The "Warning" severity. Used to indicate there is a minor problem, or to inform the message receiver of possible
|
||||
* misuse, or to indicate a problem may arise in the future.
|
||||
*/
|
||||
WARNING,
|
||||
|
||||
/**
|
||||
* The "Error" severity. Used to indicate a significant problem like a business rule violation.
|
||||
*/
|
||||
ERROR,
|
||||
|
||||
/**
|
||||
* The "Fatal" severity. Used to indicate a fatal problem like a system error.
|
||||
*/
|
||||
FATAL
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
A system for creating and managing localized messages to display in a UI.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ui.message.support;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.context.support.AbstractMessageSource;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.ui.message.Message;
|
||||
import org.springframework.ui.message.MessageContext;
|
||||
import org.springframework.ui.message.MessageResolver;
|
||||
import org.springframework.ui.message.Severity;
|
||||
import org.springframework.util.CachingMapDecorator;
|
||||
|
||||
import edu.emory.mathcs.backport.java.util.Collections;
|
||||
|
||||
/**
|
||||
* The default message context implementation.
|
||||
* Uses a {@link MessageSource} to resolve messages that are added by callers.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class DefaultMessageContext implements MessageContext {
|
||||
|
||||
private MessageSource messageSource;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private Map<String, ArrayList<Message>> messagesByElement = new CachingMapDecorator<String, ArrayList<Message>>(new LinkedHashMap<String, ArrayList<Message>>()) {
|
||||
protected ArrayList<Message> create(String element) {
|
||||
return new ArrayList<Message>();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new default message context.
|
||||
* Defaults to a message source that simply resolves default text and cannot resolve localized message codes.
|
||||
*/
|
||||
public DefaultMessageContext() {
|
||||
init(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new default message context.
|
||||
* @param messageSource the message source to resolve messages added to this context
|
||||
*/
|
||||
public DefaultMessageContext(MessageSource messageSource) {
|
||||
init(messageSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* The message source configured to resolve message text.
|
||||
* @return the message source
|
||||
*/
|
||||
public MessageSource getMessageSource() {
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
// implementing message context
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, List<Message>> getMessages() {
|
||||
return Collections.unmodifiableMap(messagesByElement);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Message> getMessages(String element) {
|
||||
List<Message> messages = messagesByElement.get(element);
|
||||
if (messages.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.unmodifiableList(messages);
|
||||
}
|
||||
|
||||
public void addMessage(String element, MessageResolver messageResolver) {
|
||||
List<Message> messages = messagesByElement.get(element);
|
||||
messages.add(new ResolvableMessage(messageResolver));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("messagesByElement", messagesByElement).toString();
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private void init(MessageSource messageSource) {
|
||||
setMessageSource(messageSource);
|
||||
}
|
||||
|
||||
private void setMessageSource(MessageSource messageSource) {
|
||||
if (messageSource == null) {
|
||||
messageSource = new DefaultTextFallbackMessageSource();
|
||||
}
|
||||
this.messageSource = messageSource;
|
||||
}
|
||||
|
||||
private static class DefaultTextFallbackMessageSource extends AbstractMessageSource {
|
||||
protected MessageFormat resolveCode(String code, Locale locale) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class ResolvableMessage implements Message {
|
||||
|
||||
private MessageResolver resolver;
|
||||
|
||||
private Message resolvedMessage;
|
||||
|
||||
public ResolvableMessage(MessageResolver resolver) {
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
public Severity getSeverity() {
|
||||
return getMessage().getSeverity();
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return getMessage().getText();
|
||||
}
|
||||
|
||||
public Message getMessage() {
|
||||
if (resolvedMessage == null) {
|
||||
resolvedMessage = resolver.resolveMessage(messageSource, LocaleContextHolder.getLocale());
|
||||
}
|
||||
return resolvedMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user