001: /*
002: * Copyright (c) 2003-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package com.jgoodies.validation.message;
032:
033: import com.jgoodies.validation.Severity;
034: import com.jgoodies.validation.ValidationMessage;
035: import com.jgoodies.validation.util.ValidationUtils;
036:
037: /**
038: * An implementation of {@link ValidationMessage} that holds a text message,
039: * the validated object (target), a descriptions of the validated property,
040: * and a description of the role this object takes in the validation context.
041: * The target can be used to identify the source of a validation message.
042: * The role and property together build the <em>aspect</em> that is used
043: * as association key; in other words, it can be used to determine whether
044: * a view is associated with a given message or not.<p>
045: *
046: * <strong>Example:</strong> We validate an invoice that has a shipping address
047: * and a physical address. We want to report that the zip code of the shipping
048: * address is missing. This can be described by:<pre>
049: * String validationRole = "Shipping address";
050: * Address validationTarget = invoice.getShippingAddress();
051: * String validationText = "is mandatory";
052: * String validationProperty= "zip code";
053: * if (validationTarget.getZipCode() ...) {
054: * validationResult.addMessage(
055: * new PropertyValidationMessage(
056: * validationText,
057: * validationTarget,
058: * validationRole,
059: * validationProperty)
060: * );
061: * }
062: * </pre>
063: *
064: * @author Karsten Lentzsch
065: * @version $Revision: 1.6 $
066: */
067: public final class PropertyValidationMessage extends
068: AbstractValidationMessage {
069:
070: /**
071: * Refers to the object that holds the validated property,
072: * for example an instance of an <code>Address</code> class.
073: */
074: private final Object target;
075:
076: /**
077: * Describes the optional role of the validated object, for example
078: * <em>shipping</em> or <em>physical</em> address.
079: */
080: private final String role;
081:
082: /**
083: * Holds the name of the validated property, for example "zip code".
084: */
085: private final String property;
086:
087: // Instance Creation ******************************************************
088:
089: /**
090: * Constructs a PropertyValidationMessage of type warning
091: * for the given text, subject, role description and property description.<p>
092: *
093: * <strong>Examples:</strong><pre>
094: * new PropertyValidationMessage(
095: * "is mandatory", aCustomer, "Customer", "last name");
096: * new PropertyValidationMessage(
097: * "must be over 18", aCustomer, "Customer", "age");
098: *
099: * new PropertyValidationMessage(
100: * "is mandatory", shippingAddress, "Shipping address", "zip code");
101: * new PropertyValidationMessage(
102: * "is mandatory", shippingAddress, "Physical address", "zip code");
103: * </pre>
104: *
105: * @param text describes the validation problem
106: * @param target the object that holds the validated property
107: * @param role describes the target's role in the context
108: * @param property describes the validated property
109: *
110: * @throws NullPointerException if the text, target, role, or property
111: * is <code>null</code>
112: * @throws IllegalArgumentException if severity is <code>Severity.OK</code>
113: */
114: public PropertyValidationMessage(String text, Object target,
115: String role, String property) {
116: this (Severity.WARNING, text, target, role, property);
117: }
118:
119: /**
120: * Constructs a PropertyValidationMessage for the given text,
121: * subject, role description and property description.
122: *
123: * <strong>Examples:</strong><pre>
124: * new PropertyValidationMessage(
125: * Severity.ERROR, "is mandatory", aCustomer, "Customer", "last name");
126: * new PropertyValidationMessage(
127: * Severity.WARNING, "must be over 18", aCustomer, "Customer", "age");
128: *
129: * new PropertyValidationMessage(
130: * Severity.ERROR, "is mandatory", shippingAddress, "Shipping address", "zip code");
131: * new PropertyValidationMessage(
132: * Severity.ERROR, "is mandatory", physicalAddress, "Physical address", "zip code");
133: * </pre>
134: *
135: * @param severity the message severity, either error or warning
136: * @param text describes the validation problem
137: * @param target the object that holds the validated property
138: * @param role describes the target's role in the context
139: * @param property describes the validated property
140: *
141: * @throws NullPointerException if the text, target, role, or property
142: * is <code>null</code>
143: * @throws IllegalArgumentException if severity is <code>Severity.OK</code>
144: */
145: public PropertyValidationMessage(Severity severity, String text,
146: Object target, String role, String property) {
147: super (text, severity);
148: if (target == null)
149: throw new NullPointerException(
150: "The target must not be null.");
151: if (role == null)
152: throw new NullPointerException("The role must not be null.");
153: if (property == null)
154: throw new NullPointerException(
155: "The property must not be null.");
156:
157: this .target = target;
158: this .role = role;
159: this .property = property;
160: }
161:
162: // Accessors **************************************************************
163:
164: /**
165: * Returns the validated object that holds the validated property,
166: * for example an address object. This object can be further described
167: * by a role, for example <em>shipping</em> or <em>physical</em> address.
168: *
169: * @return the validation target that holds the validated property
170: */
171: public Object target() {
172: return target;
173: }
174:
175: /**
176: * Returns a description of the role of the validated object.
177: * The role may differ from the type when multiple instances of the same
178: * type are validated in a larger container.<p>
179: *
180: * Example: An invoice object holds a single <code>Order</code> instance,
181: * and two instances of class <code>Address</code>, one for the shipping
182: * address and another for the physical address. You then may consider
183: * using the following roles: <em>Customer, Shipping address</em>, and
184: * <em>Physical address</em>.
185: *
186: * @return a description of the role of the validated object
187: */
188: public String role() {
189: return role;
190: }
191:
192: /**
193: * Returns a description of the validated object property, for example
194: * "zip code".
195: *
196: * @return a description of the validated property
197: */
198: public String property() {
199: return property;
200: }
201:
202: /**
203: * Returns a description of the validated aspect, that is the target's
204: * role plus the validated property.<p>
205: *
206: * Examples: <pre>
207: * "Customer.last name"
208: * "Customer.age"
209: * "Address.zip code"
210: * "Shipping address.zip code"
211: * "Physical address.zip code"
212: * </pre>
213: *
214: * @return a String that describes the validated aspect
215: */
216: public String aspect() {
217: return role() + "." + property();
218: }
219:
220: /**
221: * Returns a message description as formatted text. This implementation
222: * concatenates the validated aspect, i.e. role + property and
223: * the message text.
224: *
225: * @return a message description as formatted text
226: */
227: @Override
228: public String formattedText() {
229: return aspect() + " " + text();
230: }
231:
232: /**
233: * Returns this message's aspect as association key. This key can be used
234: * to associate messages with views.<p>
235: *
236: * @return this messages's aspect as association key
237: *
238: * @see #aspect()
239: */
240: @Override
241: public Object key() {
242: return aspect();
243: }
244:
245: // Comparison and Hashing *************************************************
246:
247: /**
248: * Compares the specified object with this validation message for equality.
249: * Returns <code>true</code> if and only if the specified object is also
250: * a property validation message, both messages have the same severity,
251: * text, target, role, and property. In other words, two property validation
252: * messages are defined to be equal if and only if they behave one like
253: * the other.<p>
254: *
255: * This implementation first checks if the specified object is this
256: * a property validation message. If so, it returns <code>true</code>;
257: * if not, it checks if the specified object is a property validation message.
258: * If not, it returns <code>false</code>; if so, it checks and returns
259: * if the severities, texts, targets, roles, and properties of both messages
260: * are equal.
261: *
262: * @param o the object to be compared for equality with this validation message.
263: *
264: * @return <code>true</code> if the specified object is equal
265: * to this validation message.
266: *
267: * @see Object#equals(java.lang.Object)
268: */
269: @Override
270: public boolean equals(Object o) {
271: if (o == this )
272: return true;
273: if (!(o instanceof PropertyValidationMessage))
274: return false;
275: PropertyValidationMessage other = (PropertyValidationMessage) o;
276: return severity().equals(other.severity())
277: && ValidationUtils.equals(text(), other.text())
278: && ValidationUtils.equals(target(), other.target())
279: && ValidationUtils.equals(role(), other.role())
280: && ValidationUtils.equals(property(), other.property());
281: }
282:
283: /**
284: * Returns the hash code value for this validation message.
285: * This implementation computes and returns the hash based
286: * on the hash code values of this messages' severity, text,
287: * target, role, and property.<p>
288: *
289: * If this class could be extended, we should check if the formatted text
290: * is <code>null</code>.
291: *
292: * @return the hash code value for this validation message.
293: *
294: * @see Object#hashCode()
295: */
296: @Override
297: public int hashCode() {
298: int result = 17;
299: result = 37 * result + severity().hashCode();
300: result = 37 * result + (text() == null ? 0 : text().hashCode());
301: result = 37 * result
302: + (target() == null ? 0 : target().hashCode());
303: result = 37 * result + (role() == null ? 0 : role().hashCode());
304: result = 37 * result
305: + (property() == null ? 0 : property().hashCode());
306: return result;
307: }
308:
309: }
|