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: tao $'
13
 *     '$Date: 2004-04-01 15:40:28 -0800 (Thu, 01 Apr 2004) $'
14
 * '$Revision: 2093 $'
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
    private StringBuffer textBuffer = new StringBuffer();
119

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

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

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

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

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

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

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

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

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

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

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

    
259
    }
260

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

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

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

    
306
    }
307

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
530
        // Set up the SAX document handlers for parsing
531
        try {
532

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

    
536
            // Set the ContentHandler to this instance
537
            parser.setContentHandler(this);
538

    
539
            // Set the error Handler to this instance
540
            parser.setErrorHandler(this);
541

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

    
547
        return parser;
548
    }
549

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

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

    
582
    /**
583
     * callback method used by the SAX Parser when the end tag of an element is
584
     * detected. Used in this context to parse and store the query information
585
     * in class variables.
586
     */
587
    public void endElement(String uri, String localName, String qName)
588
            throws SAXException
589
    {
590
        BasicNode leaving = (BasicNode) elementStack.pop();
591
        if (leaving.getTagName().equals("queryterm")) {
592
            boolean isCaseSensitive = (new Boolean(leaving
593
                    .getAttribute("casesensitive"))).booleanValue();
594
            QueryTerm currentTerm = null;
595
            if (currentPathexpr == null) {
596
                currentTerm = new QueryTerm(isCaseSensitive, leaving
597
                        .getAttribute("searchmode"), currentValue);
598
            } else {
599
                currentTerm = new QueryTerm(isCaseSensitive, leaving
600
                        .getAttribute("searchmode"), currentValue,
601
                        currentPathexpr);
602
            }
603
            QueryGroup currentGroup = (QueryGroup) queryStack.peek();
604
            currentGroup.addChild(currentTerm);
605
            currentValue = null;
606
            currentPathexpr = null;
607
        } else if (leaving.getTagName().equals("querygroup")) {
608
            QueryGroup leavingGroup = (QueryGroup) queryStack.pop();
609
        } else if (leaving.getTagName().equals("meta_file_id")) {
610
              meta_file_id = textBuffer.toString().trim();
611
        } else if (leaving.getTagName().equals("querytitle")) {
612
              queryTitle = textBuffer.toString().trim();
613
        } else if (leaving.getTagName().equals("value")) {
614
              currentValue = textBuffer.toString().trim();
615
        } else if (leaving.getTagName().equals("pathexpr")) {
616
              currentPathexpr = textBuffer.toString().trim();
617
        } else if (leaving.getTagName().equals("returndoctype")) {
618
              returnDocList.add(textBuffer.toString().trim());
619
        } else if (leaving.getTagName().equals("filterdoctype")) {
620
              filterDocList.add(textBuffer.toString().trim());
621
        } else if (leaving.getTagName().equals("returnfield")) {
622
              handleReturnField(textBuffer.toString().trim());
623
        } else if (leaving.getTagName().equals("filterdoctype")) {
624
              filterDocList.add(textBuffer.toString().trim());
625
        } else if (leaving.getTagName().equals("owner")) {
626
              ownerList.add(textBuffer.toString().trim());
627
        } else if (leaving.getTagName().equals("site")) {
628
              siteList.add(textBuffer.toString().trim());
629
        }
630

    
631
        //rest textBuffer
632
        textBuffer = null;
633
        textBuffer = new StringBuffer();
634

    
635
    }
636

    
637
    /**
638
     * callback method used by the SAX Parser when the text sequences of an xml
639
     * stream are detected. Used in this context to parse and store the query
640
     * information in class variables.
641
     */
642
    public void characters(char ch[], int start, int length)
643
    {
644
      // buffer all text nodes for same element. This is for text was splited
645
      // into different nodes
646
      textBuffer.append(new String(ch, start, length));
647

    
648
    }
649

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

    
682
    /**
683
     * create a SQL serialization of the query that this instance represents
684
     */
685
    public String printSQL(boolean useXMLIndex)
686
    {
687

    
688
        StringBuffer self = new StringBuffer();
689

    
690
        self.append("SELECT docid,docname,doctype,");
691
        self.append("date_created, date_updated, rev ");
692
        self.append("FROM xml_documents WHERE docid IN (");
693

    
694
        // This determines the documents that meet the query conditions
695
        self.append(query.printSQL(useXMLIndex));
696

    
697
        self.append(") ");
698

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

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

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

    
760
        // if there is only one percentage search item, this query is a
761
        // percentage
762
        // search query
763
        MetaCatUtil.debugMessage("percentage number: "
764
                + query.getPercentageSymbolCount(), 35);
765
        if (query.getPercentageSymbolCount() == 1) {
766
            MetaCatUtil.debugMessage("it is a percentage search", 30);
767
            percentageSearch = true;
768
        }
769

    
770
        return self.toString();
771
    }
772

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

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

    
835
            boolean firstfield = true;
836
            //put the returnfields into the query
837
            //the for loop allows for multiple fields
838
            for (int i = 0; i < returnFieldList.size(); i++) {
839
                if (firstfield) {
840
                    firstfield = false;
841
                } else {
842
                    self.append(" UNION ");
843
                }
844
                String path  = (String) returnFieldList.elementAt(i);
845
                self.append("select xml_nodes.docid, ");
846
                self.append("'"+ path  + "' as path, xml_nodes.nodedata, ");
847
                self.append("xml_nodes.parentnodeid ");
848
                self.append("from xml_nodes, xml_documents ");
849
                self.append("where parentnodeid IN ");
850
                self.append(QueryTerm.useNestedStatements(path));
851

    
852
                self.append(" AND xml_nodes.docid in (");
853
                self.append(doclist);
854
                self.append(") AND xml_nodes.nodetype = 'TEXT'");
855
                self.append(" AND xml_nodes.rootnodeid = xml_documents.rootnodeid");
856

    
857
                addAccessRestrictionSQL(unaccessableNodePair, self);
858
            }
859

    
860
            return self.toString();
861
        }
862
    }
863

    
864
    /**
865
     * This method prints sql based upon the &lt;returnfield&gt; tag in the
866
     * pathquery document. This allows for customization of the returned fields.
867
     * It uses the xml_index table and so assumes that this table has been
868
     * built.
869
     *
870
     * @param doclist the list of document ids to search
871
     * @param unaccessableNodePair the node pairs (start id and end id)
872
     *            which this user should not access
873
     */
874
    public String printExtendedSQL(String doclist,
875
            Hashtable unaccessableNodePair)
876
    {
877
        StringBuffer self = new StringBuffer();
878
        self.append("select xml_nodes.docid, xml_index.path, xml_nodes.nodedata, ");
879
        self.append("xml_nodes.parentnodeid ");
880
        self.append("from xml_index, xml_nodes where xml_index.nodeid=");
881
        self.append("xml_nodes.parentnodeid and (xml_index.path like '");
882
        boolean firstfield = true;
883
        //put the returnfields into the query
884
        //the for loop allows for multiple fields
885
        for (int i = 0; i < returnFieldList.size(); i++) {
886
            if (firstfield) {
887
                firstfield = false;
888
                self.append((String) returnFieldList.elementAt(i));
889
                self.append("' ");
890
            } else {
891
                self.append("or xml_index.path like '");
892
                self.append((String) returnFieldList.elementAt(i));
893
                self.append("' ");
894
            }
895
        }
896
        self.append(") AND xml_nodes.docid in (");
897
        self.append(doclist);
898
        self.append(") AND xml_nodes.nodetype = 'TEXT'");
899

    
900
        addAccessRestrictionSQL(unaccessableNodePair, self);
901

    
902
        return self.toString();
903
    }
904

    
905
    /**
906
     * Create the SQl necessary to restrict access to allowed nodes.  This is
907
     * accomplished by restricting the nodes that are returned to include
908
     * only those whose IDs fall outside of a set of start/stop pairs of
909
     * nodeid values.  These pairs are passed in as a hash, with the key
910
     * containing the start nodeid and the value containing the end nodeid.
911
     * Any nodes between these start and end nodeid values will be excluded
912
     * from the results.
913
     *
914
     * @param unaccessableNodePair hash of start/end nodeid pairs to restrict
915
     * @param self a stringbuffer to which the genrated SQL is appended
916
     */
917
    private void addAccessRestrictionSQL(Hashtable unaccessableNodePair,
918
            StringBuffer self)
919
    {
920
        // add control part for extended query
921
        Enumeration en = unaccessableNodePair.keys();
922

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

    
940
    /**
941
     * This method prints sql that finds the values of attributes in the xml
942
     * documents based upon the whether the returnfield tag in the pathquery
943
     * document has an attribute symbol (@). This allows for customization of
944
     * the returned fields.
945
     *
946
     * @param doclist the list of document ids to search
947
     * @param useXMLIndex a boolean flag indicating whether to search using
948
     *            xml_index
949
     */
950
    public String printAttributeQuery(String doclist, boolean useXMLIndex)
951
    {
952
        if (useXMLIndex) {
953
            return printAttributeQuery(doclist);
954
        } else {
955
            StringBuffer self = new StringBuffer();
956
            boolean firstfield = true;
957
            //put the returnfields attributes into the query
958
            //the for loop allows for multiple fields and attributes
959
            Enumeration returnAttributes = attributeReturnList.elements();
960
            while (returnAttributes.hasMoreElements()) {
961
                Vector currentVector = (Vector) returnAttributes.nextElement();
962
                String returnPath = (String) currentVector.elementAt(0);
963
                String attributeName = (String) currentVector.elementAt(1);
964
                if (firstfield) {
965
                    firstfield = false;
966
                } else {
967
                    self.append(" UNION ");
968
                }
969
                self.append("select xml_nodes.docid, '");
970
                self.append(returnPath);
971
                self.append("' as path, xml_nodes.nodedata, xml_nodes.nodename ");
972
                self.append("from xml_nodes, xml_documents ");
973
                self.append("where parentnodeid IN ");
974
                self.append(QueryTerm.useNestedStatements(returnPath));
975
                self.append(" AND xml_nodes.nodename like '");
976
                self.append(attributeName);
977
                self.append("' AND xml_nodes.docid in (");
978
                self.append(doclist);
979
                self.append(") AND xml_nodes.nodetype = 'ATTRIBUTE'");
980
                self.append(" AND xml_nodes.rootnodeid = xml_documents.rootnodeid");
981
            }
982

    
983
            MetaCatUtil.debugMessage("Attribute query: " + self.toString(), 30);
984

    
985
            return self.toString();
986
        }
987
    }
988

    
989
    /**
990
     * This method prints sql that finds the values of attributes in the xml
991
     * documents based upon the whether the returnfield tag in the pathquery
992
     * document has an attribute symbol (@). This allows for customization of
993
     * the returned fields.
994
     *
995
     * @param doclist the list of document ids to search
996
     */
997
    public String printAttributeQuery(String doclist)
998
    {
999
        StringBuffer self = new StringBuffer();
1000
        self.append("select xml_nodes.docid, xml_index.path, ");
1001
        self.append("xml_nodes.nodedata, xml_nodes.nodename ");
1002
        self.append("from xml_index, xml_nodes where xml_index.nodeid=");
1003
        self.append("xml_nodes.parentnodeid and (");
1004
        boolean firstfield = true;
1005
        //put the returnfields attributes into the query
1006
        //the for loop allows for multiple fields and attributes
1007
        Enumeration returnAttributes = attributeReturnList.elements();
1008
        while (returnAttributes.hasMoreElements()) {
1009
            Vector currentVector = (Vector) returnAttributes.nextElement();
1010
            String returnPath = (String) currentVector.elementAt(0);
1011
            String attributeName = (String) currentVector.elementAt(1);
1012
            if (firstfield) {
1013
                firstfield = false;
1014
                self.append("( xml_index.path like '");
1015
                self.append(returnPath);
1016
                self.append("' AND xml_nodes.nodename like '");
1017
                self.append(attributeName);
1018
                self.append("') ");
1019
            } else {
1020
                self.append(" or ( xml_index.path like '");
1021
                self.append(returnPath);
1022
                self.append("' AND xml_nodes.nodename like '");
1023
                self.append(attributeName);
1024
                self.append("') ");
1025
            }
1026
        }
1027
        self.append(") AND xml_nodes.docid in (");
1028
        self.append(doclist);
1029
        self.append(") AND xml_nodes.nodetype = 'ATTRIBUTE'");
1030
        MetaCatUtil.debugMessage("Attribute query: " + self.toString(), 30);
1031

    
1032
        return self.toString();
1033
    }
1034

    
1035
    public static String printRelationSQL(String docid)
1036
    {
1037
        StringBuffer self = new StringBuffer();
1038
        self.append("select subject, relationship, object, subdoctype, ");
1039
        self.append("objdoctype from xml_relation ");
1040
        self.append("where docid like '").append(docid).append("'");
1041
        return self.toString();
1042
    }
1043

    
1044
    public static String printGetDocByDoctypeSQL(String docid)
1045
    {
1046
        StringBuffer self = new StringBuffer();
1047

    
1048
        self.append("SELECT docid,docname,doctype,");
1049
        self.append("date_created, date_updated ");
1050
        self.append("FROM xml_documents WHERE docid IN (");
1051
        self.append(docid).append(")");
1052
        return self.toString();
1053
    }
1054

    
1055
    /**
1056
     * create a String description of the query that this instance represents.
1057
     * This should become a way to get the XML serialization of the query.
1058
     */
1059
    public String toString()
1060
    {
1061
        return "meta_file_id=" + meta_file_id + "\n" + query;
1062
        //DOCTITLE attr cleared from the db
1063
        //return "meta_file_id=" + meta_file_id + "\n" +
1064
        //"querytitle=" + querytitle + "\n" + query;
1065
    }
1066

    
1067
    /** A method to get rid of attribute part in path expression */
1068
    public static String newPathExpressionWithOutAttribute(String pathExpression)
1069
    {
1070
        if (pathExpression == null) { return null; }
1071
        int index = pathExpression.lastIndexOf(ATTRIBUTESYMBOL);
1072
        String newExpression = null;
1073
        if (index != 1) {
1074
            newExpression = pathExpression.substring(0, index - 1);
1075
        }
1076
        MetaCatUtil.debugMessage("The path expression without attributes: "
1077
                + newExpression, 30);
1078
        return newExpression;
1079
    }
1080

    
1081
    /** A method to get attribute name from path */
1082
    public static String getAttributeName(String path)
1083
    {
1084
        if (path == null) { return null; }
1085
        int index = path.lastIndexOf(ATTRIBUTESYMBOL);
1086
        int size = path.length();
1087
        String attributeName = null;
1088
        if (index != 1) {
1089
            attributeName = path.substring(index + 1, size);
1090
        }
1091
        MetaCatUtil.debugMessage("The attirbute name from path: "
1092
                + attributeName, 30);
1093
        return attributeName;
1094
    }
1095

    
1096
}
(51-51/62)