View Javadoc

1   // BSD License (http://www.galagosearch.org/license)
2   
3   package org.galagosearch.core.retrieval.query;
4   
5   import java.lang.reflect.Constructor;
6   import org.galagosearch.core.retrieval.structured.StructuredIterator;
7   import org.galagosearch.tupleflow.Parameters;
8   
9   /***
10   * <p>A NodeType describes the class type and input types of an iterator.</p>
11   * 
12   * <p>Traversals that modify a tree may want to know what type of iterator will be generated
13   * when a Node is converted into a StructuredIterator.  For instance, a Node with a
14   * "counts" operator will turn into a ExtentListIterator.  This is important to know because
15   * a ScoreCombinationIterator can't take an ExtentListIterator as an argument; it needs an
16   * iterator between them to convert extents into scores.  A Traversal can check the types
17   * of "counts" and "combine", notice the type mismatch, and add a "#feature" node between
18   * them so that the types match.</p>
19   * 
20   * @author trevor
21   */
22  public class NodeType {
23      private Class<? extends StructuredIterator> nodeClass;
24  
25      public NodeType(Class<? extends StructuredIterator> nodeClass) {
26          this.nodeClass = nodeClass;
27      }
28      
29      public Class<? extends StructuredIterator> getIteratorClass() {
30          return nodeClass;
31      }
32      
33      public Class[] getInputs() throws Exception {
34          Constructor constructor = null;
35          try {
36              constructor = getConstructor();
37          } catch(Exception e) {
38              return new Class[0];
39          }
40          return constructor.getParameterTypes();
41      }
42      
43      public Class[] getParameterTypes(int length) throws Exception {
44          Class[] inputs = getInputs();
45          if (inputs == null) return new Class[0];
46          if (inputs.length == 0) return new Class[0];
47          if (inputs[inputs.length-1].isArray()) {
48              if (length < inputs.length-1) {
49                  // Not enough parameters.
50                  return null;
51              } else {
52                  Class[] result = new Class[length];
53                  // Copy in classes for the first few parameters.
54                  for (int i = 0; i < inputs.length-1; ++i) {
55                      result[i] = inputs[i];
56                  }
57                  // Apply the array class type to the remaining slots.
58                  for (int i = inputs.length-1; i < result.length; ++i) {
59                      result[i] = inputs[inputs.length-1].getComponentType();
60                  }
61                  return result;
62              }
63          } else {
64              if (length != inputs.length) {
65                  return null;
66              } else {
67                  return inputs;
68              }
69          }
70      }
71      
72      public boolean isStructuredIteratorOrArray(Class c) {
73          if (c.isArray() && StructuredIterator.class.isAssignableFrom(c.getComponentType()))
74              return true;
75          if (StructuredIterator.class.isAssignableFrom(c))
76              return true;
77          return false;
78      }
79      
80      public Constructor getConstructor() throws Exception {
81          for (Constructor constructor : nodeClass.getConstructors()) {
82              Class[] types = constructor.getParameterTypes();
83           
84              // The constructor needs at least one parameter.
85              if (types.length < 1)
86                  continue;
87              // The first class needs to be a Parameters object.
88              if (!Parameters.class.isAssignableFrom(types[0]))
89                  continue;
90              // Check arguments for valid argument types.
91              boolean validTypes = true;
92              for (int i = 1; i < types.length; ++i) {
93                  if (!isStructuredIteratorOrArray(types[i])) {
94                      validTypes = false;
95                      break;
96                  }
97              }
98              // If everything looks good, return this constructor.
99              if (validTypes) {
100                 return constructor;
101             }
102         }
103         
104         throw new Exception("No reasonable constructors were found for " + nodeClass.toString());
105     }
106 }