Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that searches a relational DB for elements and 
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
8
 *  Copyright: 2000 Regents of the University of California and the
9
 *             National Center for Ecological Analysis and Synthesis
10
 *    Authors: Matt Jones
11
 *
12
 *   '$Author: berkley $'
13
 *     '$Date: 2000-08-11 11:26:07 -0700 (Fri, 11 Aug 2000) $'
14
 * '$Revision: 342 $'
15
 */
16

    
17
package edu.ucsb.nceas.metacat;
18

    
19
import java.io.*;
20
import java.net.URL;
21
import java.net.MalformedURLException;
22
import java.sql.*;
23
import java.util.Stack;
24
import java.util.Hashtable;
25
import java.util.Enumeration;
26

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

    
36
  private Connection	conn = null;
37
  private String	parserName = null;
38

    
39
  /**
40
   * the main routine used to test the DBQuery utility.
41
   * <p>
42
   * Usage: java DBQuery <xmlfile>
43
   *
44
   * @param xmlfile the filename of the xml file containing the query
45
   */
46
  static public void main(String[] args) {
47
     
48
     if (args.length < 1)
49
     {
50
        System.err.println("Wrong number of arguments!!!");
51
        System.err.println("USAGE: java DBQuery <xmlfile>");
52
        return;
53
     } else {
54
        try {
55
                    
56
          String xmlfile  = args[0];
57

    
58
          // Open a connection to the database
59
          MetaCatUtil   util = new MetaCatUtil();
60
          Connection dbconn = util.openDBConnection();
61

    
62
          // Execute the query
63
          DBQuery queryobj = new DBQuery(dbconn, util.getOption("saxparser"));
64
          FileReader xml = new FileReader(new File(xmlfile));
65
          Hashtable nodelist = null;
66
          nodelist = queryobj.findDocuments(xml);
67

    
68
          // Print the reulting document listing
69
          StringBuffer result = new StringBuffer();
70
          String document = null;
71
          String docid = null;
72
          result.append("<?xml version=\"1.0\"?>\n");
73
          result.append("<resultset>\n"); 
74
  // following line removed by Dan Higgins to avoid insertion of query XML inside returned XML doc
75
  //        result.append("  <query>" + xmlfile + "</query>\n");
76
          Enumeration doclist = nodelist.keys(); 
77
          while (doclist.hasMoreElements()) {
78
            docid = (String)doclist.nextElement();
79
            document = (String)nodelist.get(docid);
80
            result.append("  <document>\n    " + document + 
81
                          "\n  </document>\n");
82
          }
83
          result.append("</resultset>\n");
84

    
85
          System.out.println(result);
86

    
87
        } catch (Exception e) {
88
          System.err.println("EXCEPTION HANDLING REQUIRED");
89
          System.err.println(e.getMessage());
90
          e.printStackTrace(System.err);
91
        }
92
     }
93
  }
94
  
95
  /**
96
   * construct an instance of the DBQuery class 
97
   *
98
   * <p>Generally, one would call the findDocuments() routine after creating 
99
   * an instance to specify the search query</p>
100
   *
101
   * @param conn the JDBC connection that we use for the query
102
   * @param parserName the fully qualified name of a Java class implementing
103
   *                   the org.xml.sax.XMLReader interface
104
   */
105
  public DBQuery( Connection conn, String parserName ) 
106
                  throws IOException, 
107
                         SQLException, 
108
                         ClassNotFoundException {
109
    this.conn = conn;
110
    this.parserName = parserName;
111
  }
112
  
113
  /** 
114
   * routine to search the elements and attributes looking to match query
115
   *
116
   * @param xmlquery the xml serialization of the query (@see pathquery.dtd)
117
   */
118
  public Hashtable findDocuments(Reader xmlquery) {
119
      Hashtable	 docListResult = new Hashtable();
120
      PreparedStatement pstmt;
121
      String docid = null;
122
      String docname = null;
123
      String doctype = null;
124
      String doctitle = null;
125
      StringBuffer document = null; 
126

    
127
      try {
128
        // Get the XML query and covert it into a SQL statment
129
        QuerySpecification qspec = new QuerySpecification(xmlquery, 
130
                                   parserName);
131
        //System.out.println(qspec.printSQL());
132
        pstmt = conn.prepareStatement( qspec.printSQL() );
133

    
134
        // Execute the SQL query using the JDBC connection
135
        pstmt.execute();
136
        ResultSet rs = pstmt.getResultSet();
137
        boolean tableHasRows = rs.next();
138
        while (tableHasRows) {
139
          docid = rs.getString(1);
140
          docname = rs.getString(2);
141
          doctype = rs.getString(3);
142
          doctitle = rs.getString(4);
143

    
144
          document = new StringBuffer();
145
          document.append("<docid>").append(docid).append("</docid>");
146
          if (docname != null) {
147
            document.append("<docname>" + docname + "</docname>");
148
          }
149
          if (doctype != null) {
150
            document.append("<doctype>" + doctype + "</doctype>");
151
          }
152
          if (doctitle != null) {
153
            document.append("<doctitle>" + doctitle + "</doctitle>");
154
          }
155

    
156
          // Store the document id and the root node id
157
          docListResult.put(docid,(String)document.toString());
158

    
159
          // Advance to the next record in the cursor
160
          tableHasRows = rs.next();
161
        }
162
        pstmt.close();
163
      } catch (SQLException e) {
164
        System.err.println("Error getting id: " + e.getMessage());
165
      } catch (IOException ioe) {
166
        System.err.println("Error printing qspec:");
167
        System.err.println(ioe.getMessage());
168
      }
169
    return docListResult;
170
  }
171
  
172
  /**
173
   * format a structured query as an XML document that conforms
174
   * to the pathquery.dtd and is appropriate for submission to the DBQuery
175
   * structured query engine
176
   *
177
   * @param params The list of parameters that  should be included in the query
178
   * @param doctype the type of documents to include in the result set -- use
179
   *        "any" or "ANY" for unfiltered result sets
180
   */
181
  public static String createSQuery(Hashtable params, String doctype)
182
  {
183
    StringBuffer query=null;
184
    Enumeration elements;
185
    Enumeration keys;
186
    Object nextkey;
187
    Object nextelement;
188
    query.append("<?xml version=\"1.0\"?>");
189

    
190
    query.append("<pathquery version=\"1.0\"><meta_file_id>");
191
    if(params.containsKey("meta_file_id"))
192
    {
193
      query.append( ((String[])params.get("meta_file_id"))[0]);
194
    	query.append("</meta_file_id>");
195
    }
196
    else
197
    {
198
      query.append("unspecified</meta_file_id>");
199
    }
200
    query.append("<querytitle>");
201
    if(params.containsKey("querytitle"))
202
    {
203
      query.append(((String[])params.get("querytitle"))[0]);
204
    	query.append("</querytitle>");
205
    }
206
    else
207
    {
208
    	query.append("unspecified</querytitle>");
209
    }
210
    if (!doctype.equals("any") && 
211
        !doctype.equals("ANY") &&
212
        !doctype.equals("") ) 
213
    {
214
       query.append("<returndoctype>");
215
       query.append(doctype).append("</returndoctype>");
216
    }
217
    query.append("<querygroup operator=\"" + 
218
    		        ((String[])params.get("operator"))[0] + "\">");
219
    		
220
    		
221
    //anyfield is a special case because it does a 
222
    //free text search.  It does not have a <pathexpr>
223
    //tag.
224
    if(params.containsKey("anyfield") && 
225
    	 !((String[])params.get("anyfield"))[0].equals(""))
226
    {
227
    	query.append("<queryterm casesensitive=\"false\" " +
228
    			         "searchmode=\"contains\"><value>" +
229
    			         ((String[])params.get("anyfield"))[0] +
230
    			         "</value></queryterm>");
231
    }
232
    		
233
    //this while loop finds the rest of the parameters
234
    //and attempts to query for the field specified
235
    //by the parameter.
236
    elements = params.elements();
237
    keys = params.keys();
238
    while(keys.hasMoreElements() && elements.hasMoreElements())
239
    {
240
      nextkey = keys.nextElement();
241
    	nextelement = elements.nextElement();
242
    		
243
    	//make sure we aren't querying for any of these
244
    	//parameters since the are already in the query
245
      //in one form or another.
246
    	if(!nextkey.toString().equals("doctype") && 
247
    		 !nextkey.toString().equals("action")  &&
248
    		 !nextkey.toString().equals("qformat") && 
249
    		 !nextkey.toString().equals("anyfield") &&
250
    		 !nextkey.toString().equals("operator") &&
251
    		 !(((String[])nextelement)[0].equals("")) )
252
    	{
253
        query.append("<queryterm casesensitive=\"false\" " + 
254
    				         "searchmode=\"contains\">" +
255
    		             "<value>" +
256
        //add the query value
257
    		             ((String[])nextelement)[0] +
258
    		             "</value><pathexpr>" +
259
    		//add the path to query by 
260
                     nextkey.toString() + 
261
                     "</pathexpr></queryterm>");
262
    	}
263
    }
264
    query.append("</querygroup></pathquery>");
265
    return query.toString();
266
  }
267
  
268
  /**
269
   * format a simple free-text value query as an XML document that conforms
270
   * to the pathquery.dtd and is appropriate for submission to the DBQuery
271
   * structured query engine
272
   *
273
   * @param value the text string to search for in the xml catalog
274
   * @param doctype the type of documents to include in the result set -- use
275
   *        "any" or "ANY" for unfiltered result sets
276
   */
277
   public static String createQuery(String value, String doctype) {
278
     StringBuffer xmlquery = new StringBuffer();
279
     xmlquery.append("<?xml version=\"1.0\"?>\n");
280
     xmlquery.append("<pathquery version=\"1.0\">");
281
     xmlquery.append("<meta_file_id>Unspecified</meta_file_id>");
282
     xmlquery.append("<querytitle>Unspecified</querytitle>");
283

    
284
     if (!doctype.equals("any") && !doctype.equals("ANY")) {
285
       xmlquery.append("<returndoctype>");
286
       xmlquery.append(doctype).append("</returndoctype>");
287
     }
288

    
289
     xmlquery.append("<querygroup operator=\"UNION\">");
290
     xmlquery.append("<queryterm casesensitive=\"false\" ");
291
     xmlquery.append("searchmode=\"contains\">");
292
     xmlquery.append("<value>").append(value).append("</value>");
293
     xmlquery.append("</queryterm>");
294
     xmlquery.append("</querygroup>");
295
     xmlquery.append("</pathquery>");
296

    
297
     
298
     return (xmlquery.toString());
299
   }
300

    
301
  /**
302
   * format a simple free-text value query as an XML document that conforms
303
   * to the pathquery.dtd and is appropriate for submission to the DBQuery
304
   * structured query engine
305
   *
306
   * @param value the text string to search for in the xml catalog
307
   */
308
   public static String createQuery(String value) {
309
     return createQuery(value, "any");
310
   }
311
}
312

    
313
/**
314
 * '$Log$
315
 * 'Revision 1.10  2000/07/26 20:40:41  higgins
316
 * 'no message
317
 * '
318
 * 'Revision 1.9  2000/06/26 10:35:04  jones
319
 * 'Merged in substantial changes to DBWriter and associated classes and to
320
 * 'the MetaCatServlet in order to accomodate the new UPDATE and DELETE
321
 * 'functions.  The command line tools and the parameters for the
322
 * 'servlet have changed substantially.
323
 * '
324
 * 'Revision 1.8.2.2  2000/06/25 23:38:16  jones
325
 * 'Added RCSfile keyword
326
 * '
327
 * 'Revision 1.8.2.1  2000/06/25 23:34:17  jones
328
 * 'Changed documentation formatting, added log entries at bottom of source files
329
 * ''
330
 */
(8-8/25)