Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that represents a structured query, and can be 
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.
7
 *  Copyright: 2000 Regents of the University of California and the
8
 *             National Center for Ecological Analysis and Synthesis
9
 *    Authors: Matt Jones
10
 *    Release: @release@
11
 *
12
 *   '$Author: jones $'
13
 *     '$Date: 2004-03-29 11:24:05 -0800 (Mon, 29 Mar 2004) $'
14
 * '$Revision: 2069 $'
15
 *
16
 * This program is free software; you can redistribute it and/or modify
17
 * it under the terms of the GNU General Public License as published by
18
 * the Free Software Foundation; either version 2 of the License, or
19
 * (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, write to the Free Software
28
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
 */
30

    
31
package edu.ucsb.nceas.metacat;
32

    
33
import java.io.IOException;
34
import java.io.Reader;
35
import java.io.StringReader;
36
import java.util.Enumeration;
37
import java.util.Hashtable;
38
import java.util.Stack;
39
import java.util.Vector;
40

    
41
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
42

    
43
import org.xml.sax.Attributes;
44
import org.xml.sax.InputSource;
45
import org.xml.sax.SAXException;
46
import org.xml.sax.XMLReader;
47
import org.xml.sax.helpers.DefaultHandler;
48
import org.xml.sax.helpers.XMLReaderFactory;
49

    
50
/**
51
 * A Class that represents a structured query, and can be constructed from an
52
 * XML serialization conforming to
53
 * 
54
 * @see pathquery.dtd. The printSQL() method can be used to print a SQL
55
 *      serialization of the query.
56
 */
57
public class QuerySpecification extends DefaultHandler
58
{
59

    
60
    /** flag determining whether extended query terms are present */
61
    private boolean containsExtendedSQL = false;
62

    
63
    /** Identifier for this query document */
64
    private String meta_file_id;
65

    
66
    /** Title of this query */
67
    private String queryTitle;
68

    
69
    /** List of document types to be returned using package back tracing */
70
    private Vector returnDocList;
71

    
72
    /** List of document types to be searched */
73
    private Vector filterDocList;
74

    
75
    /** List of fields to be returned in result set */
76
    private Vector returnFieldList;
77

    
78
    /** List of users owning documents to be searched */
79
    private Vector ownerList;
80

    
81
    /** List of sites/scopes used to constrain search */
82
    private Vector siteList;
83

    
84
    /** The root query group that contains the recursive query constraints */
85
    private QueryGroup query = null;
86

    
87
    // Query data structures used temporarily during XML parsing
88
    private Stack elementStack;
89

    
90
    private Stack queryStack;
91

    
92
    private String currentValue;
93

    
94
    private String currentPathexpr;
95

    
96
    private String parserName = null;
97

    
98
    private String accNumberSeparator = null;
99

    
100
    private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
101

    
102
    private boolean percentageSearch = false;
103

    
104
    private String userName = null;
105

    
106
    private static final String PUBLIC = "public";
107

    
108
    private String[] group = null;
109

    
110
    public static final String ATTRIBUTESYMBOL = "@";
111

    
112
    private boolean hasAttributeReturnField = false;
113

    
114
    private Hashtable attributeReturnList = new Hashtable();
115

    
116
    private int countAttributeReturnField = 0;
117

    
118
    /**
119
     * construct an instance of the QuerySpecification class
120
     * 
121
     * @param queryspec
122
     *            the XML representation of the query (should conform to
123
     *            pathquery.dtd) as a Reader
124
     * @param parserName
125
     *            the fully qualified name of a Java Class implementing the
126
     *            org.xml.sax.XMLReader interface
127
     */
128
    public QuerySpecification(Reader queryspec, String parserName,
129
            String accNumberSeparator) throws IOException
130
    {
131
        super();
132

    
133
        // Initialize the class variables
134
        returnDocList = new Vector();
135
        filterDocList = new Vector();
136
        elementStack = new Stack();
137
        queryStack = new Stack();
138
        returnFieldList = new Vector();
139
        ownerList = new Vector();
140
        siteList = new Vector();
141
        this.parserName = parserName;
142
        this.accNumberSeparator = accNumberSeparator;
143

    
144
        // Initialize the parser and read the queryspec
145
        XMLReader parser = initializeParser();
146
        if (parser == null) {
147
            System.err.println("SAX parser not instantiated properly.");
148
        }
149
        try {
150
            parser.parse(new InputSource(queryspec));
151
        } catch (SAXException e) {
152
            System.err.println("error parsing data in "
153
                    + "QuerySpecification.QuerySpecification");
154
            System.err.println(e.getMessage());
155
        }
156
    }
157

    
158
    /**
159
     * construct an instance of the QuerySpecification class
160
     * 
161
     * @param queryspec
162
     *            the XML representation of the query (should conform to
163
     *            pathquery.dtd) as a String
164
     * @param parserName
165
     *            the fully qualified name of a Java Class implementing the
166
     *            org.xml.sax.Parser interface
167
     */
168
    public QuerySpecification(String queryspec, String parserName,
169
            String accNumberSeparator) throws IOException
170
    {
171
        this(new StringReader(queryspec), parserName, accNumberSeparator);
172
    }
173

    
174
    /**
175
     * construct an instance of the QuerySpecification class which don't need
176
     * to parser a xml document
177
     * 
178
     * @param accNumberSeparator
179
     *            the separator between doc version
180
     */
181
    public QuerySpecification(String accNumberSeparator) throws IOException
182
    {
183
        // Initialize the class variables
184
        returnDocList = new Vector();
185
        filterDocList = new Vector();
186
        elementStack = new Stack();
187
        queryStack = new Stack();
188
        returnFieldList = new Vector();
189
        ownerList = new Vector();
190
        siteList = new Vector();
191
        this.accNumberSeparator = accNumberSeparator;
192
    }
193

    
194
    /**
195
     * Method to set user name
196
     * 
197
     * @param myName
198
     *            the user name
199
     */
200
    public void setUserName(String myName)
201
    {
202
        //to lower case
203
        if (myName != null) {
204
            this.userName = myName.toLowerCase();
205
        } else {
206
            this.userName = myName;
207
        }
208
    }
209

    
210
    /**
211
     * Method to set user group
212
     * 
213
     * @param myGroup
214
     *            the user group
215
     */
216
    public void setGroup(String[] myGroup)
217
    {
218
        this.group = myGroup;
219
    }
220

    
221
    /**
222
     * Method to indicate this query is a percentage search
223
     */
224
    public boolean isPercentageSearch()
225
    {
226
        return percentageSearch;
227
    }
228

    
229
    /*
230
     * Method to get owner query. If it is owner it has all permission
231
     */
232
    private String createOwerQuery()
233
    {
234
        String ownerQuery = null;
235
        ownerQuery = "SELECT docid FROM xml_documents WHERE ";
236
        if (userName != null && !userName.equals("")) {
237
            ownerQuery = ownerQuery + "lower(user_owner) ='" + userName + "'";
238
        }
239

    
240
        MetaCatUtil.debugMessage("OwnerQuery: " + ownerQuery, 30);
241
        return ownerQuery;
242
    }
243

    
244
    /*
245
     * Method to create query for xml_access, this part is to get docid list
246
     * which have a allow rule for a given user
247
     */
248
    private String createAllowRuleQuery()
249
    {
250
        String allowQuery = null;
251
        String allowString = constructAllowString();
252
        allowQuery = "SELECT docid from xml_access WHERE( " + allowString;
253
        allowQuery = allowQuery + ") AND subtreeid IS NULL";
254
        MetaCatUtil.debugMessage("allow query is: " + allowQuery, 30);
255
        return allowQuery;
256

    
257
    }
258

    
259
    /* Method to construct a allow rule string */
260
    private String constructAllowString()
261
    {
262
        String allowQuery = "";
263
        // add allow rule for user name
264
        if (userName != null && !userName.equals("")) {
265
            allowQuery = allowQuery + "(lower(principal_name) = '" + userName
266
                    + "' AND perm_type = 'allow'"
267
                    + " AND (permission='4' OR permission='7'))";
268
        }
269
        // add allow rule for public
270
        allowQuery = allowQuery + "OR (lower(principal_name) = '" + PUBLIC
271
                + "' AND perm_type = 'allow'"
272
                + " AND (permission='4' OR permission='7'))";
273

    
274
        // add allow rule for group
275
        if (group != null) {
276
            for (int i = 0; i < group.length; i++) {
277
                String groupUint = group[i];
278
                if (groupUint != null && !groupUint.equals("")) {
279
                    groupUint = groupUint.toLowerCase();
280
                    allowQuery = allowQuery + " OR (lower(principal_name) = '"
281
                            + groupUint + "' AND perm_type = 'allow'"
282
                            + " AND (permission='4' OR permission='7'))";
283
                }//if
284
            }//for
285
        }//if
286
        MetaCatUtil.debugMessage("allow string is: " + allowQuery, 40);
287
        return allowQuery;
288
    }
289

    
290
    /*
291
     * Method to create query for xml_access, this part is to get docid list
292
     * which have a deny rule and perm_order is allowFirst for a given user.
293
     * This means the user will be denied to read
294
     */
295
    private String createDenyRuleQuery()
296
    {
297
        String denyQuery = null;
298
        String denyString = constructDenyString();
299
        denyQuery = "SELECT docid from xml_access WHERE( " + denyString;
300
        denyQuery = denyQuery + ") AND subtreeid IS NULL ";
301
        MetaCatUtil.debugMessage("denyquery is: " + denyQuery, 30);
302
        return denyQuery;
303

    
304
    }
305

    
306
    /* Construct deny string */
307
    private String constructDenyString()
308
    {
309
        String denyQuery = "";
310
        // add deny rule for user name
311
        if (userName != null && !userName.equals("")) {
312
            denyQuery = denyQuery + "(lower(principal_name) = '" + userName
313
                    + "' AND perm_type = 'deny' "
314
                    + "AND perm_order ='allowFirst'"
315
                    + " AND (permission='4' OR permission='7'))";
316
        }
317
        // add deny rule for public
318
        denyQuery = denyQuery + "OR (lower(principal_name) = '" + PUBLIC
319
                + "' AND perm_type = 'deny' " + "AND perm_order ='allowFirst'"
320
                + " AND (permission='4' OR permission='7'))";
321

    
322
        // add allow rule for group
323
        if (group != null) {
324
            for (int i = 0; i < group.length; i++) {
325
                String groupUint = group[i];
326
                if (groupUint != null && !groupUint.equals("")) {
327
                    groupUint = groupUint.toLowerCase();
328
                    denyQuery = denyQuery + " OR (lower(principal_name) = '"
329
                            + groupUint + "' AND perm_type = 'deny' "
330
                            + "AND perm_order ='allowFirst'"
331
                            + " AND (permission='4' OR permission='7'))";
332
                }//if
333
            }//for
334
        }//if
335
        return denyQuery;
336
    }
337

    
338
    /**
339
     * Method to append a access control query to SQL. So in DBQuery class, we
340
     * can get docid from both user specified query and access control query.
341
     * We don't need to checking permission after we get the doclist. It will
342
     * be good to performance
343
     *  
344
     */
345
    public String getAccessQuery()
346
    {
347
        String accessQuery = null;
348
        String onwer = createOwerQuery();
349
        String allow = createAllowRuleQuery();
350
        String deny = createDenyRuleQuery();
351
        accessQuery = " AND (docid IN(" + onwer + ")";
352
        accessQuery = accessQuery + " OR (docid IN (" + allow + ")"
353
                + " AND docid NOT IN (" + deny + ")))";
354
        MetaCatUtil.debugMessage("accessquery is: " + accessQuery, 30);
355
        return accessQuery;
356
    }
357

    
358
    /**
359
     * Returns true if the parsed query contains and extended xml query (i.e.
360
     * there is at least one &lt;returnfield&gt; in the pathquery document)
361
     */
362
    public boolean containsExtendedSQL()
363
    {
364
        if (containsExtendedSQL) {
365
            return true;
366
        } else {
367
            return false;
368
        }
369
    }
370

    
371
    /**
372
     * A method to get if the query has an attribute return field
373
     */
374
    public boolean containAttributeReturnField()
375
    {
376
        return hasAttributeReturnField;
377
    }
378

    
379
    /**
380
     * Accessor method to return the identifier of this Query
381
     */
382
    public String getIdentifier()
383
    {
384
        return meta_file_id;
385
    }
386

    
387
    /**
388
     * method to set the identifier of this query
389
     */
390
    public void setIdentifier(String id)
391
    {
392
        this.meta_file_id = id;
393
    }
394

    
395
    /**
396
     * Accessor method to return the title of this Query
397
     */
398
    public String getQueryTitle()
399
    {
400
        return queryTitle;
401
    }
402

    
403
    /**
404
     * method to set the title of this query
405
     */
406
    public void setQueryTitle(String title)
407
    {
408
        this.queryTitle = title;
409
    }
410

    
411
    /**
412
     * Accessor method to return a vector of the return document types as
413
     * defined in the &lt;returndoctype&gt; tag in the pathquery dtd.
414
     */
415
    public Vector getReturnDocList()
416
    {
417
        return this.returnDocList;
418
    }
419

    
420
    /**
421
     * method to set the list of return docs of this query
422
     */
423
    public void setReturnDocList(Vector returnDocList)
424
    {
425
        this.returnDocList = returnDocList;
426
    }
427

    
428
    /**
429
     * Accessor method to return a vector of the filter doc types as defined in
430
     * the &lt;filterdoctype&gt; tag in the pathquery dtd.
431
     */
432
    public Vector getFilterDocList()
433
    {
434
        return this.filterDocList;
435
    }
436

    
437
    /**
438
     * method to set the list of filter docs of this query
439
     */
440
    public void setFilterDocList(Vector filterDocList)
441
    {
442
        this.filterDocList = filterDocList;
443
    }
444

    
445
    /**
446
     * Accessor method to return a vector of the extended return fields as
447
     * defined in the &lt;returnfield&gt; tag in the pathquery dtd.
448
     */
449
    public Vector getReturnFieldList()
450
    {
451
        return this.returnFieldList;
452
    }
453

    
454
    /**
455
     * method to set the list of fields to be returned by this query
456
     */
457
    public void setReturnFieldList(Vector returnFieldList)
458
    {
459
        this.returnFieldList = returnFieldList;
460
    }
461

    
462
    /**
463
     * Accessor method to return a vector of the owner fields as defined in the
464
     * &lt;owner&gt; tag in the pathquery dtd.
465
     */
466
    public Vector getOwnerList()
467
    {
468
        return this.ownerList;
469
    }
470

    
471
    /**
472
     * method to set the list of owners used to constrain this query
473
     */
474
    public void setOwnerList(Vector ownerList)
475
    {
476
        this.ownerList = ownerList;
477
    }
478

    
479
    /**
480
     * Accessor method to return a vector of the site fields as defined in the
481
     * &lt;site&gt; tag in the pathquery dtd.
482
     */
483
    public Vector getSiteList()
484
    {
485
        return this.siteList;
486
    }
487

    
488
    /**
489
     * method to set the list of sites used to constrain this query
490
     */
491
    public void setSiteList(Vector siteList)
492
    {
493
        this.siteList = siteList;
494
    }
495

    
496
    /**
497
     * get the QueryGroup used to express query constraints
498
     */
499
    public QueryGroup getQueryGroup()
500
    {
501
        return query;
502
    }
503

    
504
    /**
505
     * set the querygroup
506
     */
507
    public void setQueryGroup(QueryGroup group)
508
    {
509
        query = group;
510
    }
511

    
512
    /**
513
     * set if this query sepcification has extendQuery(has return doc type or
514
     * not)
515
     */
516
    public void setContainsExtenedSQL(boolean hasExtenedQuery)
517
    {
518
        containsExtendedSQL = hasExtenedQuery;
519
    }
520

    
521
    /**
522
     * Set up the SAX parser for reading the XML serialized query
523
     */
524
    private XMLReader initializeParser()
525
    {
526
        XMLReader parser = null;
527

    
528
        // Set up the SAX document handlers for parsing
529
        try {
530

    
531
            // Get an instance of the parser
532
            parser = XMLReaderFactory.createXMLReader(parserName);
533

    
534
            // Set the ContentHandler to this instance
535
            parser.setContentHandler(this);
536

    
537
            // Set the error Handler to this instance
538
            parser.setErrorHandler(this);
539

    
540
        } catch (Exception e) {
541
            System.err.println("Error in QuerySpcecification.initializeParser "
542
                    + e.toString());
543
        }
544

    
545
        return parser;
546
    }
547

    
548
    /**
549
     * callback method used by the SAX Parser when the start tag of an element
550
     * is detected. Used in this context to parse and store the query
551
     * information in class variables.
552
     */
553
    public void startElement(String uri, String localName, String qName,
554
            Attributes atts) throws SAXException
555
    {
556
        BasicNode currentNode = new BasicNode(localName);
557
        // add attributes to BasicNode here
558
        if (atts != null) {
559
            int len = atts.getLength();
560
            for (int i = 0; i < len; i++) {
561
                currentNode
562
                        .setAttribute(atts.getLocalName(i), atts.getValue(i));
563
            }
564
        }
565

    
566
        elementStack.push(currentNode);
567
        if (currentNode.getTagName().equals("querygroup")) {
568
            QueryGroup currentGroup = new QueryGroup(currentNode
569
                    .getAttribute("operator"));
570
            if (query == null) {
571
                query = currentGroup;
572
            } else {
573
                QueryGroup parentGroup = (QueryGroup) queryStack.peek();
574
                parentGroup.addChild(currentGroup);
575
            }
576
            queryStack.push(currentGroup);
577
        }
578
    }
579

    
580
    /**
581
     * callback method used by the SAX Parser when the end tag of an element is
582
     * detected. Used in this context to parse and store the query information
583
     * in class variables.
584
     */
585
    public void endElement(String uri, String localName, String qName)
586
            throws SAXException
587
    {
588
        BasicNode leaving = (BasicNode) elementStack.pop();
589
        if (leaving.getTagName().equals("queryterm")) {
590
            boolean isCaseSensitive = (new Boolean(leaving
591
                    .getAttribute("casesensitive"))).booleanValue();
592
            QueryTerm currentTerm = null;
593
            if (currentPathexpr == null) {
594
                currentTerm = new QueryTerm(isCaseSensitive, leaving
595
                        .getAttribute("searchmode"), currentValue);
596
            } else {
597
                currentTerm = new QueryTerm(isCaseSensitive, leaving
598
                        .getAttribute("searchmode"), currentValue,
599
                        currentPathexpr);
600
            }
601
            QueryGroup currentGroup = (QueryGroup) queryStack.peek();
602
            currentGroup.addChild(currentTerm);
603
            currentValue = null;
604
            currentPathexpr = null;
605
        } else if (leaving.getTagName().equals("querygroup")) {
606
            QueryGroup leavingGroup = (QueryGroup) queryStack.pop();
607
        }
608
    }
609

    
610
    /**
611
     * callback method used by the SAX Parser when the text sequences of an xml
612
     * stream are detected. Used in this context to parse and store the query
613
     * information in class variables.
614
     */
615
    public void characters(char ch[], int start, int length)
616
    {
617

    
618
        String inputString = new String(ch, start, length);
619
        BasicNode currentNode = (BasicNode) elementStack.peek();
620
        String currentTag = currentNode.getTagName();
621
        if (currentTag.equals("meta_file_id")) {
622
            meta_file_id = inputString;
623
        } else if (currentTag.equals("querytitle")) {
624
            queryTitle = inputString;
625
        } else if (currentTag.equals("value")) {
626
            currentValue = inputString;
627
        } else if (currentTag.equals("pathexpr")) {
628
            currentPathexpr = inputString;
629
        } else if (currentTag.equals("returndoctype")) {
630
            returnDocList.add(inputString);
631
        } else if (currentTag.equals("filterdoctype")) {
632
            filterDocList.add(inputString);
633
        } else if (currentTag.equals("returnfield")) {
634
            handleReturnField(inputString);
635
        } else if (currentTag.equals("filterdoctype")) {
636
            filterDocList.add(inputString);
637
        } else if (currentTag.equals("owner")) {
638
            ownerList.add(inputString);
639
        } else if (currentTag.equals("site")) {
640
            siteList.add(inputString);
641
        }
642
    }
643

    
644
    /**
645
     * Method to transfer string to return field
646
     */
647
    public void handleReturnField(String inputString)
648
    {
649
        // make sure if return fields has an attribute or not
650
        if (inputString.indexOf(ATTRIBUTESYMBOL) == -1) {
651
            // no attribute value will be returned
652
            returnFieldList.add(inputString);
653
            containsExtendedSQL = true;
654
        } else {
655
            // has a attribute return field
656
            // divied the return filed into two parts, one is path and the
657
            // other is attribue name
658
            String returnPath = newPathExpressionWithOutAttribute(inputString);
659
            String attributeName = getAttributeName(inputString);
660
            Vector pathInfo = new Vector();
661
            // the vector has the information about return path and
662
            // attributename
663
            pathInfo.addElement(returnPath);
664
            pathInfo.addElement(attributeName);
665
            // put the vector into a hash table. The reseaon why don't put
666
            // return path or attributename as a key is because they are not
667
            // unique
668
            attributeReturnList.put(new Integer(countAttributeReturnField),
669
                    pathInfo);
670
            countAttributeReturnField++;
671
            hasAttributeReturnField = true;
672
            containsExtendedSQL = true;
673

    
674
        }
675
    }
676

    
677
    /**
678
     * create a SQL serialization of the query that this instance represents
679
     */
680
    public String printSQL(boolean useXMLIndex)
681
    {
682

    
683
        StringBuffer self = new StringBuffer();
684

    
685
        self.append("SELECT docid,docname,doctype,");
686
        self.append("date_created, date_updated, rev ");
687
        self.append("FROM xml_documents WHERE docid IN (");
688

    
689
        // This determines the documents that meet the query conditions
690
        self.append(query.printSQL(useXMLIndex));
691

    
692
        self.append(") ");
693

    
694
        // Add SQL to filter for doctypes requested in the query
695
        // This is an implicit OR for the list of doctypes. Only doctypes in
696
        // this
697
        // list will be searched if the tag is present
698
        if (!filterDocList.isEmpty()) {
699
            boolean firstdoctype = true;
700
            self.append(" AND (");
701
            Enumeration en = filterDocList.elements();
702
            while (en.hasMoreElements()) {
703
                String currentDoctype = (String) en.nextElement();
704
                if (firstdoctype) {
705
                    firstdoctype = false;
706
                    self.append(" doctype = '" + currentDoctype + "'");
707
                } else {
708
                    self.append(" OR doctype = '" + currentDoctype + "'");
709
                }
710
            }
711
            self.append(") ");
712
        }
713

    
714
        // Add SQL to filter for owners requested in the query
715
        // This is an implicit OR for the list of owners
716
        if (!ownerList.isEmpty()) {
717
            boolean first = true;
718
            self.append(" AND (");
719
            Enumeration en = ownerList.elements();
720
            while (en.hasMoreElements()) {
721
                String current = (String) en.nextElement();
722
                if (current != null) {
723
                    current = current.toLowerCase();
724
                }
725
                if (first) {
726
                    first = false;
727
                    self.append(" lower(user_owner) = '" + current + "'");
728
                } else {
729
                    self.append(" OR lower(user_owner) = '" + current + "'");
730
                }
731
            }
732
            self.append(") ");
733
        }
734

    
735
        // Add SQL to filter for sites requested in the query
736
        // This is an implicit OR for the list of sites
737
        if (!siteList.isEmpty()) {
738
            boolean first = true;
739
            self.append(" AND (");
740
            Enumeration en = siteList.elements();
741
            while (en.hasMoreElements()) {
742
                String current = (String) en.nextElement();
743
                if (first) {
744
                    first = false;
745
                    self.append(" SUBSTR(docid, 1, INSTR(docid, '"
746
                            + accNumberSeparator + "')-1) = '" + current + "'");
747
                } else {
748
                    self.append(" OR SUBSTR(docid, 1, INSTR(docid, '"
749
                            + accNumberSeparator + "')-1) = '" + current + "'");
750
                }
751
            }
752
            self.append(") ");
753
        }
754

    
755
        // if there is only one percentage search item, this query is a
756
        // percentage
757
        // search query
758
        MetaCatUtil.debugMessage("percentage number: "
759
                + query.getPercentageSymbolCount(), 35);
760
        if (query.getPercentageSymbolCount() == 1) {
761
            MetaCatUtil.debugMessage("it is a percentage search", 30);
762
            percentageSearch = true;
763
        }
764

    
765
        return self.toString();
766
    }
767

    
768
    /**
769
     * This sql command will selecet startnodeid and endnodeid that user can
770
     * NOT access
771
     */
772
    public String printAccessControlSQLForReturnField(String doclist)
773
    {
774
        StringBuffer sql = new StringBuffer();
775
        String allowString = constructAllowString();
776
        String denyString = constructDenyString();
777
        sql.append("SELECT distinct startnodeid, endnodeid from xml_access ");
778
        sql.append("WHERE docid in (");
779
        sql.append(doclist);
780
        sql.append(") AND startnodeid IS NOT NULL AND ");
781
        sql.append("(");
782
        sql.append("(");
783
        sql
784
                .append("startnodeid NOT IN (SELECT startnodeid from xml_access, xml_documents ");
785
        sql.append(" WHERE xml_access.docid = xml_documents.docid");
786
        sql.append(" AND lower(xml_documents.user_owner) ='");
787
        sql.append(userName);
788
        sql.append("' AND xml_access.startnodeid IS NOT NULL)");
789
        sql.append(")");
790
        sql.append(" AND ");
791
        sql.append("(");
792
        sql
793
                .append("(startnodeid NOT IN (SELECT startnodeid from xml_access where( ");
794
        sql.append(allowString);
795
        sql.append(") AND (startnodeid IS NOT NULL))");
796
        sql.append(")");
797
        sql
798
                .append(" OR (startnodeid IN (SELECT startnodeid from xml_access where( ");
799
        sql.append(denyString);
800
        sql.append(") AND (startnodeid IS NOT NULL))");
801
        sql.append(")");
802
        sql.append(")");
803
        sql.append(")");
804
        MetaCatUtil.debugMessage("accessControlSQLForReturnField: "
805
                + sql.toString(), 30);
806
        return sql.toString();
807
    }
808

    
809
    /**
810
     * This method prints sql based upon the &lt;returnfield&gt; tag in the
811
     * pathquery document. This allows for customization of the returned fields.
812
     * If the boolean useXMLIndex paramter is false, it uses a recursive query on 
813
     * xml_nodes to find the fields to be included by their path expression, and 
814
     * avoids the use of the xml_index table.
815
     * 
816
     * @param doclist 
817
     *            the list of document ids to search by
818
     * @param unaccessableNodePair
819
     *            the node pair(start id and end id) which this user could not
820
     *            access it
821
     * @param useXMLIndex a boolean flag indicating whether to search using xml_index
822
     */
823
    public String printExtendedSQL(String doclist,
824
            Hashtable unaccessableNodePair, boolean useXMLIndex)
825
    {
826
        if (useXMLIndex) {
827
            return printExtendedSQL(doclist, unaccessableNodePair);
828
        } else {
829
            StringBuffer self = new StringBuffer();
830

    
831
            boolean firstfield = true;
832
            //put the returnfields into the query
833
            //the for loop allows for multiple fields
834
            for (int i = 0; i < returnFieldList.size(); i++) {
835
                if (firstfield) {
836
                    firstfield = false;
837
                    self.append("(");
838
                } else {
839
                    self.append(" UNION (");   
840
                }
841
                String path  = (String) returnFieldList.elementAt(i);
842
                self.append("select xml_nodes.docid, ");
843
                self.append("'"+ path  + "' as path, ");
844
                self.append("xml_nodes.nodedata, ");
845
                self.append("xml_nodes.parentnodeid ");
846
                self.append("from xml_nodes, xml_documents ");
847
                self.append("where parentnodeid IN ");
848
                self.append(QueryTerm.useNestedStatements(path));
849
                
850
                self.append(" AND xml_nodes.docid in (");
851
                self.append(doclist);
852
                self.append(")");
853
                self.append(" AND xml_nodes.nodetype = 'TEXT'");
854
                self.append(" AND xml_nodes.rootnodeid = xml_documents.rootnodeid");
855
                
856
                // add control part for extended query
857
                Enumeration en = unaccessableNodePair.keys();
858

    
859
                while (en.hasMoreElements()) {
860
                    // Get control pairs in object
861
                    Long startNodeIdObject = (Long) en.nextElement();
862
                    Long endNodeIdObject = (Long) unaccessableNodePair
863
                            .get(startNodeIdObject);
864
                    // change it to long
865
                    long startNodeId = startNodeIdObject.longValue();
866
                    long endNodeId = endNodeIdObject.longValue();
867
                    // add into query
868
                    self.append(" AND( xml_nodes.nodeid < ");
869
                    self.append(startNodeId);
870
                    self.append(" OR xml_nodes.nodeid > ");
871
                    self.append(endNodeId);
872
                    self.append(")");
873
                }
874
                self.append(")");
875
            }
876

    
877
            return self.toString();
878
        }
879
    }
880
    
881
    /**
882
     * This method prints sql based upon the &lt;returnfield&gt; tag in the
883
     * pathquery document. This allows for customization of the returned fields.
884
     * It uses the xml_index table and so assumes that this table has been
885
     * built.
886
     * 
887
     * @param doclist
888
     *            the list of document ids to search by
889
     * @param unaccessableNodePair
890
     *            the node pair(start id and end id) which this user could not
891
     *            access it
892
     */
893
    public String printExtendedSQL(String doclist, 
894
            Hashtable unaccessableNodePair)
895
    {
896
        StringBuffer self = new StringBuffer();
897
        self.append("select xml_nodes.docid, xml_index.path, xml_nodes.nodedata, ");
898
        self.append("xml_nodes.parentnodeid ");
899
        self.append("from xml_index, xml_nodes where xml_index.nodeid=");
900
        self.append("xml_nodes.parentnodeid and (xml_index.path like '");
901
        boolean firstfield = true;
902
        //put the returnfields into the query
903
        //the for loop allows for multiple fields
904
        for (int i = 0; i < returnFieldList.size(); i++) {
905
            if (firstfield) {
906
                firstfield = false;
907
                self.append((String) returnFieldList.elementAt(i));
908
                self.append("' ");
909
            } else {
910
                self.append("or xml_index.path like '");
911
                self.append((String) returnFieldList.elementAt(i));
912
                self.append("' ");
913
            }
914
        }
915
        self.append(") AND xml_nodes.docid in (");
916
        //self.append(query.printSQL());
917
        self.append(doclist);
918
        self.append(")");
919
        self.append(" AND xml_nodes.nodetype = 'TEXT'");
920

    
921
        // add control part for extended query
922
        Enumeration en = unaccessableNodePair.keys();
923

    
924
        while (en.hasMoreElements()) {
925
            // Get control pairs in object
926
            Long startNodeIdObject = (Long) en.nextElement();
927
            Long endNodeIdObject = (Long) unaccessableNodePair
928
                    .get(startNodeIdObject);
929
            // change it to long
930
            long startNodeId = startNodeIdObject.longValue();
931
            long endNodeId = endNodeIdObject.longValue();
932
            // add into query
933
            self.append(" AND( xml_nodes.nodeid < ");
934
            self.append(startNodeId);
935
            self.append(" OR xml_nodes.nodeid > ");
936
            self.append(endNodeId);
937
            self.append(")");
938
        }
939

    
940
        return self.toString();
941
    }
942

    
943
    /**
944
     * This method prints sql based upon the returnfield tag in the pathquery
945
     * document has an attribute. This allows for customization of the returned
946
     * fields
947
     * 
948
     * @param doclist
949
     *            the list of document ids to search by
950
     */
951
    public String printAttributeQuery(String doclist)
952
    {
953
        StringBuffer self = new StringBuffer();
954
        self.append("select xml_nodes.docid, xml_index.path, ");
955
        self.append("xml_nodes.nodedata, xml_nodes.nodename ");
956
        self.append("from xml_index, xml_nodes where xml_index.nodeid=");
957
        self.append("xml_nodes.parentnodeid and (");
958
        boolean firstfield = true;
959
        //put the returnfields attributes into the query
960
        //the for loop allows for multiple fields and attributes
961
        Enumeration returnAttributes = attributeReturnList.elements();
962
        while (returnAttributes.hasMoreElements()) {
963
            Vector currentVector = (Vector) returnAttributes.nextElement();
964
            String returnPath = (String) currentVector.elementAt(0);
965
            String attributeName = (String) currentVector.elementAt(1);
966
            if (firstfield) {
967
                firstfield = false;
968
                self.append("( xml_index.path like '");
969
                self.append(returnPath);
970
                self.append("' AND xml_nodes.nodename like '");
971
                self.append(attributeName);
972
                self.append("') ");
973
            } else {
974
                self.append(" or ( xml_index.path like '");
975
                self.append(returnPath);
976
                self.append("' AND xml_nodes.nodename like '");
977
                self.append(attributeName);
978
                self.append("') ");
979
            }
980
        }
981
        self.append(") AND xml_nodes.docid in (");
982
        //self.append(query.printSQL());
983
        self.append(doclist);
984
        self.append(")");
985
        self.append(" AND xml_nodes.nodetype = 'ATTRIBUTE'");
986
        MetaCatUtil.debugMessage("Attribute query: " + self.toString(), 30);
987

    
988
        return self.toString();
989
    }
990

    
991
    public static String printRelationSQL(String docid)
992
    {
993
        StringBuffer self = new StringBuffer();
994
        self.append("select subject, relationship, object, subdoctype, ");
995
        self.append("objdoctype from xml_relation ");
996
        self.append("where docid like '").append(docid).append("'");
997
        return self.toString();
998
    }
999

    
1000
    public static String printGetDocByDoctypeSQL(String docid)
1001
    {
1002
        StringBuffer self = new StringBuffer();
1003

    
1004
        self.append("SELECT docid,docname,doctype,");
1005
        self.append("date_created, date_updated ");
1006
        self.append("FROM xml_documents WHERE docid IN (");
1007
        self.append(docid).append(")");
1008
        return self.toString();
1009
    }
1010

    
1011
    /**
1012
     * create a String description of the query that this instance represents.
1013
     * This should become a way to get the XML serialization of the query.
1014
     */
1015
    public String toString()
1016
    {
1017
        return "meta_file_id=" + meta_file_id + "\n" + query;
1018
        //DOCTITLE attr cleared from the db
1019
        //return "meta_file_id=" + meta_file_id + "\n" +
1020
        //"querytitle=" + querytitle + "\n" + query;
1021
    }
1022

    
1023
    /* A method to get rid of attribute part in path expression */
1024
    public static String newPathExpressionWithOutAttribute(String pathExpression)
1025
    {
1026
        if (pathExpression == null) { return null; }
1027
        int index = pathExpression.lastIndexOf(ATTRIBUTESYMBOL);
1028
        String newExpression = null;
1029
        if (index != 1) {
1030
            newExpression = pathExpression.substring(0, index - 1);
1031
        }
1032
        MetaCatUtil.debugMessage("The path expression without attributes: "
1033
                + newExpression, 30);
1034
        return newExpression;
1035
    }
1036

    
1037
    /* A method to get attribute name from path */
1038
    public static String getAttributeName(String path)
1039
    {
1040
        if (path == null) { return null; }
1041
        int index = path.lastIndexOf(ATTRIBUTESYMBOL);
1042
        int size = path.length();
1043
        String attributeName = null;
1044
        if (index != 1) {
1045
            attributeName = path.substring(index + 1, size);
1046
        }
1047
        MetaCatUtil.debugMessage("The attirbute name from path: "
1048
                + attributeName, 30);
1049
        return attributeName;
1050
    }
1051

    
1052
}
(48-48/58)