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: package org.mandarax.kernel.meta;
019:
020: import java.util.Collection;
021: import java.util.Iterator;
022: import java.util.Vector;
023:
024: import org.mandarax.kernel.Clause;
025: import org.mandarax.kernel.ClauseSet;
026: import org.mandarax.util.DataSource;
027: import org.mandarax.util.StaticDataSource;
028:
029: /**
030: * Clause set use the java object model to build a fact base.
031: * A JClauseSet has a method and an array of parameters.
032: * A call to <code>clauses()</code> loops over all combinations of
033: * elements in the object collections and invokes the method for any combination
034: * of elements. The method is supposed to return a boolean. In case this
035: * boolean is true, a fact is built with the method (wrapped by an instance of <code>JPredicate</code>)
036: * as predicate and the respective set of objects (wrapped by constant terms). <p>
037: * After creating the object a couple of checks is performed, e.g. regarding the arity
038: * of the array, whether the return type of the method is a boolean and whether the
039: * method is public and therefore accessible. <p>
040: * If something is wrong, an exception is thrown. However, we do <i>not</i> check
041: * whether all objects in the collections can be casted to the types expected by the method
042: * at the respective positions. In this case, the exceptions thrown in <code>invoke()</code>
043: * are captured, a message is printed out to <code>System.err()</code> and we coninue without
044: * adding the fact.
045: * @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
046: * @version 3.4 <7 March 05>
047: * @since 1.0
048: */
049: public final class JClauseSet extends
050: org.mandarax.kernel.meta.AbstractClauseSet implements ClauseSet {
051:
052: private DataSource[] argumentSets = null;
053:
054: /**
055: * Constructor.
056: * @param aPredicate a predicate
057: * @param argumentSets the collections of objects
058: * @throws java.lang.IllegalAccessException Thrown if the method wrapped by the predicate is not public.
059: * @throws java.lang.IllegalArgumentException Thrown if the return type of the method wrapped by the predicate is not boolean or if the number of argument sets does not match.
060: */
061: public JClauseSet(JPredicate aPredicate, Collection[] argumentSets)
062: throws NullPointerException, IllegalAccessException,
063: IllegalArgumentException {
064: this (aPredicate, argumentSets, false);
065: }
066:
067: /**
068: * Constructor.
069: * @param aPredicate a predicate
070: * @param argumentSets the collections of objects
071: * @param isNegated true if the set should be negated, false otherwise
072: * @throws java.lang.IllegalAccessException Thrown if the method wrapped by the predicate is not public.
073: * @throws java.lang.IllegalArgumentException Thrown if the return type of the method wrapped by the predicate is not boolean or if the number of argument sets does not match.
074: */
075: public JClauseSet(JPredicate aPredicate, Collection[] argumentSets,
076: boolean isNegated) throws NullPointerException,
077: IllegalAccessException, IllegalArgumentException {
078: this (aPredicate, buildDataSources(argumentSets), isNegated);
079: }
080:
081: /**
082: * Constructor.
083: * @param aPredicate a predicate
084: * @param argumentSets the data sources (kind of dynamic collections)
085: * @throws java.lang.IllegalAccessException Thrown if the method wrapped by the predicate is not public.
086: * @throws java.lang.IllegalArgumentException Thrown if the return type of the method wrapped by the predicate is not boolean or if the number of argument sets does not match.
087: */
088: public JClauseSet(JPredicate aPredicate, DataSource[] argumentSets)
089: throws NullPointerException, IllegalAccessException,
090: IllegalArgumentException {
091: this (aPredicate, argumentSets, false);
092: }
093:
094: /**
095: * Constructor.
096: * @param aPredicate a predicate
097: * @param argumentSets the data sources (kind of dynamic collections)
098: * @param isNegated true if the set should be negated, false otherwise
099: * @throws java.lang.IllegalAccessException Thrown if the method wrapped by the predicate is not public.
100: * @throws java.lang.IllegalArgumentException Thrown if the return type of the method wrapped by the predicate is not boolean or if the number of argument sets does not match.
101: */
102: public JClauseSet(JPredicate aPredicate, DataSource[] argumentSets,
103: boolean isNegated) throws NullPointerException,
104: IllegalAccessException, IllegalArgumentException {
105: super (isNegated);
106:
107: initialize(aPredicate, argumentSets);
108: }
109:
110: /**
111: * Build an array of data sources from an array of collections.
112: * @return an array of datasources
113: * @param argumentSets the collections of objects
114: */
115: private static DataSource[] buildDataSources(Collection[] coll) {
116: DataSource[] ds = new DataSource[coll.length];
117:
118: for (int i = 0; i < coll.length; i++) {
119: ds[i] = new StaticDataSource(coll[i]);
120: }
121:
122: return ds;
123: }
124:
125: /**
126: * Build the collection of facts.
127: * @return java.util.Collection
128: */
129: protected Collection buildFacts() {
130: Collection data = argumentSets[0].getData();
131: Collection coll = new Vector(argumentSets.length * data.size());
132:
133: for (Iterator it = data.iterator(); it.hasNext();) {
134: Object[] args = new Object[argumentSets.length - 1];
135:
136: buildFacts(coll, it.next(), args, 0);
137: }
138:
139: return coll;
140: }
141:
142: /**
143: * Recursive method to loop over the parameter sets.
144: * @param container the container collecting the facts built
145: * @param target the target that receives the method
146: * @param args the arguments
147: * @param pointer recursion counter
148: */
149: private void buildFacts(Collection container, Object target,
150: Object[] args, int pointer) {
151: if (pointer < args.length) {
152:
153: // i.e., we have to go to a new inner loop
154: Collection data = argumentSets[pointer + 1].getData();
155:
156: for (Iterator it = data.iterator(); it.hasNext();) {
157: args[pointer] = it.next();
158:
159: buildFacts(container, target, args, pointer + 1);
160: }
161: } else {
162:
163: // i.e., we are in the most inner loopo and can build the facts
164: Clause c = buildFact(target, args);
165:
166: if (c != null) {
167: container.add(c);
168: }
169: }
170: }
171:
172: /**
173: * Validate the parameters provided to set up the set.
174: * @param aPredicate the predicate
175: * @param argSets the data sources
176: * @throws java.lang.IllegalAccessException Thrown if the Predicate is not public.
177: * @throws java.lang.IllegalArgumentException Thrown if the return type of the Predicate is not boolean or if the number of argument sets does not match.
178: */
179: private void initialize(JPredicate aPredicate, DataSource[] argSets)
180: throws NullPointerException, IllegalAccessException,
181: IllegalArgumentException {
182: if (argSets == null) {
183: throw new NullPointerException(
184: "The argument sets cannot be null");
185: }
186:
187: initialize(aPredicate);
188:
189: argumentSets = argSets;
190: }
191: }
|