001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: ConstrainedBean.java 3669 2007-02-26 13:51:23Z gbevin $
007: */
008: package com.uwyn.rife.site;
009:
010: import java.util.ArrayList;
011: import java.util.HashMap;
012: import java.util.List;
013:
014: import com.uwyn.rife.datastructures.EnumClass;
015:
016: /**
017: * A <code>ConstrainedBean</code> object makes it possible to define all
018: * constraints for a bean instance that are not related to a single property.
019: * The constraints here are global for the entire bean and either involve
020: * several properties or are even totally unrelated to properties.
021: * <p>It's possible to add constraints to a ConstrainedProperty instance
022: * through regular setters, but chainable setters are also available to make
023: * it possible to easily define a series of constraints, for example:
024: * <pre>ConstrainedBean constrained = new ConstrainedBean()
025: * .unique("firstName", "lastName")
026: * .defaultOrder("city")
027: * .defaultOrder("lastName")
028: * .defaultOrder("firstName");</pre>
029: * <p>
030: * <p>A constrained bean is typically added to a {@link Constrained} bean in
031: * its constructor. These are the static constraints that will be set for each
032: * and every instance of the bean. You'll however most of the time use the
033: * {@link Validation} abstract class that provides the {@link
034: * Validation#activateValidation activateValidation} method which initializes
035: * the constraints on a need-to-have basis. This dramatically reduces memory
036: * usage since otherwise all constraints will be initialized for every bean
037: * instance, even though you don't use them.
038: *
039: * @author Geert Bevin (gbevin[remove] at uwyn dot com)
040: * @see Constrained
041: * @see ConstrainedProperty
042: * @version $Revision: 3669 $
043: * @since 1.0
044: */
045: public class ConstrainedBean<T extends ConstrainedBean> {
046: public static final Direction ASC = new Direction("ASC");
047: public static final Direction DESC = new Direction("DESC");
048:
049: // standard constraint identifiers
050: public final static String ASSOCIATIONS = "ASSOCIATIONS";
051: public final static String UNIQUE = "UNIQUE";
052: public final static String TEXTUAL_IDENTIFIER = "TEXTUAL_IDENTIFIER";
053: public final static String DEFAULT_ORDERING = "DEFAULT_ORDERING";
054:
055: // constraints
056: protected HashMap<String, Object> mConstraints = new HashMap<String, Object>();
057:
058: /**
059: * Creates a new <code>ConstrainedBean</code>.
060: *
061: * @since 1.0
062: */
063: public ConstrainedBean() {
064: }
065:
066: public T associations(Class... associations) {
067: setAssociations(associations);
068:
069: return (T) this ;
070: }
071:
072: public void setAssociations(Class... associations) {
073: if (null == associations) {
074: mConstraints.remove(ASSOCIATIONS);
075: } else {
076: mConstraints.put(ASSOCIATIONS, associations);
077: }
078: }
079:
080: public Class[] getAssociations() {
081: return (Class[]) mConstraints.get(ASSOCIATIONS);
082: }
083:
084: public boolean hasAssociations() {
085: return mConstraints.containsKey(ASSOCIATIONS)
086: && ((Class[]) mConstraints.get(ASSOCIATIONS)).length > 0;
087: }
088:
089: public T unique(String... unique) {
090: if (unique != null) {
091: List<String[]> unique_list = (List<String[]>) mConstraints
092: .get(UNIQUE);
093: if (null == unique_list) {
094: unique_list = new ArrayList<String[]>();
095: mConstraints.put(UNIQUE, unique_list);
096: }
097:
098: unique_list.add(unique);
099: }
100:
101: return (T) this ;
102: }
103:
104: public T uniques(List<String[]> unique) {
105: setUniques(unique);
106:
107: return (T) this ;
108: }
109:
110: public void setUniques(List<String[]> unique) {
111: if (null == unique) {
112: mConstraints.remove(UNIQUE);
113: } else {
114: mConstraints.put(UNIQUE, unique);
115: }
116: }
117:
118: public List<String[]> getUniques() {
119: return (List<String[]>) mConstraints.get(UNIQUE);
120: }
121:
122: public boolean hasUniques() {
123: return mConstraints.containsKey(UNIQUE)
124: && ((List<String[]>) mConstraints.get(UNIQUE)).size() > 0;
125: }
126:
127: public T textualIdentifier(TextualIdentifierGenerator identifier) {
128: setTextualIdentifier(identifier);
129:
130: return (T) this ;
131: }
132:
133: public void setTextualIdentifier(
134: TextualIdentifierGenerator identifier) {
135: if (null == identifier) {
136: mConstraints.remove(TEXTUAL_IDENTIFIER);
137: } else {
138: mConstraints.put(TEXTUAL_IDENTIFIER, identifier);
139: }
140: }
141:
142: public TextualIdentifierGenerator getTextualIdentifier() {
143: return (TextualIdentifierGenerator) mConstraints
144: .get(TEXTUAL_IDENTIFIER);
145: }
146:
147: public boolean hasTextualIdentifier() {
148: return mConstraints.containsKey(TEXTUAL_IDENTIFIER);
149: }
150:
151: public T defaultOrder(String propertyName) {
152: return defaultOrder(propertyName, ASC);
153: }
154:
155: public T defaultOrder(String propertyName, Direction direction) {
156: return defaultOrder(new Order(propertyName, direction));
157: }
158:
159: public T defaultOrder(Order order) {
160: if (order != null) {
161: List<Order> ordering_list = (List<Order>) mConstraints
162: .get(DEFAULT_ORDERING);
163: if (null == ordering_list) {
164: ordering_list = new ArrayList<Order>();
165: mConstraints.put(DEFAULT_ORDERING, ordering_list);
166: }
167:
168: ordering_list.add(order);
169: }
170:
171: return (T) this ;
172: }
173:
174: public T defaultOrdering(List<Order> ordering) {
175: setDefaultOrdering(ordering);
176:
177: return (T) this ;
178: }
179:
180: public void setDefaultOrdering(List<Order> ordering) {
181: if (null == ordering) {
182: mConstraints.remove(DEFAULT_ORDERING);
183: } else {
184: mConstraints.put(DEFAULT_ORDERING, ordering);
185: }
186: }
187:
188: public List<Order> getDefaultOrdering() {
189: return (List<Order>) mConstraints.get(DEFAULT_ORDERING);
190: }
191:
192: public boolean hasDefaultOrdering() {
193: return mConstraints.containsKey(DEFAULT_ORDERING)
194: && ((List<Order>) mConstraints.get(DEFAULT_ORDERING))
195: .size() > 0;
196: }
197:
198: HashMap<String, Object> getConstraints() {
199: return mConstraints;
200: }
201:
202: public static class Order implements Cloneable {
203: private String mPropertyName = null;
204: private Direction mDirection = null;
205:
206: public Order(String property, Direction direction) {
207: setPropertyName(property);
208: setDirection(direction);
209: }
210:
211: public String getPropertyName() {
212: return mPropertyName;
213: }
214:
215: void setPropertyName(String propertyName) {
216: if (null == propertyName)
217: throw new IllegalArgumentException(
218: "propertyName can't be null.");
219: if (0 == propertyName.length())
220: throw new IllegalArgumentException(
221: "propertyName can't be empty.");
222:
223: mPropertyName = propertyName;
224: }
225:
226: public Direction getDirection() {
227: return mDirection;
228: }
229:
230: void setDirection(Direction direction) {
231: if (null == direction)
232: throw new IllegalArgumentException(
233: "direction can't be null.");
234:
235: mDirection = direction;
236: }
237:
238: public Order clone() {
239: Order new_instance;
240: try {
241: new_instance = (Order) super .clone();
242: } catch (CloneNotSupportedException e) {
243: new_instance = null;
244: }
245:
246: return new_instance;
247: }
248: }
249:
250: public static class Direction extends EnumClass<String> {
251: Direction(String identifier) {
252: super(identifier);
253: }
254: }
255: }
|