001/*
002 * Copyright (c) 2004-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.ecoinformatics.seek.ecogrid.quicksearch;
031
032import java.util.Hashtable;
033import java.util.List;
034import java.util.Vector;
035
036import org.kepler.configuration.ConfigurationProperty;
037 
038/**
039 * A class to implement a query object that looks like this:
040
041 <query>
042      <queryId>eml210-quick-search-query</queryId> 
043      <system>http://knb.ecoinformatics.org</system>
044      <namespace>
045        <prefix>eml</prefix>
046        <value>eml://ecoinformatics.org/eml-2.1.0</value>
047      </namespace>
048      <returnField>dataset/title</returnField>
049      <returnField>entityName</returnField>
050      <title>eml210-quick-search-query</title>
051      <AND>
052        <OR>
053          <condition>
054            <concept>dataset/title</concept>
055            <operator>LIKE</operator>
056            <value>#value#</value>
057          </condition>
058          <condition>
059            <concept>keyword</concept> 
060            <operator>LIKE</operator>
061            <value>#value#</value>
062          </condition>
063          <condition> 
064            <concept>creator/individualName/surName</concept>
065            <operator>LIKE</operator>
066            <value>#value#</value>
067          </condition>
068          <condition> 
069            <concept>taxonRankValue</concept> 
070            <operator>LIKE</operator>
071            <value>#value#</value>
072          </condition>
073          <condition> 
074            <concept>abstract/para</concept>
075            <operator>LIKE</operator>
076            <value>#value#</value>
077          </condition>
078        </OR>
079        <OR>
080          <condition>
081            <concept>dataset/dataTable/physical/distribution/online/url</concept>
082            <operator>LIKE</operator>
083            <value>http://%</value>
084          </condition>
085          <condition>
086            <concept>dataset/dataTable/physical/distribution/online/url</concept> 
087            <operator>LIKE</operator>
088            <value>ecogrid://%</value>
089          </condition>
090          <condition> 
091            <concept>dataset/spatialRaster/physical/distribution/online/url</concept> 
092            <operator>LIKE</operator>
093            <value>ecogrid://%</value>
094          </condition>
095        </OR>
096        <OR>
097          <condition>
098            <concept>dataset/dataTable/physical/distribution/online/url/@function</concept> 
099            <operator>EQUALS</operator>
100            <value>download</value>
101          </condition>
102          <condition> 
103            <concept>dataset/spatialRaster/physical/distribution/online/url/@function</concept>
104            <operator>EQUALS</operator>
105            <value>download</value>
106          </condition>
107        </OR>
108      </AND>
109    </query>
110
111*/
112public class SearchQuery
113{
114  public String queryId;
115  public String system;
116  public Namespace namespace;
117  public Vector<String> returnField;
118  public String title;
119  public Condition condition;
120  public BooleanLogic andOrConditions;
121  
122  /**
123   * constructor
124   */
125  public SearchQuery(ConfigurationProperty queryProp)
126  {
127    parseProp(queryProp);
128  }
129  
130  /**
131   * replace the values in the conditions with the values in the hash
132   */
133  public void replaceValues(Hashtable valueMap)
134  {
135    if(andOrConditions != null)
136    {
137      andOrConditions.replaceValues(valueMap);
138    }
139    
140    if(condition != null)
141    {
142      condition.replaceValue(valueMap);
143    }
144  }
145  
146  /**
147   * toString
148   */
149  public String toString()
150  {
151    String s = new String();
152    s += "<query queryId=\"" + queryId + "\" system=\"" + system + "\">\n";
153    s += namespace.toString();
154
155    for(int i=0; i<returnField.size(); i++)
156    {
157      String rf = (String)returnField.get(i);
158      s += "<returnField>" + rf + "</returnField>\n";
159    }
160    
161    s += "<title>" + title + "</title>\n";
162    
163    if(condition != null)
164    {
165      s += condition.toString();
166    }
167    if(andOrConditions != null)
168    {
169      s += andOrConditions.toString();
170    }
171    s += "</query>\n";
172    return s;
173  }
174  
175  /**
176   * parse the property 
177   */
178  private void parseProp(ConfigurationProperty queryProp)
179  {
180    //get the basic fields
181    queryId = getValueIfNotNull(queryProp.getProperty("queryId"));
182    system = getValueIfNotNull(queryProp.getProperty("system"));
183    title = getValueIfNotNull(queryProp.getProperty("title"));
184    
185    //get the returnfields
186    List returnfields = queryProp.getProperties("returnField");
187    returnField = new Vector();
188    for(int i=0; i<returnfields.size(); i++)
189    {
190      String returnfield = ((ConfigurationProperty)returnfields.get(i)).getValue();
191      returnField.add(returnfield);
192    }
193    
194    //namespace
195    ConfigurationProperty namespaceProp = queryProp.getProperty("namespace");
196    if(namespaceProp != null)
197    {
198      namespace = new Namespace();
199      namespace.prefix = getValueIfNotNull(namespaceProp.getProperty("prefix"));
200      namespace.value = getValueIfNotNull(namespaceProp.getProperty("value"));
201    }
202    
203    //conditions
204    ConfigurationProperty conditionProp = queryProp.getProperty("condition");
205    if(conditionProp != null)
206    {
207      condition = new Condition(conditionProp);
208    }
209    
210    //AND/OR/Conditions    
211    andOrConditions = parseAndOrProp(queryProp);
212
213  }
214  
215  /**
216   * parse the conditions
217   */
218  private BooleanLogic parseAndOrProp(ConfigurationProperty queryProp)
219  {
220    List l = queryProp.getProperties();
221    BooleanLogic bl = new BooleanLogic();
222    
223    for(int i=0; i<l.size(); i++)
224    {
225      ConfigurationProperty cp = (ConfigurationProperty)l.get(i);
226      if(cp.getName().equals("AND"))
227      {
228        bl.isAnd = true;
229        bl.logic.add(parseAndOrProp(cp));
230      }
231      else if(cp.getName().equals("OR"))
232      {
233        bl.isOr = true;
234        bl.logic.add(parseAndOrProp(cp));
235      }
236      else if(cp.getName().equals("condition"))
237      {
238        bl.addCondition(new Condition(cp));
239      }
240      else
241      {
242        continue;
243      }
244    }
245    return bl;
246  }
247  
248  /**
249   * get the value or null if there isn't one
250   */
251  private String getValueIfNotNull(ConfigurationProperty cp)
252  {
253    if(cp != null)
254    {
255      return cp.getValue();
256    }
257    else
258    {
259      return null;
260    }
261  }
262  
263  /**
264   * class to hold a namespace
265   */
266  private class Namespace
267  {
268    public String prefix;
269    public String value;
270    
271    public Namespace()
272    {
273      
274    }
275    
276    public String toString()
277    {
278      String s = "";
279      s += "<namespace prefix=\"" + prefix + "\">" + value + "</namespace>\n";
280      return s;
281    }
282  }
283  
284  /**
285   * class to hold a condition
286   */
287  private class Condition
288  {
289    public String concept;
290    public String operator;
291    public String value;
292    
293    public Condition(ConfigurationProperty conditionProp)
294    {
295      concept = getValueIfNotNull(conditionProp.getProperty("concept"));
296      operator = getValueIfNotNull(conditionProp.getProperty("operator"));
297      value = getValueIfNotNull(conditionProp.getProperty("value"));
298    }
299    
300    /**
301     * replace the value of this condition with the value in the valueMap
302     */
303    public void replaceValue(Hashtable valueMap)
304    {
305      String v = (String)valueMap.get(value);
306      if(v != null)
307      {
308        value = v;
309      }
310    }
311    
312    public String toString()
313    {
314      String s = "";
315      s += "<condition concept=\"" + concept + "\" operator=\"" + operator + "\">" + value + "</condition>\n";
316      return s;
317    }
318  }
319  
320  /**
321   * class to contain the boolean logic
322   */
323  private class BooleanLogic
324  {
325    public Vector<Condition> conditions;
326    public Vector<BooleanLogic> logic;
327    public boolean isOr = false;
328    public boolean isAnd = false;
329    
330    public BooleanLogic()
331    {
332      logic = new Vector();
333      conditions = new Vector();
334    }
335    
336    public void addCondition(Condition c)
337    {
338      conditions.add(c);
339    }
340    
341    public void addBooleanLogic(BooleanLogic b)
342    {
343      logic.add(b);
344    }
345    
346    public String toString()
347    {
348      return toString(this);
349    }
350    
351    /**
352     * replace the values in the conditions with the values in the valueMap
353     */
354    public void replaceValues(Hashtable valueMap)
355    {
356      replaceValues(valueMap, this);
357    }
358    
359    private void replaceValues(Hashtable valueMap, BooleanLogic bl)
360    {
361      if(bl.conditions != null && bl.conditions.size() > 0)
362      {
363        for(int i=0; i<bl.conditions.size(); i++)
364        {
365          Condition c = (Condition)bl.conditions.get(i);
366          c.replaceValue(valueMap);
367        }
368      }
369      
370      if(bl.logic != null && bl.logic.size() > 0)
371      {
372        for(int i=0; i<bl.logic.size(); i++)
373        {
374          BooleanLogic newbl = (BooleanLogic)bl.logic.get(i);
375          replaceValues(valueMap, newbl);
376        }
377      }
378    }
379    
380    private String toString(BooleanLogic bl)
381    {
382      String s = "";
383      
384      if(bl.conditions != null && bl.conditions.size() > 0)
385      {
386        for(int i=0; i<bl.conditions.size(); i++)
387        {
388          Condition c = (Condition)bl.conditions.get(i);
389          s += c.toString();
390        }
391      }
392      
393      if(bl.logic != null && bl.logic.size() > 0)
394      {
395        for(int i=0; i<bl.logic.size(); i++)
396        {
397          BooleanLogic newbl = (BooleanLogic)bl.logic.get(i);
398          if(bl.isAnd)
399          {
400            s += "<AND>\n";
401            s += toString(newbl);
402            s += "</AND>\n";
403          }
404          else if(bl.isOr)
405          {
406            s += "<OR>\n";
407            s += toString(newbl);
408            s += "</OR>\n";
409          }
410        }
411      }
412      
413      return s;
414    }
415  }
416}