001: /*
002: * Copyright (C) 1999-2004 <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</a>
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package org.mandarax.kernel.meta;
020:
021: import java.io.IOException;
022: import java.io.ObjectInputStream;
023: import java.io.ObjectOutputStream;
024: import java.lang.reflect.Method;
025: import org.mandarax.kernel.Predicate;
026: import org.mandarax.util.PredicateUtils;
027:
028: /**
029: * A JPredicate is a predicate defined by a java method. Despite it is not
030: * enforced here, the method should return a <code>boolean</boolean>,
031: * e.g. <code>equals()</code>.
032: * Note that the predicate can be negated. E.g., if the <code>equals()</code>
033: * associates objects that are equal, the negated <code>equals()</code> predicate
034: * associates objects that are <b>not</b> equal. In case the predicate is
035: * negated and no name is given, the prefix <i>not</i> is automatically
036: * added to the generated name, i.e. to the name of the method.
037: * This is important since <code>equals()</code> invokes the name of the predicate
038: * (and not the method)!!
039: * <br>
040: * In version 3.2, session support has been added. The last parameter (found in the wrapoped method)
041: * is treated separately if its type is Session (or a subclass of session). Then this parameter is used
042: * to pass a session reference at query time to the function or predicate!
043: * @see org.mandarax.kernel.Session
044: * @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
045: * @version 3.4 <7 March 05>
046: * @since 1.0
047: */
048: public final class JPredicate extends JConstructor implements Predicate {
049: private String[] slotNames = null;
050: private boolean isNegated = false;
051:
052: /**
053: * Constructor.
054: */
055: public JPredicate() {
056: super ();
057: }
058:
059: /**
060: * Constructor.
061: * @param aMethod the method used
062: */
063: public JPredicate(Method aMethod) {
064: super (aMethod);
065: }
066:
067: /**
068: * Constructor.
069: * @param aMethod the method used
070: * @param aName the name of the object
071: */
072: public JPredicate(Method aMethod, String aName) {
073: super (aMethod, aName);
074: }
075:
076: /**
077: * Constructor.
078: * @param aMethod the method used
079: * @param aName the name of the object
080: * @param boolean true if the predicate is negated, false otherwise
081: */
082: public JPredicate(Method aMethod, String aName, boolean negated) {
083: super (aMethod, aName);
084:
085: isNegated = negated;
086: }
087:
088: /**
089: * Constructor.
090: * @param aMethod the method used
091: * @param boolean true if the predicate is negated, false otherwise
092: */
093: public JPredicate(Method aMethod, boolean negated) {
094: super (aMethod);
095:
096: isNegated = negated;
097: }
098:
099: /**
100: * Indicates whether the two objects are equal. This method invokes
101: * comparing the names and checking the structure types for compatibility (and not for
102: * identity!).
103: * @param obj the object to compare this object with
104: * @return true if the objects are equal, false otherwise
105: */
106: public boolean equals(Object obj) {
107: if (obj instanceof org.mandarax.kernel.Predicate) {
108: Predicate p = (Predicate) obj;
109: Class[] c1 = p.getStructure();
110: Class[] c2 = getStructure();
111: boolean result = p.getName().equals(getName());
112:
113: result = result && (c1.length == c2.length);
114:
115: for (int i = 0; i < c1.length; i++) {
116: result = result
117: && ((c1[i] == c2[i])
118: || (c1[i].isAssignableFrom(c2[i])) || (c2[i]
119: .isAssignableFrom(c1[i])));
120: }
121:
122: return result;
123: }
124:
125: return false;
126: }
127:
128: /**
129: * Get the name.
130: * @return the name of the predicate
131: */
132: public String getName() {
133: if (name == null) {
134: String m = (method == null) ? null : method.getName();
135:
136: if (m == null) {
137: return "?";
138: } else {
139: return isNegated ? "not " + m : m;
140: }
141: } else {
142: // bugfix 1.9
143: return isNegated ? "not " + name : name;
144: }
145: }
146:
147: /**
148: * Get the hash code of the object.
149: * @return the hash value
150: */
151: public int hashCode() {
152: if (getName() == null) {
153: return 0;
154: } else {
155: return getName().hashCode() + getStructure().length;
156: }
157: }
158:
159: /**
160: * Indicates whether the predicate is negated.
161: * @return true if the predicate is negated, false otherwise
162: */
163: public boolean isNegated() {
164: return isNegated;
165: }
166:
167: /**
168: * Set the negated property.
169: * @param neg a boolean
170: */
171: public void setNegated(boolean neg) {
172: isNegated = neg;
173: }
174:
175: /**
176: * Read the object from an object input stream.
177: * @param in an input stream
178: */
179: private void readObject(ObjectInputStream in) throws IOException,
180: ClassNotFoundException {
181: in.defaultReadObject();
182:
183: String methodName = (String) in.readObject();
184: Class declaringClass = (Class) in.readObject();
185: Class[] parTypes = (Class[]) in.readObject();
186:
187: try {
188: Method m = declaringClass.getMethod(methodName, parTypes);
189:
190: method = m;
191: } catch (NoSuchMethodException x) {
192: throw new IOException("Cannot find method " + name);
193: }
194: }
195:
196: /**
197: * Write the object to an object output stream.
198: * @param out an output stream
199: */
200: private void writeObject(ObjectOutputStream out)
201: throws IOException, ClassNotFoundException {
202: out.defaultWriteObject();
203: out.writeObject(method.getName());
204: out.writeObject(method.getDeclaringClass());
205: out.writeObject(method.getParameterTypes());
206: }
207:
208: /**
209: * Get the slot names.
210: * @return an array of strings, the length of the array is the same as
211: * the length of the array of terms (the structure of the predicate)
212: */
213: public String[] getSlotNames() {
214: if (slotNames == null) {
215: slotNames = new String[getStructure().length];
216: for (int i = 0; i < slotNames.length; i++)
217: slotNames[i] = PredicateUtils.getSlotName(this , i);
218: }
219: return slotNames;
220: }
221:
222: /**
223: * Set the slot names.
224: * @param names an array of strings, the length of the array is the same as
225: * the length of the array of terms (the structure of the predicate)
226: */
227: public void setSlotNames(String[] names) {
228: if (names != null && names.length != getStructure().length)
229: throw new IllegalArgumentException(
230: "Number of slot names and number of slots must match - cannot set slot names for predicate "
231: + this );
232: this .slotNames = names;
233: }
234:
235: /**
236: * Indicates whether the slot names can be modified.
237: * @return a boolean
238: */
239: public boolean slotNamesCanBeEdited() {
240: return true;
241: }
242: }
|