Project

General

Profile

« Previous | Next » 

Revision 172

Added by Matt Jones over 24 years ago

completed work on creating structured query prototype in DBQuery and QuerySpecification classes

View differences:

src/edu/ucsb/nceas/metacat/QuerySpecification.java
1 1
/**
2 2
 *      Name: QuerySpecification.java
3 3
 *   Purpose: A Class that represents a structured query, and can be 
4
 *            constructed from an XML serialization
4
 *            constructed from an XML serialization conforming to 
5
 *            pathquery.dtd. The printSQL() method can be used to print 
6
 *            a SQL serialization of the query.
5 7
 * Copyright: 2000 Regents of the University of California and the
6 8
 *            National Center for Ecological Analysis and Synthesis
7 9
 *   Authors: Matt Jones
......
23 25
import org.xml.sax.SAXException;
24 26
import org.xml.sax.SAXParseException;
25 27
import org.xml.sax.helpers.ParserFactory;
26
//import oracle.xml.parser.v2.SAXParser;
27 28

  
28

  
29

  
30 29
/** 
31
 * A Class that represents a structured query,and can be constructed from an
32
 * XML serialization conforming to "pathquery.dtd"
30
 * A Class that represents a structured query, and can be 
31
 * constructed from an XML serialization conforming to @see pathquery.dtd. 
32
 * The printSQL() method can be used to print a SQL serialization of the query.
33 33
 */
34 34
public class QuerySpecification extends HandlerBase {
35 35
 
......
41 41
  // Query data structures
42 42
  private String meta_file_id;
43 43
  private String querytitle;
44
  private Vector doctypeList;
44 45
  private QueryGroup query = null;
45 46

  
46 47
  private Stack elementStack;
47 48
  private Stack queryStack;
48 49
  private String currentValue;
49 50
  private String currentPathexpr;
51
  private String parserName = null;
50 52

  
51 53
  /**
52 54
   * construct an instance of the QuerySpecification class 
53 55
   *
54
   * @param queryspec the XML representation of the query as a Reader
56
   * @param queryspec the XML representation of the query (should conform
57
   *                  to pathquery.dtd) as a Reader
58
   * @param parserName the fully qualified name of a Java Class implementing
59
   *                  the org.xml.sax.Parser interface
55 60
   */
56
  public QuerySpecification( Reader queryspec ) throws IOException {
61
  public QuerySpecification( Reader queryspec, String parserName ) 
62
         throws IOException {
57 63
    super();
58 64

  
59
    // Initialize the stack
65
    // Initialize the class variables
66
    doctypeList = new Vector();
60 67
    elementStack = new Stack();
61 68
    queryStack   = new Stack();
69
    this.parserName = parserName;
62 70

  
63 71
    // Initialize the parser and read the queryspec
64 72
    Parser parser = initializeParser();
......
73 81
  /**
74 82
   * construct an instance of the QuerySpecification class 
75 83
   *
76
   * @param queryspec the XML representation of the query as a String
84
   * @param queryspec the XML representation of the query (should conform
85
   *                  to pathquery.dtd) as a String
86
   * @param parserName the fully qualified name of a Java Class implementing
87
   *                  the org.xml.sax.Parser interface
77 88
   */
78
  public QuerySpecification( String queryspec ) throws IOException {
79

  
80
    this(new StringReader(queryspec));
89
  public QuerySpecification( String queryspec, String parserName ) 
90
         throws IOException {
91
    this(new StringReader(queryspec), parserName);
81 92
  }
82 93

  
83 94
  /** Main routine for testing */
......
92 103
        
93 104
       try {
94 105
         FileReader xml = new FileReader(new File(xmlfile));
95
         QuerySpecification qspec = new QuerySpecification(xml);
96
         System.out.println(qspec.toSQL());
106
         QuerySpecification qspec = new QuerySpecification(xml, DEFAULT_PARSER);
107
         System.out.println(qspec.printSQL());
97 108
       } catch (IOException e) {
98 109
         System.err.println(e.getMessage());
99 110
       }
......
101 112
     }
102 113
  }
103 114

  
115
  /**
116
   * Set up the SAX parser for reading the XML serialized query
117
   */
104 118
  private Parser initializeParser() {
105 119
    Parser parser = null;
106
    //
120

  
107 121
    // Set up the SAX document handlers for parsing
108
    //
109 122
    try {
110 123

  
111 124
      // Get an instance of the parser
112
      parser = ParserFactory.makeParser(DEFAULT_PARSER);
125
      parser = ParserFactory.makeParser(parserName);
113 126

  
114 127
      // Set the DocumentHandler to this instance
115 128
      parser.setDocumentHandler(this);
......
124 137
    return parser;
125 138
  }
126 139

  
140
  /**
141
   * callback method used by the SAX Parser when the start tag of an 
142
   * element is detected. Used in this context to parse and store
143
   * the query information in class variables.
144
   */
127 145
  public void startElement (String name, AttributeList atts) 
128 146
         throws SAXException {
129 147

  
......
150 168
    }
151 169
  }
152 170

  
171
  /**
172
   * callback method used by the SAX Parser when the end tag of an 
173
   * element is detected. Used in this context to parse and store
174
   * the query information in class variables.
175
   */
153 176
  public void endElement (String name) throws SAXException {
154 177
    BasicNode leaving = (BasicNode)elementStack.pop(); 
155 178
    if (leaving.getTagName().equals("queryterm")) {
......
173 196
    }
174 197
  }
175 198

  
199
  /**
200
   * callback method used by the SAX Parser when the text sequences of an 
201
   * xml stream are detected. Used in this context to parse and store
202
   * the query information in class variables.
203
   */
176 204
  public void characters(char ch[], int start, int length) {
177 205

  
178 206
    String inputString = new String(ch, start, length);
......
186 214
      currentValue = inputString;
187 215
    } else if (currentTag.equals("pathexpr")) {
188 216
      currentPathexpr = inputString;
217
    } else if (currentTag.equals("returndoctype")) {
218
      doctypeList.add(inputString);
189 219
    }
190 220
  }
191 221

  
192
  public String toSQL() {
222

  
223
  /**
224
   * create a SQL serialization of the query that this instance represents
225
   */
226
  public String printSQL() {
193 227
    StringBuffer self = new StringBuffer();
194 228

  
229
    // This determines the returned results
230
    self.append("SELECT docid,docname,doctype,doctitle ");
231
    self.append("FROM xml_documents WHERE docid IN (");
195 232
    self.append("SELECT DISTINCT docid FROM xml_nodes WHERE \n");
196
    self.append(query.toSQL());
197 233

  
234
    // This determines the WHERE conditions
235
    self.append(query.printSQL());
236

  
237
    self.append(") ");
238

  
239
    // Add SQL to filter for doctypes requested in the query
240
    if (!doctypeList.isEmpty()) {
241
      boolean firstdoctype = true;
242
      self.append(" AND ("); 
243
      Enumeration en = doctypeList.elements();
244
      while (en.hasMoreElements()) {
245
        String currentDoctype = (String)en.nextElement();
246
        if (firstdoctype) {
247
          firstdoctype = false;
248
          self.append(" doctype = '" + currentDoctype + "'"); 
249
        } else {
250
          self.append(" OR doctype = '" + currentDoctype + "'"); 
251
        }
252
      }
253
      self.append(") ");
254
    }
255

  
198 256
    return self.toString();
199 257
  }
200 258

  
259
  /**
260
   * create a String description of the query that this instance represents.
261
   * This should become a way to get the XML serialization of the query.
262
   */
201 263
  public String toString() {
202 264
    return "meta_file_id=" + meta_file_id + "\n" + 
203 265
           "querytitle=" + querytitle + "\n" + query;
......
208 270
    private String booleantype = null; // indicates how query terms are combined
209 271
    private Vector children = null;    // the list of query terms and groups
210 272

  
273
    /** 
274
     * construct a new QueryGroup 
275
     *
276
     * @param booleantype the boolean conector used to connect query terms 
277
     *                    in this query group
278
     */
211 279
    public QueryGroup(String booleantype) {
212 280
      this.booleantype = booleantype;
213 281
      children = new Vector();
214 282
    }
215 283

  
284
    /** 
285
     * Add a child QueryGroup to this QueryGroup
286
     *
287
     * @param qgroup the query group to be added to the list of terms
288
     */
216 289
    public void addChild(QueryGroup qgroup) {
217 290
      children.add((Object)qgroup); 
218 291
    }
219 292

  
293
    /**
294
     * Add a child QueryTerm to this QueryGroup
295
     *
296
     * @param qterm the query term to be added to the list of terms
297
     */
220 298
    public void addChild(QueryTerm qterm) {
221 299
      children.add((Object)qterm); 
222 300
    }
223 301

  
302
    /**
303
     * Retrieve an Enumeration of query terms for this QueryGroup
304
     */
224 305
    public Enumeration getChildren() {
225 306
      return children.elements();
226 307
    }
227 308
   
228
    public String toSQL() {
309
    /**
310
     * create a SQL serialization of the query that this instance represents
311
     */
312
    public String printSQL() {
229 313
      StringBuffer self = new StringBuffer();
230 314
      boolean first = true;
231 315

  
......
241 325
        }
242 326
        if (qobject instanceof QueryGroup) {
243 327
          QueryGroup qg = (QueryGroup)qobject;
244
          self.append(qg.toSQL());
328
          self.append(qg.printSQL());
245 329
        } else if (qobject instanceof QueryTerm) {
246 330
          QueryTerm qt = (QueryTerm)qobject;
247
          self.append(qt.toSQL());
331
          self.append(qt.printSQL());
248 332
        } else {
249 333
          System.err.println("qobject wrong type: fatal error");
250 334
        }
......
253 337
      return self.toString();
254 338
    }
255 339

  
340
    /**
341
     * create a String description of the query that this instance represents.
342
     * This should become a way to get the XML serialization of the query.
343
     */
256 344
    public String toString() {
257 345
      StringBuffer self = new StringBuffer();
258 346

  
......
274 362
    private String value = null;
275 363
    private String pathexpr = null;
276 364

  
365
    /**
366
     * Construct a new instance of a query term for a free text search
367
     * (using the value only)
368
     *
369
     * @param casesensitive flag indicating whether case is used to match
370
     * @param searchmode determines what kind of substring match is performed
371
     *        (one of starts-with|ends-with|contains|matches-exactly)
372
     * @param value the text value to match
373
     */
277 374
    public QueryTerm(boolean casesensitive, String searchmode, 
278 375
                     String value) {
279 376
      this.casesensitive = casesensitive;
......
281 378
      this.value = value;
282 379
    }
283 380

  
381
    /**
382
     * Construct a new instance of a query term for a structured search
383
     * (matching the value only for those nodes in the pathexpr)
384
     *
385
     * @param casesensitive flag indicating whether case is used to match
386
     * @param searchmode determines what kind of substring match is performed
387
     *        (one of starts-with|ends-with|contains|matches-exactly)
388
     * @param value the text value to match
389
     * @param pathexpr the hierarchical path to the nodes to be searched
390
     */
284 391
    public QueryTerm(boolean casesensitive, String searchmode, 
285 392
                     String value, String pathexpr) {
286 393
      this(casesensitive, searchmode, value);
287 394
      this.pathexpr = pathexpr;
288 395
    }
289 396

  
397
    /** determine if the QueryTerm is case sensitive */
290 398
    public boolean isCaseSensitive() {
291 399
      return casesensitive;
292 400
    }
293 401

  
402
    /** get the searchmode parameter */
294 403
    public String getSearchMode() {
295 404
      return searchmode;
296 405
    }
297 406
 
407
    /** get the Value parameter */
298 408
    public String getValue() {
299 409
      return value;
300 410
    }
301 411

  
412
    /** get the path expression parameter */
302 413
    public String getPathExpression() {
303 414
      return pathexpr;
304 415
    }
305 416

  
306
    public String toSQL() {
417
    /**
418
     * create a SQL serialization of the query that this instance represents
419
     */
420
    public String printSQL() {
307 421
      StringBuffer self = new StringBuffer();
308 422

  
309
      //self.append("    Query Term iscasesensitive=" + casesensitive + "\n");
310

  
311 423
      // Uppercase the search string if case match is not important
312 424
      String casevalue = null;
313 425
      String nodedataterm = null;
......
348 460
      return self.toString();
349 461
    }
350 462

  
463
    /**
464
     * create a String description of the query that this instance represents.
465
     * This should become a way to get the XML serialization of the query.
466
     */
351 467
    public String toString() {
352 468
      StringBuffer self = new StringBuffer();
353 469

  
src/edu/ucsb/nceas/metacat/DBQuery.java
1 1
/**
2 2
 *      Name: DBQuery.java
3 3
 *   Purpose: A Class that searches a relational DB for elements and 
4
 *            attributes that have free text matches to the query string.  
5
 *            It returns a result set consisting of the root nodeid for 
6
 *            each document that satisfies the query
4
 *            attributes that have free text matches a query string,
5
 *            or structured query matches to a path specified node in the 
6
 *            XML hierarchy.  It returns a result set consisting of the 
7
 *            document ID for each document that satisfies the query
7 8
 * Copyright: 2000 Regents of the University of California and the
8 9
 *            National Center for Ecological Analysis and Synthesis
9 10
 *   Authors: Matt Jones
......
22 23
import java.util.Enumeration;
23 24

  
24 25
/** 
25
 * A Class that searches a relational DB for elements and attributes that
26
 * have structured text matches to the query string.  It returns a result set 
27
 * consisting of the root nodeid for each document that satisfies the query
26
 * A Class that searches a relational DB for elements and 
27
 * attributes that have free text matches a query string,
28
 * or structured query matches to a path specified node in the 
29
 * XML hierarchy.  It returns a result set consisting of the 
30
 * document ID for each document that satisfies the query
28 31
 */
29 32
public class DBQuery {
30 33

  
31
  static  String 	defaultDB = "jdbc:oracle:thin:@localhost:1521:test";
34
  private static String defaultDB = "jdbc:oracle:thin:@localhost:1521:test";
32 35
  private Connection	conn = null;
36
  private String	parserName = null;
33 37

  
34 38
  /**
35 39
   * the main routine used to test the DBQuery utility.
......
43 47
   */
44 48
  static public void main(String[] args) {
45 49
     
46
     if (args.length < 3)
50
     if (args.length < 4)
47 51
     {
48 52
        System.err.println("Wrong number of arguments!!!");
49 53
        System.err.println("USAGE: java DBQuery " +
50
                           "<xmlfile> <user> <password> [dbstring]");
54
                           "<xmlfile> <parser> <user> <password> [dbstring]");
51 55
        return;
52 56
     } else {
53 57
        try {
54 58
                    
55 59
          String xmlfile  = args[0];
56
          String user     = args[1];
57
          String password = args[2];
60
          String parser   = args[1];
61
          String user     = args[2];
62
          String password = args[3];
58 63
          String dbstring = null;
59 64

  
60
          if (args.length <= 3) {
65
          if (args.length <= 4) {
61 66
            dbstring = defaultDB;
62 67
          } else {
63
            dbstring = args[3];
68
            dbstring = args[4];
64 69
          }
65 70

  
66 71
          // Open a connection to the database
67 72
          Connection dbconn = MetaCatUtil.openDBConnection( 
68 73
                              "oracle.jdbc.driver.OracleDriver",
69 74
                              dbstring, user, password);
75

  
70 76
          // Execute the query
71
          DBQuery rd = new DBQuery(dbconn);
72

  
77
          DBQuery rd = new DBQuery(dbconn, parser);
73 78
          FileReader xml = new FileReader(new File(xmlfile));
74
          //QuerySpecification qspec = new QuerySpecification(xml);
75
          //System.out.println(qspec.toSQL());
76

  
77 79
          Hashtable nodelist = null;
78 80
          nodelist = rd.findDocuments(xml);
79 81

  
80
          // Print the reulting root nodes
82
          // Print the reulting document listing
81 83
          StringBuffer result = new StringBuffer();
82 84
          String document = null;
83 85
          String docid = null;
......
110 112
   * an instance to specify the search query</p>
111 113
   *
112 114
   * @param conn the JDBC connection that we use for the query
115
   * @param parserName the fully qualified name of a Java class implementing
116
   *                   the org.xml.sax.Parser interface
113 117
   */
114
  public DBQuery( Connection conn ) 
118
  public DBQuery( Connection conn, String parserName ) 
115 119
                  throws IOException, 
116 120
                         SQLException, 
117
                         ClassNotFoundException
118
  {
121
                         ClassNotFoundException {
119 122
    this.conn = conn;
123
    this.parserName = parserName;
120 124
  }
121 125
  
122 126
  /** 
123 127
   * routine to search the elements and attributes looking to match query
124 128
   *
125
   * @param queryspec the xml serialization of the query (pathquery.dtd)
129
   * @param queryspec the xml serialization of the query (@see pathquery.dtd)
126 130
   */
127 131
  public Hashtable findDocuments(Reader queryspec) {
128 132
      Hashtable	 docListResult = new Hashtable();
129

  
130 133
      PreparedStatement pstmt;
131

  
132
      // Now look up the document id
133 134
      String docid = null;
134 135
      String docname = null;
135 136
      String doctype = null;
......
137 138
      StringBuffer document = null; 
138 139

  
139 140
      try {
140
        QuerySpecification qspec = new QuerySpecification(queryspec);
141
 
142
        pstmt = conn.prepareStatement(
143
              "SELECT docid,docname,doctype,doctitle " +
144
              "FROM xml_documents WHERE docid IN (" +
145
              qspec.toSQL() + ")");
141
        // Get the XML query and covert it into a SQL statment
142
        QuerySpecification qspec = new QuerySpecification(queryspec, 
143
                                   parserName);
144
        pstmt = conn.prepareStatement( qspec.printSQL() );
146 145

  
146
        // Execute the SQL query using the JDBC connection
147 147
        pstmt.execute();
148 148
        ResultSet rs = pstmt.getResultSet();
149 149
        boolean tableHasRows = rs.next();

Also available in: Unified diff