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-26 15:25:53 -0800 (Fri, 26 Mar 2004) $'
14
 * '$Revision: 2067 $'
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.File;
34
import java.io.FileReader;
35
import java.io.IOException;
36
import java.io.Reader;
37
import java.io.StringReader;
38
import java.util.Enumeration;
39
import java.util.Hashtable;
40
import java.util.Stack;
41
import java.util.Vector;
42

    
43
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
44

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

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

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

    
65
    /** Identifier for this query document */
66
    private String meta_file_id;
67

    
68
    /** Title of this query */
69
    private String queryTitle;
70

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

    
74
    /** List of document types to be searched */
75
    private Vector filterDocList;
76

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

    
80
    /** List of users owning documents to be searched */
81
    private Vector ownerList;
82

    
83
    /** List of sites/scopes used to constrain search */
84
    private Vector siteList;
85

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

    
89
    // Query data structures used temporarily during XML parsing
90
    private Stack elementStack;
91

    
92
    private Stack queryStack;
93

    
94
    private String currentValue;
95

    
96
    private String currentPathexpr;
97

    
98
    private String parserName = null;
99

    
100
    private String accNumberSeparator = null;
101

    
102
    private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
103

    
104
    private boolean percentageSearch = false;
105

    
106
    private String userName = null;
107

    
108
    private static final String PUBLIC = "public";
109

    
110
    private String[] group = null;
111

    
112
    public static final String ATTRIBUTESYMBOL = "@";
113

    
114
    private boolean hasAttributeReturnField = false;
115

    
116
    private Hashtable attributeReturnList = new Hashtable();
117

    
118
    private int countAttributeReturnField = 0;
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
    /** Main routine for testing */
361
    static public void main(String[] args)
362
    {
363

    
364
        if (args.length < 1) {
365
            System.err.println("Wrong number of arguments!!!");
366
            System.err.println("USAGE: java QuerySpecification <xmlfile>");
367
            return;
368
        } else {
369
            int i = 0;
370
            boolean useXMLIndex = true;
371
            if (args[i].equals("-noindex")) {
372
                useXMLIndex = false;
373
                i++;
374
            }
375
            String xmlfile = args[i];
376

    
377
            try {
378
                MetaCatUtil util = new MetaCatUtil();
379
                FileReader xml = new FileReader(new File(xmlfile));
380
                QuerySpecification qspec = new QuerySpecification(xml, util
381
                        .getOption("saxparser"), util
382
                        .getOption("accNumberSeparator"));
383
                System.out.println(qspec.printSQL(useXMLIndex));
384

    
385
            } catch (IOException e) {
386
                System.err.println(e.getMessage());
387
            }
388

    
389
        }
390
    }
391

    
392
    /**
393
     * Returns true if the parsed query contains and extended xml query (i.e.
394
     * there is at least one &lt;returnfield&gt; in the pathquery document)
395
     */
396
    public boolean containsExtendedSQL()
397
    {
398
        if (containsExtendedSQL) {
399
            return true;
400
        } else {
401
            return false;
402
        }
403
    }
404

    
405
    /**
406
     * A method to get if the query has an attribute return field
407
     */
408
    public boolean containAttributeReturnField()
409
    {
410
        return hasAttributeReturnField;
411
    }
412

    
413
    /**
414
     * Accessor method to return the identifier of this Query
415
     */
416
    public String getIdentifier()
417
    {
418
        return meta_file_id;
419
    }
420

    
421
    /**
422
     * method to set the identifier of this query
423
     */
424
    public void setIdentifier(String id)
425
    {
426
        this.meta_file_id = id;
427
    }
428

    
429
    /**
430
     * Accessor method to return the title of this Query
431
     */
432
    public String getQueryTitle()
433
    {
434
        return queryTitle;
435
    }
436

    
437
    /**
438
     * method to set the title of this query
439
     */
440
    public void setQueryTitle(String title)
441
    {
442
        this.queryTitle = title;
443
    }
444

    
445
    /**
446
     * Accessor method to return a vector of the return document types as
447
     * defined in the &lt;returndoctype&gt; tag in the pathquery dtd.
448
     */
449
    public Vector getReturnDocList()
450
    {
451
        return this.returnDocList;
452
    }
453

    
454
    /**
455
     * method to set the list of return docs of this query
456
     */
457
    public void setReturnDocList(Vector returnDocList)
458
    {
459
        this.returnDocList = returnDocList;
460
    }
461

    
462
    /**
463
     * Accessor method to return a vector of the filter doc types as defined in
464
     * the &lt;filterdoctype&gt; tag in the pathquery dtd.
465
     */
466
    public Vector getFilterDocList()
467
    {
468
        return this.filterDocList;
469
    }
470

    
471
    /**
472
     * method to set the list of filter docs of this query
473
     */
474
    public void setFilterDocList(Vector filterDocList)
475
    {
476
        this.filterDocList = filterDocList;
477
    }
478

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

    
488
    /**
489
     * method to set the list of fields to be returned by this query
490
     */
491
    public void setReturnFieldList(Vector returnFieldList)
492
    {
493
        this.returnFieldList = returnFieldList;
494
    }
495

    
496
    /**
497
     * Accessor method to return a vector of the owner fields as defined in the
498
     * &lt;owner&gt; tag in the pathquery dtd.
499
     */
500
    public Vector getOwnerList()
501
    {
502
        return this.ownerList;
503
    }
504

    
505
    /**
506
     * method to set the list of owners used to constrain this query
507
     */
508
    public void setOwnerList(Vector ownerList)
509
    {
510
        this.ownerList = ownerList;
511
    }
512

    
513
    /**
514
     * Accessor method to return a vector of the site fields as defined in the
515
     * &lt;site&gt; tag in the pathquery dtd.
516
     */
517
    public Vector getSiteList()
518
    {
519
        return this.siteList;
520
    }
521

    
522
    /**
523
     * method to set the list of sites used to constrain this query
524
     */
525
    public void setSiteList(Vector siteList)
526
    {
527
        this.siteList = siteList;
528
    }
529

    
530
    /**
531
     * get the QueryGroup used to express query constraints
532
     */
533
    public QueryGroup getQueryGroup()
534
    {
535
        return query;
536
    }
537

    
538
    /**
539
     * set the querygroup
540
     */
541
    public void setQueryGroup(QueryGroup group)
542
    {
543
        query = group;
544
    }
545

    
546
    /**
547
     * set if this query sepcification has extendQuery(has return doc type or
548
     * not)
549
     */
550
    public void setContainsExtenedSQL(boolean hasExtenedQuery)
551
    {
552
        containsExtendedSQL = hasExtenedQuery;
553
    }
554

    
555
    /**
556
     * Set up the SAX parser for reading the XML serialized query
557
     */
558
    private XMLReader initializeParser()
559
    {
560
        XMLReader parser = null;
561

    
562
        // Set up the SAX document handlers for parsing
563
        try {
564

    
565
            // Get an instance of the parser
566
            parser = XMLReaderFactory.createXMLReader(parserName);
567

    
568
            // Set the ContentHandler to this instance
569
            parser.setContentHandler(this);
570

    
571
            // Set the error Handler to this instance
572
            parser.setErrorHandler(this);
573

    
574
        } catch (Exception e) {
575
            System.err.println("Error in QuerySpcecification.initializeParser "
576
                    + e.toString());
577
        }
578

    
579
        return parser;
580
    }
581

    
582
    /**
583
     * callback method used by the SAX Parser when the start tag of an element
584
     * is detected. Used in this context to parse and store the query
585
     * information in class variables.
586
     */
587
    public void startElement(String uri, String localName, String qName,
588
            Attributes atts) throws SAXException
589
    {
590
        BasicNode currentNode = new BasicNode(localName);
591
        // add attributes to BasicNode here
592
        if (atts != null) {
593
            int len = atts.getLength();
594
            for (int i = 0; i < len; i++) {
595
                currentNode
596
                        .setAttribute(atts.getLocalName(i), atts.getValue(i));
597
            }
598
        }
599

    
600
        elementStack.push(currentNode);
601
        if (currentNode.getTagName().equals("querygroup")) {
602
            QueryGroup currentGroup = new QueryGroup(currentNode
603
                    .getAttribute("operator"));
604
            if (query == null) {
605
                query = currentGroup;
606
            } else {
607
                QueryGroup parentGroup = (QueryGroup) queryStack.peek();
608
                parentGroup.addChild(currentGroup);
609
            }
610
            queryStack.push(currentGroup);
611
        }
612
    }
613

    
614
    /**
615
     * callback method used by the SAX Parser when the end tag of an element is
616
     * detected. Used in this context to parse and store the query information
617
     * in class variables.
618
     */
619
    public void endElement(String uri, String localName, String qName)
620
            throws SAXException
621
    {
622
        BasicNode leaving = (BasicNode) elementStack.pop();
623
        if (leaving.getTagName().equals("queryterm")) {
624
            boolean isCaseSensitive = (new Boolean(leaving
625
                    .getAttribute("casesensitive"))).booleanValue();
626
            QueryTerm currentTerm = null;
627
            if (currentPathexpr == null) {
628
                currentTerm = new QueryTerm(isCaseSensitive, leaving
629
                        .getAttribute("searchmode"), currentValue);
630
            } else {
631
                currentTerm = new QueryTerm(isCaseSensitive, leaving
632
                        .getAttribute("searchmode"), currentValue,
633
                        currentPathexpr);
634
            }
635
            QueryGroup currentGroup = (QueryGroup) queryStack.peek();
636
            currentGroup.addChild(currentTerm);
637
            currentValue = null;
638
            currentPathexpr = null;
639
        } else if (leaving.getTagName().equals("querygroup")) {
640
            QueryGroup leavingGroup = (QueryGroup) queryStack.pop();
641
        }
642
    }
643

    
644
    /**
645
     * callback method used by the SAX Parser when the text sequences of an xml
646
     * stream are detected. Used in this context to parse and store the query
647
     * information in class variables.
648
     */
649
    public void characters(char ch[], int start, int length)
650
    {
651

    
652
        String inputString = new String(ch, start, length);
653
        BasicNode currentNode = (BasicNode) elementStack.peek();
654
        String currentTag = currentNode.getTagName();
655
        if (currentTag.equals("meta_file_id")) {
656
            meta_file_id = inputString;
657
        } else if (currentTag.equals("querytitle")) {
658
            queryTitle = inputString;
659
        } else if (currentTag.equals("value")) {
660
            currentValue = inputString;
661
        } else if (currentTag.equals("pathexpr")) {
662
            currentPathexpr = inputString;
663
        } else if (currentTag.equals("returndoctype")) {
664
            returnDocList.add(inputString);
665
        } else if (currentTag.equals("filterdoctype")) {
666
            filterDocList.add(inputString);
667
        } else if (currentTag.equals("returnfield")) {
668
            handleReturnField(inputString);
669
        } else if (currentTag.equals("filterdoctype")) {
670
            filterDocList.add(inputString);
671
        } else if (currentTag.equals("owner")) {
672
            ownerList.add(inputString);
673
        } else if (currentTag.equals("site")) {
674
            siteList.add(inputString);
675
        }
676
    }
677

    
678
    /**
679
     * Method to transfer string to return field
680
     */
681
    public void handleReturnField(String inputString)
682
    {
683
        // make sure if return fields has an attribute or not
684
        if (inputString.indexOf(ATTRIBUTESYMBOL) == -1) {
685
            // no attribute value will be returned
686
            returnFieldList.add(inputString);
687
            containsExtendedSQL = true;
688
        } else {
689
            // has a attribute return field
690
            // divied the return filed into two parts, one is path and the
691
            // other is attribue name
692
            String returnPath = newPathExpressionWithOutAttribute(inputString);
693
            String attributeName = getAttributeName(inputString);
694
            Vector pathInfo = new Vector();
695
            // the vector has the information about return path and
696
            // attributename
697
            pathInfo.addElement(returnPath);
698
            pathInfo.addElement(attributeName);
699
            // put the vector into a hash table. The reseaon why don't put
700
            // return path or attributename as a key is because they are not
701
            // unique
702
            attributeReturnList.put(new Integer(countAttributeReturnField),
703
                    pathInfo);
704
            countAttributeReturnField++;
705
            hasAttributeReturnField = true;
706
            containsExtendedSQL = true;
707

    
708
        }
709
    }
710

    
711
    /**
712
     * create a SQL serialization of the query that this instance represents
713
     */
714
    public String printSQL(boolean useXMLIndex)
715
    {
716

    
717
        StringBuffer self = new StringBuffer();
718

    
719
        self.append("SELECT docid,docname,doctype,");
720
        self.append("date_created, date_updated, rev ");
721
        self.append("FROM xml_documents WHERE docid IN (");
722

    
723
        // This determines the documents that meet the query conditions
724
        self.append(query.printSQL(useXMLIndex));
725

    
726
        self.append(") ");
727

    
728
        // Add SQL to filter for doctypes requested in the query
729
        // This is an implicit OR for the list of doctypes. Only doctypes in
730
        // this
731
        // list will be searched if the tag is present
732
        if (!filterDocList.isEmpty()) {
733
            boolean firstdoctype = true;
734
            self.append(" AND (");
735
            Enumeration en = filterDocList.elements();
736
            while (en.hasMoreElements()) {
737
                String currentDoctype = (String) en.nextElement();
738
                if (firstdoctype) {
739
                    firstdoctype = false;
740
                    self.append(" doctype = '" + currentDoctype + "'");
741
                } else {
742
                    self.append(" OR doctype = '" + currentDoctype + "'");
743
                }
744
            }
745
            self.append(") ");
746
        }
747

    
748
        // Add SQL to filter for owners requested in the query
749
        // This is an implicit OR for the list of owners
750
        if (!ownerList.isEmpty()) {
751
            boolean first = true;
752
            self.append(" AND (");
753
            Enumeration en = ownerList.elements();
754
            while (en.hasMoreElements()) {
755
                String current = (String) en.nextElement();
756
                if (current != null) {
757
                    current = current.toLowerCase();
758
                }
759
                if (first) {
760
                    first = false;
761
                    self.append(" lower(user_owner) = '" + current + "'");
762
                } else {
763
                    self.append(" OR lower(user_owner) = '" + current + "'");
764
                }
765
            }
766
            self.append(") ");
767
        }
768

    
769
        // Add SQL to filter for sites requested in the query
770
        // This is an implicit OR for the list of sites
771
        if (!siteList.isEmpty()) {
772
            boolean first = true;
773
            self.append(" AND (");
774
            Enumeration en = siteList.elements();
775
            while (en.hasMoreElements()) {
776
                String current = (String) en.nextElement();
777
                if (first) {
778
                    first = false;
779
                    self.append(" SUBSTR(docid, 1, INSTR(docid, '"
780
                            + accNumberSeparator + "')-1) = '" + current + "'");
781
                } else {
782
                    self.append(" OR SUBSTR(docid, 1, INSTR(docid, '"
783
                            + accNumberSeparator + "')-1) = '" + current + "'");
784
                }
785
            }
786
            self.append(") ");
787
        }
788

    
789
        // if there is only one percentage search item, this query is a
790
        // percentage
791
        // search query
792
        MetaCatUtil.debugMessage("percentage number: "
793
                + query.getPercentageSymbolCount(), 35);
794
        if (query.getPercentageSymbolCount() == 1) {
795
            MetaCatUtil.debugMessage("it is a percentage search", 30);
796
            percentageSearch = true;
797
        }
798

    
799
        return self.toString();
800
    }
801

    
802
    /**
803
     * This sql command will selecet startnodeid and endnodeid that user can
804
     * NOT access
805
     */
806
    public String printAccessControlSQLForReturnField(String doclist)
807
    {
808
        StringBuffer sql = new StringBuffer();
809
        String allowString = constructAllowString();
810
        String denyString = constructDenyString();
811
        sql.append("SELECT distinct startnodeid, endnodeid from xml_access ");
812
        sql.append("WHERE docid in (");
813
        sql.append(doclist);
814
        sql.append(") AND startnodeid IS NOT NULL AND ");
815
        sql.append("(");
816
        sql.append("(");
817
        sql.append("startnodeid NOT IN (SELECT startnodeid from xml_access, xml_documents ");
818
        sql.append(" WHERE xml_access.docid = xml_documents.docid");
819
        sql.append(" AND lower(xml_documents.user_owner) ='");
820
        sql.append(userName);
821
        sql.append("' AND xml_access.startnodeid IS NOT NULL)");
822
        sql.append(")");
823
        sql.append(" AND ");
824
        sql.append("(");
825
        sql.append("(startnodeid NOT IN (SELECT startnodeid from xml_access where( ");
826
        sql.append(allowString);
827
        sql.append(") AND (startnodeid IS NOT NULL))");
828
        sql.append(")");
829
        sql.append(" OR (startnodeid IN (SELECT startnodeid from xml_access where( ");
830
        sql.append(denyString);
831
        sql.append(") AND (startnodeid IS NOT NULL))");
832
        sql.append(")");
833
        sql.append(")");
834
        sql.append(")");
835
        MetaCatUtil.debugMessage("accessControlSQLForReturnField: "
836
                + sql.toString(), 30);
837
        return sql.toString();
838
    }
839

    
840
    /**
841
     * This method prints sql based upon the &lt;returnfield&gt; tag in the
842
     * pathquery document. This allows for customization of the returned fields
843
     * 
844
     * @param doclist
845
     *            the list of document ids to search by
846
     * @param unaccessableNodePair
847
     *            the node pair(start id and end id) which this user could not
848
     *            access it
849
     */
850
    public String printExtendedSQL(String doclist,
851
            Hashtable unaccessableNodePair)
852
    {
853
        StringBuffer self = new StringBuffer();
854
        self
855
                .append("select xml_nodes.docid, xml_index.path, xml_nodes.nodedata, ");
856
        self.append("xml_nodes.parentnodeid ");
857
        self.append("from xml_index, xml_nodes where xml_index.nodeid=");
858
        self.append("xml_nodes.parentnodeid and (xml_index.path like '");
859
        boolean firstfield = true;
860
        //put the returnfields into the query
861
        //the for loop allows for multiple fields
862
        for (int i = 0; i < returnFieldList.size(); i++) {
863
            if (firstfield) {
864
                firstfield = false;
865
                self.append((String) returnFieldList.elementAt(i));
866
                self.append("' ");
867
            } else {
868
                self.append("or xml_index.path like '");
869
                self.append((String) returnFieldList.elementAt(i));
870
                self.append("' ");
871
            }
872
        }
873
        self.append(") AND xml_nodes.docid in (");
874
        //self.append(query.printSQL());
875
        self.append(doclist);
876
        self.append(")");
877
        self.append(" AND xml_nodes.nodetype = 'TEXT'");
878

    
879
        // add control part for extended query
880
        Enumeration en = unaccessableNodePair.keys();
881

    
882
        while (en.hasMoreElements()) {
883
            // Get control pairs in object
884
            Long startNodeIdObject = (Long) en.nextElement();
885
            Long endNodeIdObject = (Long) unaccessableNodePair
886
                    .get(startNodeIdObject);
887
            // change it to long
888
            long startNodeId = startNodeIdObject.longValue();
889
            long endNodeId = endNodeIdObject.longValue();
890
            // add into query
891
            self.append(" AND( xml_nodes.nodeid < ");
892
            self.append(startNodeId);
893
            self.append(" OR xml_nodes.nodeid > ");
894
            self.append(endNodeId);
895
            self.append(")");
896
        }
897

    
898
        return self.toString();
899
    }
900

    
901
    /**
902
     * This method prints sql based upon the returnfield tag in the pathquery
903
     * document has an attribute. This allows for customization of the returned
904
     * fields
905
     * 
906
     * @param doclist
907
     *            the list of document ids to search by
908
     */
909
    public String printAttributeQuery(String doclist)
910
    {
911
        StringBuffer self = new StringBuffer();
912
        self.append("select xml_nodes.docid, xml_index.path, ");
913
        self.append("xml_nodes.nodedata, xml_nodes.nodename ");
914
        self.append("from xml_index, xml_nodes where xml_index.nodeid=");
915
        self.append("xml_nodes.parentnodeid and (");
916
        boolean firstfield = true;
917
        //put the returnfields attributes into the query
918
        //the for loop allows for multiple fields and attributes
919
        Enumeration returnAttributes = attributeReturnList.elements();
920
        while (returnAttributes.hasMoreElements()) {
921
            Vector currentVector = (Vector) returnAttributes.nextElement();
922
            String returnPath = (String) currentVector.elementAt(0);
923
            String attributeName = (String) currentVector.elementAt(1);
924
            if (firstfield) {
925
                firstfield = false;
926
                self.append("( xml_index.path like '");
927
                self.append(returnPath);
928
                self.append("' AND xml_nodes.nodename like '");
929
                self.append(attributeName);
930
                self.append("') ");
931
            } else {
932
                self.append(" or ( xml_index.path like '");
933
                self.append(returnPath);
934
                self.append("' AND xml_nodes.nodename like '");
935
                self.append(attributeName);
936
                self.append("') ");
937
            }
938
        }
939
        self.append(") AND xml_nodes.docid in (");
940
        //self.append(query.printSQL());
941
        self.append(doclist);
942
        self.append(")");
943
        self.append(" AND xml_nodes.nodetype = 'ATTRIBUTE'");
944
        MetaCatUtil.debugMessage("Attribute query: " + self.toString(), 30);
945

    
946
        return self.toString();
947
    }
948

    
949
    public static String printRelationSQL(String docid)
950
    {
951
        StringBuffer self = new StringBuffer();
952
        self.append("select subject, relationship, object, subdoctype, ");
953
        self.append("objdoctype from xml_relation ");
954
        self.append("where docid like '").append(docid).append("'");
955
        return self.toString();
956
    }
957

    
958
    public static String printGetDocByDoctypeSQL(String docid)
959
    {
960
        StringBuffer self = new StringBuffer();
961

    
962
        self.append("SELECT docid,docname,doctype,");
963
        self.append("date_created, date_updated ");
964
        self.append("FROM xml_documents WHERE docid IN (");
965
        self.append(docid).append(")");
966
        return self.toString();
967
    }
968

    
969
    /**
970
     * create a String description of the query that this instance represents.
971
     * This should become a way to get the XML serialization of the query.
972
     */
973
    public String toString()
974
    {
975
        return "meta_file_id=" + meta_file_id + "\n" + query;
976
        //DOCTITLE attr cleared from the db
977
        //return "meta_file_id=" + meta_file_id + "\n" +
978
        //"querytitle=" + querytitle + "\n" + query;
979
    }
980

    
981
    /* A method to get rid of attribute part in path expression */
982
    public static String newPathExpressionWithOutAttribute(String pathExpression)
983
    {
984
        if (pathExpression == null) { return null; }
985
        int index = pathExpression.lastIndexOf(ATTRIBUTESYMBOL);
986
        String newExpression = null;
987
        if (index != 1) {
988
            newExpression = pathExpression.substring(0, index - 1);
989
        }
990
        MetaCatUtil.debugMessage("The path expression without attributes: "
991
                + newExpression, 30);
992
        return newExpression;
993
    }
994

    
995
    /* A method to get attribute name from path */
996
    public static String getAttributeName(String path)
997
    {
998
        if (path == null) { return null; }
999
        int index = path.lastIndexOf(ATTRIBUTESYMBOL);
1000
        int size = path.length();
1001
        String attributeName = null;
1002
        if (index != 1) {
1003
            attributeName = path.substring(index + 1, size);
1004
        }
1005
        MetaCatUtil.debugMessage("The attirbute name from path: "
1006
                + attributeName, 30);
1007
        return attributeName;
1008
    }
1009

    
1010
}
(48-48/58)