All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.smartlab.web.DataAccessObject Maven / Gradle / Ivy

/*
 * The SmartWeb Framework
 * Copyright (C) 2004-2006
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * For further informations on the SmartWeb Framework please visit
 *
 *                        http://smartweb.sourceforge.net
 */
package net.smartlab.web;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Locale;
import java.util.StringTokenizer;

import net.smartlab.web.bean.ConversionException;
import net.smartlab.web.bean.ConverterManager;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * This interface should be implemented by classes which provide some form of
 * persistence.
 * 
 * @author rlogiacco,gperrone
 * @uml.dependency supplier="net.smartlab.web.DAOException"
 */
public interface DataAccessObject {

	/**
	 * Retrieves from the persistence tier the object which primary key equals
	 * the one specified.
	 * 
	 * @param key the primary key used to search the instance into the
	 *        persistence tier.
	 * @return an object representing the datas stored in the persistence tier
	 *         associated with the specified key.
	 * @throws DAOException if an error occur while accessing the persistence
	 *         tier.
	 * @throws UndefinedKeyException if the specified primary key is not present
	 *         on the persistence tier.
	 */
	public Object findByKey(Serializable key) throws DAOException;

	/**
	 * Permanently deletes an instance from the persistence tier.
	 * 
	 * @param object the instance representing the informations to be deleted
	 *        from the store.
	 * @throws DAOException if an error occur while accessing the persistence
	 *         tier.
	 */
	public void remove(Object object) throws DAOException;

	/**
	 * Ensures the persistence tier representation of the object is consistent
	 * with the in memory representation. If the object doesn't exist yet into
	 * the persistence tier it must be added and a new primary key assigned to
	 * the object.
	 * 
	 * @param object the object to be persisted.
	 * @throws DAOException if an error occur while accessing the persistence
	 *         tier
	 */
	public void update(Object object) throws DAOException;

	/**
	 * Returns a collection of objects representing all the persistence tier
	 * informations matching the specified search criterias.
	 * 
	 * @param info the criterias to be used to search the persistence tier.
	 * @return a collection of matching entities.
	 * @throws DAOException if an error occur while accessing the persistence
	 *         tier
	 */
	public Collection list(SearchInfo info) throws DAOException;


	/**
	 * Instances of this class represents a set of criterias to be used in
	 * persistence tier searches. This class is providen as a support class used
	 * to define search criterias using request parameters and should not be
	 * used in place of Hibernate's Criteria or Query
	 * as it doesn't provide the same customizability or features.
	 * 
	 * @author rlogiacco
	 */
	public static class SearchInfo implements Serializable {

		private static final long serialVersionUID = 1038393869915276007L;

		private static final Log logger = LogFactory.getLog(SearchInfo.class);

		/**
		 * Entity properties to be filtered.
		 * 
		 * @uml.property name="filters"
		 */
		private Collection filters = new ArrayList();

		/**
		 * Property to be used for ordering.
		 * 
		 * @uml.property name="order"
		 */
		private String order = null;

		/**
		 * The ordering direction.
		 * 
		 * @uml.property name="descendant"
		 */
		private boolean descendant = false;

		/**
		 * The filtering style.
		 * 
		 * @uml.property name="union"
		 */
		private boolean union = false;

		/**
		 * The locale used to convert filters.
		 */
		private Locale locale = Locale.getDefault();

		/**
		 * Identifies a greater expression condition.
		 */
		public final static int EQUALS = 1;

		/**
		 * Identifies an equals expression condition.
		 */
		public final static int GREATER = 2;

		/**
		 * Identifies a greater expression condition.
		 */
		public final static int GREATER_EQUALS = 3;

		/**
		 * Identifies a greater equals expression condition.
		 */
		public final static int LESSER = 4;

		/**
		 * Identifies a lesser expression condition.
		 */
		public final static int LESSER_EQUALS = 5;

		/**
		 * Identifies a lesser equal expression condition.
		 */
		public final static int NOT_EQUALS = -1;

		/**
		 * Identifies a like expression condition.
		 */
		public final static int LIKE = 6;

		/**
		 * Identifies an ilike expression condition.
		 */
		public final static int ILIKE = 7;

		/**
		 * Identifies a between expression condition.
		 */
		public final static int BETWEEN = 8;

		/**
		 * Identifies an is null expression condition.
		 */
		public final static int NULL = 9;

		/**
		 * Identifies an is not null expression condition.
		 */
		public final static int NOT_NULL = -9;

		/**
		 * Identifies an in expression condition.
		 */
		public final static int IN = 11;

		/**
		 * Identifies a not in expression condition.
		 */
		public final static int NOT_IN = -11;


		/**
		 * @return returns the ordering direction.
		 * @uml.property name="descendant"
		 */
		public boolean isDescendant() {
			return descendant;
		}

		/**
		 * @return returns the filters.
		 * @uml.property name="filters"
		 */
		public Collection getFilters() {
			return filters;
		}

		/**
		 * @param filters the filters to set.
		 * @uml.property name="filters"
		 */
		public void setFilters(Collection filters) {
			this.filters = filters;
		}

		/**
		 * @param filters the filters to set.
		 */
		public void setFilters(String[] filters) {
			if (filters != null) {
				for (int i = 0; i < filters.length; i++) {
					this.addFilter(filters[i]);
				}
			}
		}

		/**
		 * Adds a filter.
		 * 
		 * @param filter the filter to add.
		 */
		public void addFilter(String filter) {
			try {
				for (int i = 0; i < filter.length(); i++) {
					switch (filter.charAt(i)) {
							// Not equals / Not in
						case '!':
							if (filter.charAt(i + 1) == '|') {
								filters.add(new Filter(filter.substring(0, i), NOT_IN, filter.substring(i + 2)));
							} else {
								filters.add(new Filter(filter.substring(0, i), NOT_EQUALS, filter.substring(i + 1)));
							}
							return;
							// Equal
						case '=':
							filters.add(new Filter(filter.substring(0, i), EQUALS, filter.substring(i + 1)));
							return;
							// Greater
						case '>':
							// Greater equal
							if (filter.charAt(i + 1) == '=') {
								filters
										.add(new Filter(filter.substring(0, i), GREATER_EQUALS, filter.substring(i + 2)));
							} else {
								filters.add(new Filter(filter.substring(0, i), GREATER, filter.substring(i + 1)));
							}
							return;
							// Lesser
						case '<':
							// Lesser equal
							if (filter.charAt(i + 1) == '=') {
								filters.add(new Filter(filter.substring(0, i), LESSER_EQUALS, filter.substring(i + 2)));
							} else {
								filters.add(new Filter(filter.substring(0, i), LESSER, filter.substring(i + 1)));
							}
							return;
							// Between / In
						case '|':
							if (filter.charAt(i + 1) == '|') {
								filters.add(new Filter(filter.substring(0, i), IN, filter.substring(i + 2)));
							} else {
								filters.add(new Filter(filter.substring(0, i), BETWEEN, filter.substring(i + 1)));
							}
							return;
							// Like / ILike
						case '%':
							if (filter.charAt(i + 1) == '%') {
								// ILike
								filters.add(new Filter(filter.substring(0, i), ILIKE, filter.substring(i + 2)));
								return;
							} else {
								// Like
								filters.add(new Filter(filter.substring(0, i), LIKE, filter.substring(i + 1)));
								return;
							}
						case '\\':
							i++;
							continue;
					}
				}
			} catch (SkipFilterException sfe) {
				logger.debug("skipping filter `" + filter + "`");
			}
		}

		/**
		 * Adds a filter.
		 * 
		 * @param property the property to filter on.
		 * @param condition the expression condition to apply on the property.
		 * @param values a comma separated list of values to evaluate against
		 *        the condition.
		 */
		public void addFilter(String property, int condition, String values) {
			try {
				filters.add(new Filter(property, condition, values));
			} catch (SkipFilterException sfe) {
				logger.debug("skipping filter on `" + property + "` with condition " + condition + " and values `"
						+ values + "`");
			}
		}
		
		/**
		 * Adds a filter.
		 * 
		 * @param property the property to filter on.
		 * @param condition the expression condition to apply on the property.
		 * @param value a value to evaluate against the condition.
		 * @throws ConversionException 
		 */
		public void addFilter(String property, int condition, Object value) throws ConversionException {
			try {
				filters.add(new Filter(property, condition, (String)ConverterManager.getDefault().convert(String.class, value, locale)));
			} catch (SkipFilterException sfe) {
				logger.debug("skipping filter on `" + property + "` with condition " + condition + " and value `"
						+ value + "`");
			}
		}

		/**
		 * Adds a filter.
		 * 
		 * @param property the property to filter on.
		 * @param condition the expression condition to apply on the property.
		 * @param values an array of values to evaluate against the condition.
		 */
		public void addFilter(String property, int condition, String[] values) {
			try {
				StringBuffer buffer = new StringBuffer();
				for (int i = 0; i < values.length; i++) {
					buffer.append(values[i]);
					buffer.append(',');
				}
				filters.add(new Filter(property, condition, buffer.toString()));
			} catch (SkipFilterException sfe) {
				logger.debug("skipping filter on `" + property + "` with condition " + condition + " and values `"
						+ values + "`");
			}
		}

		/**
		 * Adds a filter.
		 * 
		 * @param property the property to filter on.
		 * @param condition the expression condition to apply on the property.
		 * @param values an array of values to evaluate against the condition.
		 * @throws ConversionException
		 */
		public void addFilter(String property, int condition, Object[] values) throws ConversionException {
			try {
				StringBuffer buffer = new StringBuffer();
				for (int i = 0; i < values.length; i++) {
					buffer.append(ConverterManager.getDefault().convert(String.class, values[i], locale));
					buffer.append(',');
				}
				filters.add(new Filter(property, condition, buffer.toString()));
			} catch (SkipFilterException sfe) {
				logger.debug("skipping filter on `" + property + "` with condition " + condition + " and values `"
						+ values + "`");
			}
		}

		/**
		 * @return returns the order.
		 * @uml.property name="order"
		 */
		public String getOrder() {
			return order;
		}

		/**
		 * Sets the property used to order the collection. By default the
		 * ordering is set to descendant unless an ! 
		 * (exclamation mark) is prefixed indicating an
		 * ascendant order must be used.
		 * 
		 * @param order the property used to order the collection, optionally
		 *        prefixed by !  (exclamation mark) to
		 *        invert the sorting direction.
		 * @uml.property name="order"
		 */
		public void setOrder(String order) {
			if (order != null && order.length() > 0) {
				if (order.charAt(0) == '!') {
					this.order = order.substring(1);
					this.descendant = true;
				} else {
					this.order = order;
					this.descendant = false;
				}
			} else {
				this.order = null;
			}
		}

		/**
		 * TODO documentation
		 * 
		 * @param style
		 */
		public void setUnion(String style) {
			if (style != null && style.length() > 0) {
				if (style.equalsIgnoreCase("OR") || style.equalsIgnoreCase("true") || style.equalsIgnoreCase("yes") || style.equalsIgnoreCase("y")) {
					this.union = true;
				} else {
					this.union = false;
				}
			}
		}
		
		/**
		 * TODO documentation
		 * 
		 * @return
		 * @since 1.2.12
		 * @uml.property name="union"
		 */
		public void setUnion(boolean union) {
			this.union = union;
		}

		/**
		 * TODO documentation
		 * 
		 * @return
		 * @uml.property name="union"
		 */
		public boolean isUnion() {
			return union;
		}

		/**
		 * Sets the locale used to convert filters.
		 * 
		 * @param locale the locale to set.
		 */
		public void setLocale(Locale locale) {
			this.locale = locale;
		}

		/**
		 * Returns the locale used to convert filters.
		 * 
		 * @return the locale used to convert filters.
		 */
		public Locale getLocale() {
			return locale;
		}

		/**
		 * @see java.lang.Object#toString()
		 */
		public String toString() {
			return new ToStringBuilder(this).append(this.filters).append(this.order).append(this.descendant).append(
					this.union).append(this.locale).toString();
		}


		/**
		 * Represents a filtering condition to be applied while performing
		 * searches.
		 * 
		 * @author rlogiacco
		 */
		protected class Filter {

			/**
			 * The column.
			 * 
			 * @uml.property name="column"
			 */
			private String property;

			/**
			 * The condition.
			 * 
			 * @uml.property name="condition"
			 */
			private int condition;

			/**
			 * The values array.
			 * 
			 * @uml.property name="values"
			 */
			private String[] values;


			/**
			 * Creates a filter with a column, a condition and a comma separated
			 * list of values to check against.
			 * 
			 * @param property the property to filter on.
			 * @param condition the condition to apply.
			 * @param values a comma separated list of values to check against.
			 * @throws SkipFilterException if the filter must be skipped invalid
			 */
			private Filter(String property, int condition, String values) throws SkipFilterException {
				if (values == null) {
					throw new SkipFilterException();
				}
				this.property = property;
				this.condition = condition;
				StringTokenizer tokenizer = new StringTokenizer(values, ",", false);
				this.values = new String[tokenizer.countTokens()];
				for (int i = 0; tokenizer.hasMoreTokens(); i++) {
					this.values[i] = tokenizer.nextToken();
					if (this.values[i].indexOf('\\') > -1) {
						StringBuffer buffer = new StringBuffer();
						for (int j = 0; j < this.values[i].length(); j++) {
							char c = this.values[i].charAt(j);
							switch (c) {
								case '\\':
									if (this.values[i].length() > j + 1 && this.values[i].charAt(j + 1) == '\\') {
										buffer.append(c);
										j++;
									}
									break;
								default:
									buffer.append(c);
							}
						}
						this.values[i] = buffer.toString();
					}
				}
				if (this.values.length == 1 && this.values[0].equals("NULL")
						&& (condition == EQUALS || condition == NOT_EQUALS)) {
					if (condition == EQUALS) {
						this.condition = NULL;
					} else if (condition == NOT_EQUALS) {
						this.condition = NOT_NULL;
					}
					this.values = null;
				} else if (this.values.length == 0) {
					throw new SkipFilterException();
				}
				logger.trace("adding filter on `" + property + "` with condition " + condition + " and values `" + values
						+ "`");
			}
			
			/**
			 * @deprecated this was a misleading name.
			 * @see getProperty()
			 */
			protected String getColumn() {
				return property;
			}
			
			/**
			 * Returns the property.
			 * 
			 * @return the property.
			 * @uml.property name="property"
			 * @since 1.2.12
			 */
			protected String getProperty() {
				return property;
			}

			/**
			 * Returns the condition.
			 * 
			 * @return the condition.
			 * @uml.property name="condition"
			 */
			protected int getCondition() {
				return condition;
			}

			/**
			 * Returns the values.
			 * 
			 * @return the values array.
			 * @uml.property name="values"
			 */
			protected String[] getValues() {
				return values;
			}

			/**
			 * Returns the n-th value in the list where the specified index is 0
			 * based.
			 * 
			 * @param index the 0 based index of the value to retrieve.
			 * @return the n-th value in the values list.
			 */
			protected String getValue(int index) {
				return values[index];
			}

			/**
			 * @see java.lang.Object#equals(java.lang.Object)
			 */
			public boolean equals(Object object) {
				if (!(object instanceof Filter)) {
					return false;
				}
				Filter filter = (Filter)object;
				return new EqualsBuilder().append(this.property, filter.property).append(this.condition, filter.condition)
						.append(this.values, filter.values).isEquals();
			}

			/**
			 * @see java.lang.Object#hashCode()
			 */
			public int hashCode() {
				return new HashCodeBuilder(-27848275, 353473951).append(this.property).append(this.condition).append(
						this.values).toHashCode();
			}

			/**
			 * @see java.lang.Object#toString()
			 */
			public String toString() {
				return new ToStringBuilder(this).append(this.property).append(this.condition).append(this.values)
						.toString();
			}
		}

		private static class SkipFilterException extends Exception {

			private static final long serialVersionUID = 5576925342229697415L;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy