/* * Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com) * Licensed under the Apache License, Version 2.0 (the "License") * $Id: ConstrainedBean.java 3918 2008-04-14 17:35:35Z gbevin $ */ package com.uwyn.rife.site; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import com.uwyn.rife.datastructures.EnumClass; /** * A <code>ConstrainedBean</code> object makes it possible to define all * constraints for a bean instance that are not related to a single property. * The constraints here are global for the entire bean and either involve * several properties or are even totally unrelated to properties. * <p>It's possible to add constraints to a ConstrainedProperty instance * through regular setters, but chainable setters are also available to make * it possible to easily define a series of constraints, for example: * <pre>ConstrainedBean constrained = new ConstrainedBean() * .unique("firstName", "lastName") * .defaultOrder("city") * .defaultOrder("lastName") * .defaultOrder("firstName");</pre> * <p> * <p>A constrained bean is typically added to a {@link Constrained} bean in * its constructor. These are the static constraints that will be set for each * and every instance of the bean. You'll however most of the time use the * {@link Validation} abstract class that provides the {@link * Validation#activateValidation activateValidation} method which initializes * the constraints on a need-to-have basis. This dramatically reduces memory * usage since otherwise all constraints will be initialized for every bean * instance, even though you don't use them. * * @author Geert Bevin (gbevin[remove] at uwyn dot com) * @see Constrained * @see ConstrainedProperty * @version $Revision: 3918 $ * @since 1.0 */ public class ConstrainedBean<T extends ConstrainedBean> { public static final Direction ASC = new Direction("ASC"); public static final Direction DESC = new Direction("DESC"); // standard constraint identifiers public final static String ASSOCIATIONS = "ASSOCIATIONS"; public final static String UNIQUE = "UNIQUE"; public final static String TEXTUAL_IDENTIFIER = "TEXTUAL_IDENTIFIER"; public final static String DEFAULT_ORDERING = "DEFAULT_ORDERING"; // constraints protected HashMap<String, Object> mConstraints = new HashMap<String, Object>(); /** * Creates a new <code>ConstrainedBean</code>. * * @since 1.0 */ public ConstrainedBean() { } public T associations(Class... associations) { setAssociations(associations); return (T)this; } public void setAssociations(Class... associations) { if (null == associations) { mConstraints.remove(ASSOCIATIONS); } else { mConstraints.put(ASSOCIATIONS, associations); } } public Class[] getAssociations() { return (Class[])mConstraints.get(ASSOCIATIONS); } public boolean hasAssociations() { return mConstraints.containsKey(ASSOCIATIONS) && ((Class[])mConstraints.get(ASSOCIATIONS)).length > 0; } public T unique(String... unique) { if (unique != null) { List<String[]> unique_list = (List<String[]>)mConstraints.get(UNIQUE); if (null == unique_list) { unique_list = new ArrayList<String[]>(); mConstraints.put(UNIQUE, unique_list); } unique_list.add(unique); } return (T)this; } public T uniques(List<String[]> unique) { setUniques(unique); return (T)this; } public void setUniques(List<String[]> unique) { if (null == unique) { mConstraints.remove(UNIQUE); } else { mConstraints.put(UNIQUE, unique); } } public List<String[]> getUniques() { return (List<String[]>)mConstraints.get(UNIQUE); } public boolean hasUniques() { return mConstraints.containsKey(UNIQUE) && ((List<String[]>)mConstraints.get(UNIQUE)).size() > 0; } public T textualIdentifier(TextualIdentifierGenerator identifier) { setTextualIdentifier(identifier); return (T)this; } public void setTextualIdentifier(TextualIdentifierGenerator identifier) { if (null == identifier) { mConstraints.remove(TEXTUAL_IDENTIFIER); } else { mConstraints.put(TEXTUAL_IDENTIFIER, identifier); } } public TextualIdentifierGenerator getTextualIdentifier() { return (TextualIdentifierGenerator)mConstraints.get(TEXTUAL_IDENTIFIER); } public boolean hasTextualIdentifier() { return mConstraints.containsKey(TEXTUAL_IDENTIFIER); } public T defaultOrder(String propertyName) { return defaultOrder(propertyName, ASC); } public T defaultOrder(String propertyName, Direction direction) { return defaultOrder(new Order(propertyName, direction)); } public T defaultOrder(Order order) { if (order != null) { List<Order> ordering_list = (List<Order>)mConstraints.get(DEFAULT_ORDERING); if (null == ordering_list) { ordering_list = new ArrayList<Order>(); mConstraints.put(DEFAULT_ORDERING, ordering_list); } ordering_list.add(order); } return (T)this; } public T defaultOrdering(List<Order> ordering) { setDefaultOrdering(ordering); return (T)this; } public void setDefaultOrdering(List<Order> ordering) { if (null == ordering) { mConstraints.remove(DEFAULT_ORDERING); } else { mConstraints.put(DEFAULT_ORDERING, ordering); } } public List<Order> getDefaultOrdering() { return (List<Order>)mConstraints.get(DEFAULT_ORDERING); } public boolean hasDefaultOrdering() { return mConstraints.containsKey(DEFAULT_ORDERING) && ((List<Order>)mConstraints.get(DEFAULT_ORDERING)).size() > 0; } HashMap<String, Object> getConstraints() { return mConstraints; } public static class Order implements Cloneable { private String mPropertyName = null; private Direction mDirection = null; public Order(String property, Direction direction) { setPropertyName(property); setDirection(direction); } public String getPropertyName() { return mPropertyName; } void setPropertyName(String propertyName) { if (null == propertyName) throw new IllegalArgumentException("propertyName can't be null."); if (0 == propertyName.length()) throw new IllegalArgumentException("propertyName can't be empty."); mPropertyName = propertyName; } public Direction getDirection() { return mDirection; } void setDirection(Direction direction) { if (null == direction) throw new IllegalArgumentException("direction can't be null."); mDirection = direction; } public Order clone() { Order new_instance; try { new_instance = (Order)super.clone(); } catch (CloneNotSupportedException e) { new_instance = null; } return new_instance; } } public static class Direction extends EnumClass<String> { Direction(String identifier) { super(identifier); } } }