001 /*
002 Copyright (c) 1996-2012, Damon Hart-Davis
003 All rights reserved.
004
005 Redistribution and use in source and binary forms, with or without
006 modification, are permitted provided that the following conditions are
007 met:
008
009 * Redistributions of source code must retain the above copyright
010 notice, this list of conditions and the following disclaimer.
011
012 * Redistributions in binary form must reproduce the above copyright
013 notice, this list of conditions and the following disclaimer in the
014 documentation and/or other materials provided with the
015 distribution.
016
017 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
018 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
019 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
020 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
021 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
022 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
023 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
024 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
025 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
027 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028 */
029 package org.hd.d.pg2k.webSvr.exhibit;
030
031 import org.hd.d.pg2k.svrCore.AllExhibitProperties;
032 import org.hd.d.pg2k.svrCore.Name;
033
034 /**Abstract base for an expression (for a FilterBean).
035 * Expressions must be Serializable so that they can
036 * be persisted. They must not attempt to cache any reference,
037 * direct or indirect, to a DataSourceBean.
038 * <p>
039 * Expression objects must be immutable and their accept()/sort()
040 * methods must be idempotent.
041 * <p>
042 * Expressions may be nested like this:
043 * <pre>
044 * new SortExpr(new FilterExpr(null, new BuiltInFilters.filtAll(null)),
045 * new BuiltInFilters.sortByName(BuiltInFilters.sortByName.SMART))
046 * </pre>
047 * <p>
048 * Operations such as filtering and sorting may be carried out concurrently internally,
049 * so filters and sorts should be thread-safe
050 * and should preferably admit concurrency if possible.
051 * <p>
052 * FIXME: this and all derived classes and expressions must support equals()
053 * and hashCode() where possible.
054 */
055 public abstract class Expr implements java.io.Serializable
056 {
057 /**The upstream expression pipeline. */
058 private final Expr upstream;
059
060 /**Construct us with the upstream expression.
061 * If the upstream expression is null then we are
062 * the head of the expression chain and process the input first.
063 */
064 protected Expr(final Expr _upstream)
065 {
066 upstream = _upstream;
067 }
068
069 /**Evaluate this expression.
070 * Given the upstream expression, compute its results and
071 * then compute ours on it.
072 * <p>
073 * We return a set of names, possibly empty.
074 * <p>
075 * The result array contains no duplicates nor nulls
076 * (providing the input is similarly well-behaved)
077 * and is never null itself.
078 * <p>
079 * Designed to be overridden and have super() called to
080 * collect upstream results... By itself returns all
081 * the exhibits untouched, ie is a null filter/sorter,
082 * the identity expression.
083 * <p>
084 * The head of the expression chain takes a copy of the inputs
085 * and returns them; other items just pass the data up untouched.
086 */
087 public Name.ExhibitFull[] eval(final AllExhibitProperties aep, final Name.ExhibitFull[] in)
088 {
089 // We are the head of the chain, we use the input...
090 if(upstream == null) { return(in.clone()); }
091
092 // He are not the head of the chain, pass the input up.
093 return(upstream.eval(aep, in));
094 }
095
096 /**Hash depends on upstream object, or is zero if none. */
097 @Override
098 public int hashCode()
099 {
100 final Expr e = upstream;
101 if(e == null) { return(0); }
102 return(e.hashCode() + 1);
103 }
104
105 /**Equality depends on the upstream expressions being equal (or both null).
106 * This does not return true unless the structure is the same and
107 * all elements are the same.
108 */
109 @Override
110 public boolean equals(final Object obj)
111 {
112 // We are identical to ourself.
113 if(obj == this) { return(true); }
114
115 if(!(obj instanceof Expr)) { return(false); }
116 final Expr other = (Expr) obj;
117
118 // If identical upstream (eg both null or both same object)
119 // then these are the same.
120 if(other.upstream == upstream) { return(true); }
121
122 // If we are null (and the other is not), them we are not equal.
123 if(upstream == null) { return(false); }
124
125 // Compare upstream objects; can only work if equals is symmetrical.
126 // This may be hard to achieve in derived classes without care,
127 // so, for a start, we make sure that the implementation classes are
128 // exactly the same.
129 return((upstream.getClass() == other.upstream.getClass()) &&
130 upstream.equals(other.upstream));
131 }
132
133
134 /**Unique Serialisation class ID generated by http://random.hd.org/. */
135 private static final long serialVersionUID = -881322470744786046L;
136 }