[metacat-cvs] metacat/src/edu/ucsb/nceas/metacat/advancedsearch AdvancedSearch.java AdvancedSearchBean.java AdvancedSearchPathQuery.java AdvancedSearchQueryGroup.java AdvancedSearchQueryTerm.java AdvancedSearchServlet.java BrowseServlet.java LTERSite.java LoginBean.java LoginServlet.java MetacatHelper.java MetacatLogin.java SearchServlet.java Stylizer.java

Duane Costa costa at ecoinformatics.org
Wed Nov 16 09:57:34 PST 2005


costa       05/11/16 09:57:34

  Added:       src/edu/ucsb/nceas/metacat/advancedsearch
                        AdvancedSearch.java AdvancedSearchBean.java
                        AdvancedSearchPathQuery.java
                        AdvancedSearchQueryGroup.java
                        AdvancedSearchQueryTerm.java
                        AdvancedSearchServlet.java BrowseServlet.java
                        LTERSite.java LoginBean.java LoginServlet.java
                        MetacatHelper.java MetacatLogin.java
                        SearchServlet.java Stylizer.java
  Log:
  Bug #2207: Implementation of the Metacat Advanced Search engine.
  
  Revision  Changes    Path
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/AdvancedSearch.java
  
  Index: AdvancedSearch.java
  ===================================================================
  /**
   *  '$RCSfile: AdvancedSearch.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  import java.io.Reader;
  import java.io.StringReader;
  import java.util.ArrayList;
  import java.util.StringTokenizer;
  
  import edu.ucsb.nceas.metacat.client.*;
  import edu.ucsb.nceas.utilities.*;
  
  /**
   * @author dcosta
   * 
   * AdvancedSearch class constructs queries that use the pathquery feature of 
   * Metacat. It can execute either an advanced search, where the user fills in
   * fields in a web form, or a simple search on a string.
   */
  public class AdvancedSearch  {
  
    // Object variables
    private AdvancedSearchBean advancedSearchBean = null;
    private String caseSensitive;
    private final String globalOperator;
    private boolean hasSubjectSearch = false;
    private boolean hasAuthorSearch = false;
    private boolean hasSpatialSearch = false;
    private boolean hasTaxonomicSearch = false;
    private boolean hasTemporalSearch = false;
    private boolean hasSiteFilter = false;
    private int indentLevel = 2;
    private boolean isCaseSensitive = false;
    private AdvancedSearchPathQuery pathQuery;
    private AdvancedSearchQueryGroup queryGroup;
    private String queryString;
    private String site;
    private final String title = "Advanced Search";
  
  
    /**
     * Constructor. Used when the user has filled in an Advanced Search form.
     * The property values are contained in the advancedSearchBean object.
     * For a simple search, the advancedSearchBean object is passed as null.
     * 
     * @param advancedSearchBean   An AdvancedSearch bean.
     */
    public AdvancedSearch(final AdvancedSearchBean advancedSearchBean) {
      int allAny = AdvancedSearchBean.MATCH_ALL;
      String indent = getIndent(indentLevel * 1);
      final String operator;
      
      if (advancedSearchBean != null) {
        allAny = advancedSearchBean.getFormAllAny();
        this.isCaseSensitive = advancedSearchBean.isCaseSensitive();
        site = advancedSearchBean.getSiteValue();
      }
  
      if (allAny == AdvancedSearchBean.MATCH_ALL) {
        globalOperator = "INTERSECT";
      }
      else {
        globalOperator = "UNION";
      }
      
      if (isCaseSensitive == true) {
        this.caseSensitive = "true";
      }
      else {
        this.caseSensitive = "false";
      }
  
      this.queryGroup = new AdvancedSearchQueryGroup(globalOperator, indent);
      this.pathQuery = new AdvancedSearchPathQuery(title, queryGroup, indent);
      this.advancedSearchBean = advancedSearchBean;
    }
    
  
    /**
     * Adds a string to an ArrayList of terms. An auxiliary method to the
     * parseTermsAdvanced() method.
     * 
     * @param terms      ArrayList of strings.
     * @param term       the new string to add to the ArrayList, but only if
     *                   it isn't an empty string.
     */
    private void addTerm(ArrayList terms, final StringBuffer term) {
      final String s = term.toString().trim();
        
      if (s.length() > 0) {
        terms.add(s);
      }
    }
  
  
    /**
     * A full subject query searches the title, abstract, and keyword sections of
     * the document. Individual searches on these sections is also supported.
     */
    private void buildQuerySubject() {
      int allAny = advancedSearchBean.getSubjectAllAny();
      String emlField;
      String indent;
      final String innerOperator = "UNION";
      AdvancedSearchQueryGroup innerQuery = null;
      final String outerOperator;
      AdvancedSearchQueryGroup outerQuery;
      AdvancedSearchQueryTerm qt;
      String searchMode;
      final String subjectField = advancedSearchBean.getSubjectField();
      final int subjectQueryType = advancedSearchBean.getSubjectQueryType();
      String term;
      ArrayList terms;
      String value = advancedSearchBean.getSubjectValue();
   
      if ((value != null) && (!(value.equals("")))) {
        hasSubjectSearch = true;
  
        if (allAny == AdvancedSearchBean.MATCH_ALL) {
          outerOperator = "INTERSECT";
        }
        else {
          outerOperator = "UNION";
        }
  
        indent = getIndent(indentLevel * 2);
        outerQuery = new AdvancedSearchQueryGroup(outerOperator, indent);
        terms = parseTermsAdvanced(value);
        searchMode = metacatSearchMode(subjectQueryType);
        
        for (int i = 0; i < terms.size(); i++) {
          term = (String) terms.get(i);
          indent = getIndent(indentLevel * 3);
          innerQuery = new AdvancedSearchQueryGroup(innerOperator, indent);
          indent = getIndent(indentLevel * 4);
              
          if (subjectField.equals("ALL") || subjectField.equals("TITLE")) {
            emlField = "dataset/title";
            qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                             term, indent);
            innerQuery.addQueryTerm(qt);
          }
  
          if (subjectField.equals("ALL") || subjectField.equals("ABSTRACT")) {
            emlField = "dataset/abstract/para";
            qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                             term, indent);
            innerQuery.addQueryTerm(qt);
  
            emlField = "dataset/abstract/section/para";
            qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                             term, indent);
            innerQuery.addQueryTerm(qt);
          }
  
          if (subjectField.equals("ALL") || subjectField.equals("KEYWORDS")) {
            emlField = "keywordSet/keyword";
            qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                             term, indent);
            innerQuery.addQueryTerm(qt);
          }
        
          outerQuery.addQueryGroup(innerQuery);
        }
  
        // Minimize the number of query groups that get created, depending on
        // which criteria the user specified.
        //
        if (terms.size() > 1) {
          queryGroup.addQueryGroup(outerQuery);
        }
        else if (terms.size() == 1){
          queryGroup.addQueryGroup(innerQuery);
        }
      }
  
    }
    
  
    /**
     * An author query will search the creator/individualName/surName field, the
     * creator/organizationName field, or an intersection of both fields.
     */
    private void buildQueryAuthor() {
      boolean addQueryGroup = false;
      final int creatorSurnameQueryType = 
                                  advancedSearchBean.getCreatorSurnameQueryType();
      final int creatorOrganizationQueryType = 
                             advancedSearchBean.getCreatorOrganizationQueryType();
      String emlField;
      String indent = getIndent(indentLevel * 2);
      AdvancedSearchQueryGroup qg = 
                             new AdvancedSearchQueryGroup(globalOperator, indent);
      AdvancedSearchQueryTerm qt;
      String searchMode;
      String value = advancedSearchBean.getCreatorSurname();
  
      indent = getIndent(indentLevel * 3);
      if ((value != null) && (!(value.equals("")))) {
        emlField = "dataset/creator/individualName/surName";
        searchMode = metacatSearchMode(creatorSurnameQueryType);
        qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                         value, indent);
        qg.addQueryTerm(qt);        
        addQueryGroup = true;
      }
  
      value = advancedSearchBean.getCreatorOrganization();
        
      if ((value != null) && (!(value.equals("")))) {
        emlField = "creator/organizationName";
        searchMode = metacatSearchMode(creatorOrganizationQueryType);
        qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                         value, indent);
        qg.addQueryTerm(qt);        
        addQueryGroup = true;
      }
      
      if (addQueryGroup) {      
        hasAuthorSearch = true;
        queryGroup.addQueryGroup(qg);
      }
    }
    
  
    /**
     * Two kinds of spatial searches are supported. The first is on a specific
     * named location. The second is on north/south/east/west bounding
     * coordinates. An intersection of both searches is done if the user
     * specifies search values for a named location as well as one or more
     * bounding coordinates.
     */
    private void buildQuerySpatialCriteria() {
      boolean addBoundingValues = false;
      boolean addGeographicDescription = false;
      final boolean boundaryContained = advancedSearchBean.isBoundaryContained();
      String emlField;
      final String operator = "INTERSECT";
      String indent = getIndent(indentLevel * 2);
      AdvancedSearchQueryGroup qgBounding;
      AdvancedSearchQueryGroup qgGeographicDescription;
      AdvancedSearchQueryGroup qgSpatial;
      AdvancedSearchQueryTerm qt;
      String searchMode;
      String value, northValue, southValue, eastValue, westValue;
  
      qgSpatial = new AdvancedSearchQueryGroup(globalOperator, indent);
      indent = getIndent(indentLevel * 3);
      qgBounding = new AdvancedSearchQueryGroup(operator, indent);
      qgGeographicDescription = new AdvancedSearchQueryGroup(operator, indent);
      indent = getIndent(indentLevel * 4);
  
      /* Check whether user specified a named location. */
      value = advancedSearchBean.getLocationName();   
  
      if ((value != null) && (!(value.equals("")))) {
        searchMode = "contains";
        emlField = "geographicCoverage/geographicDescription";
        qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                         value, indent);
        qgGeographicDescription.addQueryTerm(qt);
        addGeographicDescription = true;
      }
  
      /*
       * If the user selects the boundaryContained checkbox, use the following
       * logical expression. N, S, E, and W are the boundaries of the bounding
       * box, while N', S', E', and W' are the boundaries specified in a given
       * EML document:
       *              (N' <= N) && (S' >= S) && (E' <= E) && (W' >= W)
       */
      if (boundaryContained) {
        northValue = advancedSearchBean.getNorthBound();
        if ((northValue != null) && (!(northValue.equals("")))) {
          emlField = 
                 "geographicCoverage/boundingCoordinates/northBoundingCoordinate";
          searchMode = "less-than-equals";
          qt=new AdvancedSearchQueryTerm(searchMode,caseSensitive,emlField, 
                                         northValue, indent);
          qgBounding.addQueryTerm(qt);        
          addBoundingValues = true;
        }
  
        southValue = advancedSearchBean.getSouthBound();
        if ((southValue != null) && (!(southValue.equals("")))) {
          emlField = 
                 "geographicCoverage/boundingCoordinates/southBoundingCoordinate";
          searchMode = "greater-than-equals";
          qt=new AdvancedSearchQueryTerm(searchMode,caseSensitive,emlField, 
                                         southValue, indent);
          qgBounding.addQueryTerm(qt);        
          addBoundingValues = true;
        }
  
        eastValue = advancedSearchBean.getEastBound();
        if ((eastValue != null) && (!(eastValue.equals("")))) {
          emlField =
                  "geographicCoverage/boundingCoordinates/eastBoundingCoordinate";
          searchMode = "less-than-equals";
          qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                           eastValue, indent);
          qgBounding.addQueryTerm(qt);        
          addBoundingValues = true;
        }
  
        westValue = advancedSearchBean.getWestBound();
        if ((westValue != null) && (!(westValue.equals("")))) {
          emlField =
                  "geographicCoverage/boundingCoordinates/westBoundingCoordinate";
          searchMode = "greater-than-equals";
          qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                           westValue, indent);
          qgBounding.addQueryTerm(qt);        
          addBoundingValues = true;
        }
      }
     /*
      * Else, if the user does not select the boundaryContained checkbox, use the 
      * following logical expression. N, S, E, and W are the boundaries of the 
      * bounding box, while N', S', E', and W' are the boundaries specified in a 
      * given EML document:
      *              (N' > S) && (S' < N) && (E' > W) && (W' < E)
      */
      else {     
        northValue = advancedSearchBean.getNorthBound();
        if ((northValue != null) && (!(northValue.equals("")))) {
          emlField =
                 "geographicCoverage/boundingCoordinates/southBoundingCoordinate";
          searchMode = "less-than";
          qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                           northValue, indent);
          qgBounding.addQueryTerm(qt);        
          addBoundingValues = true;
        }
  
        southValue = advancedSearchBean.getSouthBound();
        if ((southValue != null) && (!(southValue.equals("")))) {
          emlField = 
                 "geographicCoverage/boundingCoordinates/northBoundingCoordinate";
          searchMode = "greater-than";
          qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                           southValue, indent);
          qgBounding.addQueryTerm(qt);        
          addBoundingValues = true;
        }
  
        eastValue = advancedSearchBean.getEastBound();
        if ((eastValue != null) && (!(eastValue.equals("")))) {
          emlField =
                  "geographicCoverage/boundingCoordinates/westBoundingCoordinate";
          searchMode = "less-than";
          qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                           eastValue, indent);
          qgBounding.addQueryTerm(qt);        
          addBoundingValues = true;
        }
  
        westValue = advancedSearchBean.getWestBound();
        if ((westValue != null) && (!(westValue.equals("")))) {
          emlField =
                  "geographicCoverage/boundingCoordinates/eastBoundingCoordinate";
          searchMode = "greater-than";
          qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                           westValue, indent);
          qgBounding.addQueryTerm(qt);        
          addBoundingValues = true;
        }
      }
  
      // Minimize the number of query groups that get created, depending on
      // which criteria the user specified.
      //
      if (addBoundingValues || addGeographicDescription) {      
        hasSpatialSearch = true;
        
        if (addBoundingValues && addGeographicDescription) { 
          qgSpatial.addQueryGroup(qgBounding);
          qgSpatial.addQueryGroup(qgGeographicDescription);
          queryGroup.addQueryGroup(qgSpatial);
        }    
        else if (addBoundingValues) {
          queryGroup.addQueryGroup(qgBounding);
        }
        else {
          queryGroup.addQueryGroup(qgGeographicDescription);
        }
      }
      
    }
    
  
    /**
     * Two kinds of temporal searches are supported. The first is on a named
     * time scale. The second is on a specific start date and/or end date.
     */
    private void buildQueryTemporalCriteria() {
      boolean addQueryGroup = false;
      boolean addQueryGroupDates = false;
      boolean addQueryGroupNamed = false;
      final String dateField = advancedSearchBean.getDateField();
      String emlField;
      final String operator = "INTERSECT";
      String indent = getIndent(indentLevel * 2);
      final int namedTimescaleQueryType = 
                                  advancedSearchBean.getNamedTimescaleQueryType();
      AdvancedSearchQueryGroup qg= new AdvancedSearchQueryGroup(operator, indent);
      AdvancedSearchQueryGroup qgNamed, qgDates, qgDatesStart, qgDatesEnd;
      AdvancedSearchQueryTerm qt;
      String searchMode;
      final String namedTimescale, startDate, endDate;
  
      indent = getIndent(indentLevel * 3);
      namedTimescale = advancedSearchBean.getNamedTimescale();
      startDate = advancedSearchBean.getStartDate();
      endDate = advancedSearchBean.getEndDate();
  
      /* If the user specified a named timescale, check to see whether it occurs
       * in any of three possible places: singleDateTime, beginDate, or endDate.
       */
      qgNamed = new AdvancedSearchQueryGroup("UNION", indent);
      if ((namedTimescale != null) && (!(namedTimescale.equals("")))) {
        indent = getIndent(indentLevel * 4);
        searchMode = metacatSearchMode(namedTimescaleQueryType);
        
        emlField = 
             "temporalCoverage/singleDateTime/alternativeTimeScale/timeScaleName";
        qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                         namedTimescale, indent);
        qgNamed.addQueryTerm(qt);
        
        emlField = 
     "temporalCoverage/rangeOfDates/beginDate/alternativeTimeScale/timeScaleName";
        qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                         namedTimescale, indent);
        qgNamed.addQueryTerm(qt);
        
        emlField = 
       "temporalCoverage/rangeOfDates/endDate/alternativeTimeScale/timeScaleName";
        qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                         namedTimescale, indent);
        qgNamed.addQueryTerm(qt);
        
        addQueryGroupNamed = true;
      }
      
      qgDates = new AdvancedSearchQueryGroup("INTERSECT", indent);
  
      // If a start date was specified, search for temporal coverage and/or a
      // pubDate greater than or equal to the start date.
      //
      if ((startDate != null) && (!(startDate.equals("")))) {
        indent = getIndent(indentLevel * 4);
        qgDatesStart = new AdvancedSearchQueryGroup("UNION", indent);
        indent = getIndent(indentLevel * 5);
        searchMode = "greater-than-equals";
  
        if (dateField.equals("ALL") || dateField.equals("COLLECTION")) {
          emlField = "temporalCoverage/rangeOfDates/beginDate/calendarDate";
          qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                           startDate, indent);
          qgDatesStart.addQueryTerm(qt);        
  
          emlField = "temporalCoverage/singleDateTime/calendarDate";
          qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                           startDate, indent);
          qgDatesStart.addQueryTerm(qt);
        }
        
        if (dateField.equals("ALL") || dateField.equals("PUBLICATION")) {
          emlField = "dataset/pubDate";
          qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                           startDate, indent);
          qgDatesStart.addQueryTerm(qt);        
        }
        
        qgDates.addQueryGroup(qgDatesStart);
        addQueryGroupDates = true;
      }
  
      // If an end date was specified, search for temporal coverage and/or a
      // pubDate less than or equal to the end date.
      //
      if ((endDate != null) && (!(endDate.equals("")))) {
        indent = getIndent(indentLevel * 4);
        qgDatesEnd = new AdvancedSearchQueryGroup("UNION", indent);
        indent = getIndent(indentLevel * 5);
        searchMode = "less-than-equals";
  
        if (dateField.equals("ALL") || dateField.equals("COLLECTION")) {
          emlField = "temporalCoverage/rangeOfDates/endDate/calendarDate";
          qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                           endDate, indent);
          qgDatesEnd.addQueryTerm(qt);        
  
          emlField = "temporalCoverage/singleDateTime/calendarDate";
          qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                           endDate, indent);
          qgDatesEnd.addQueryTerm(qt);
        }
        
        if (dateField.equals("ALL") || dateField.equals("PUBLICATION")) {
          emlField = "dataset/pubDate";
          qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                           endDate, indent);
          qgDatesEnd.addQueryTerm(qt);        
        }      
  
        qgDates.addQueryGroup(qgDatesEnd);
        addQueryGroupDates = true;
      }
      
      if (addQueryGroupNamed) {
        qg.addQueryGroup(qgNamed);
        addQueryGroup = true;
      }
      
      if (addQueryGroupDates) {
        qg.addQueryGroup(qgDates);
        addQueryGroup = true;
      }
      
      if (addQueryGroup) {
        hasTemporalSearch = true;
        queryGroup.addQueryGroup(qg);
      }
  
    }
  
  
    /**
     * A taxon query searches the taxonomicClassification/taxonRankValue field,
     * matching the field if the user-specified value is contained in the field.
     */
    private void buildQueryTaxon() {
      boolean addQueryGroup = false;
      final String emlField;
      String indent = getIndent(indentLevel * 2);
      final String operator = "INTERSECT";
      AdvancedSearchQueryGroup qg= new AdvancedSearchQueryGroup(operator, indent);
      AdvancedSearchQueryTerm qt;
      final String searchMode;
      int taxonQueryType = advancedSearchBean.getTaxonQueryType();
      final String value = advancedSearchBean.getTaxon();
        
      indent = getIndent(indentLevel * 3);
  
      if ((value != null) && (!(value.equals("")))) {
        emlField = "taxonomicClassification/taxonRankValue";
        searchMode = metacatSearchMode(taxonQueryType);
        qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                         value, indent);
        qg.addQueryTerm(qt);        
        addQueryGroup = true;
      }
  
      if (addQueryGroup) {      
        hasTaxonomicSearch = true;
        queryGroup.addQueryGroup(qg);
      }
    }
    
  
    /**
     * Build a site filter. If the AdvancedSearch's site value is non-null, add a
     * query group that limits the results to a particular LTER site. Do this
     * by searching for a packageId attribute that starts with "knb-lter-xyz"
     * where "xyz" is the three-letter site acronym, or for a site keyword
     * phrase (e.g. "Kellogg Biological Station") anywhere in the documment.
     */
    private void buildSiteFilter() {
      String attributeValue = "";
      String emlField = "";
      String indent = getIndent(indentLevel * 2);
      final LTERSite lterSite = new LTERSite(site);
      final String operator = "UNION";
      AdvancedSearchQueryGroup qg= new AdvancedSearchQueryGroup(operator, indent);
      AdvancedSearchQueryTerm qt;
      String searchMode;
      final String siteKeyword;
     
      if (lterSite.isValidSite()) {
        hasSiteFilter = true;
        indent = getIndent(indentLevel * 3);
        
        // Handle some LTER sites with irregular naming conventions in their EML
        // For CAP and CWT, we need to search on the system attribute rather than
        // the packageId attribute
        //
        if (site.equals("CAP") || site.equals("CWT")) {
          emlField = "/eml/@system";
          attributeValue = lterSite.getSystem();
        }
        else {
          // For other LTER sites, search the packageId
          emlField = "/eml/@packageId";
          attributeValue = lterSite.getPackageId();
        }
        
        searchMode = "starts-with";
        qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                         attributeValue, indent);
        qg.addQueryTerm(qt);        
  
        // Search for site keyword phrase
        siteKeyword = lterSite.getSiteKeyword();
        emlField = "";
        searchMode = "contains";
        qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                         siteKeyword, indent);
        qg.addQueryTerm(qt);    
        
        queryGroup.addQueryGroup(qg); 
      }
    }
  
  
    /**
     * Counts the number of search types on the form. For example, if the user
     * has filled in values for both a subject search and a spatial search,
     * would return 2.
     * 
     * @return  searchTypes  An integer representing the total number of searches
     *                       that the user has filled in for this advanced search.
     */
    private int countSearchTypes () {
      int searchTypes = 0;
      
      if (hasSubjectSearch == true)   { searchTypes++; }
      if (hasAuthorSearch == true)    { searchTypes++; }
      if (hasSpatialSearch == true)   { searchTypes++; }
      if (hasTaxonomicSearch == true) { searchTypes++; }
      if (hasTemporalSearch == true)  { searchTypes++; }
      if (hasSiteFilter == true)      { searchTypes++; }
      
      return searchTypes;
    }
    
  
    /**
     * Builds and runs an advanced search, returning HTML result string.
     * 
     * @param metacatURL  URL to the metacat servlet
     * @param metacat     A metacat client object, possible null.
     * @param xslPath     File path to the resultset.xsl stylesheet.
     * @return htmlString HTML string representation of the search results.
     */
    public String executeAdvancedSearch(final String metacatURL,
                                        final Metacat metacat,
                                        final String xslPath) {
      String htmlString = "";
      int searchTypes;
  
      buildQuerySubject();
      buildQueryAuthor();
      buildQueryTaxon();
      buildQuerySpatialCriteria();
      buildQueryTemporalCriteria();
      buildSiteFilter();
  
      // Count the number of search types the user has entered.
      searchTypes = countSearchTypes();
  
      // If the user has entered values for only one type of search criteria,
      // then optimize the search by setting the QueryGroup object's
      // includeOuterQueryGroup to false. This will strip off the outer query
      // group and result in a more simplified SQL statement.
      //
      if (searchTypes == 1) {
        queryGroup.setIncludeOuterQueryGroup(false);
      }
      
      queryString = pathQuery.toString();
      htmlString = this.runQuery(metacatURL, metacat, xslPath);
      return htmlString;
    }
    
  
    /**
     * Builds and runs a simple search, returning HTML result string.
     * For a simple search, the AdvancedSearchBean object can be null because
     * all we need is a string value to search on.
     * 
     * @param metacatURL  URL to the metacat servlet
     * @param metacat     A metacat client object, possible null.
     * @param xslPath     File path to the resultset.xsl stylesheet.
     * @param value       String value to search on.
     * 
     * @return htmlString HTML string representation of the search results.
     */
    public String executeSearch(final String metacatURL,
                                final Metacat metacat,
                                final String xslPath,
                                String value) {
      String emlField = "";
      String htmlString = "";
      String indent = getIndent(indentLevel * 2);
      String operator = "UNION";
      AdvancedSearchQueryTerm qt;
      String searchMode = "contains";
      
      indent = getIndent(indentLevel * 3);
  
      /* Check whether user specified an empty search string. 
       */
      if ((value == null) || (value.equals(""))) {
          value = "%";
      }
  
      qt = new AdvancedSearchQueryTerm(searchMode, caseSensitive, emlField, 
                                       value, indent);
      queryGroup.addQueryTerm(qt);
      queryString = pathQuery.toString();
      htmlString = this.runQuery(metacatURL, metacat, xslPath);
      return htmlString;
    }
    
  
    /**
     * Returns a string of spaces that corresponds to the current indent level.
     * 
     * @param indentLevel   The number of spaces to be indented.
     * @return              A string containing indentLevel number of spaces.
     */
    private String getIndent(final int indentLevel) {
      StringBuffer indent = new StringBuffer(12);
      
      for (int i = 0; i < indentLevel; i++) {
        indent.append(" ");
      }
      
      return indent.toString();
    }
    
  
    /**
     * Given a AdvancedSearchBean query type, return the corresponding Metacat
     * searchmode string.
     * 
     * @param queryType       An int indicating the query type as specified in
     *                        the AdvancedSearchBean class.
     * @return searchmode     A string, the Metacat search mode value.
     */ 
    private String metacatSearchMode(final int queryType) {
      final String searchMode;
      
      switch (queryType) {
        case AdvancedSearchBean.CONTAINS:
          searchMode = "contains";
          break;
        case AdvancedSearchBean.EXACT_MATCH:
          searchMode = "equals";
          break;
        case AdvancedSearchBean.STARTS_WITH:
          searchMode = "starts-with";
          break;
        case AdvancedSearchBean.ENDS_WITH:
          searchMode = "ends-with";
          break;
        default:
          searchMode = "contains";
          break;
      }
      
      return searchMode;
    }
    
  
    /**
     * Parses search terms from a string. In this simple implementation, the 
     * string is considered to be a list of tokens separated by spaces. The more 
     * advanced implementation (parserTermsAdvanced) parses quoted strings 
     * containing spaces as a term. This method can be eliminated if we are
     * satisfied that parseTermsAdvanced() is working properly.
     * 
     * @param  value    The string value as entered by the user.
     * 
     * @return terms    An ArrayList of String objects. Each space-separated 
     *                  token is a single term.
     */
    private ArrayList parseTerms(final String value) {
      StringTokenizer st;
      ArrayList terms = new ArrayList();
      String token;
      final int tokenCount;
      
      st = new StringTokenizer(value, " ");
      tokenCount = st.countTokens();
      
      for (int i = 0; i < tokenCount; i++) {
        token = st.nextToken();
        terms.add(token);
      }
      
      return terms;
    }
  
    
    /**
     * Parses search terms from a string. In this advanced implementation,
     * double-quoted strings that contain spaces are considered a single term.
     * 
     * @param  value     The string value as entered by the user.
     * 
     * @return terms    An ArrayList of String objects. Each string is a term.
     */
    private ArrayList parseTermsAdvanced(String value) {
      char c;
      StringBuffer currentTerm = new StringBuffer(100);
      boolean keepSpaces = false;
      StringTokenizer st;
      final int stringLength;
      ArrayList terms = new ArrayList();
      String token;
      int tokenCount;
  
      value = value.trim();
      stringLength = value.length();
      
      for (int i = 0; i < stringLength; i++) {
        c = value.charAt(i);
    
        if (c == '\"') {
          // Termination of a quote-enclosed term. Add the current term to the
          // list and start a new term.
          if (keepSpaces) {
            addTerm(terms, currentTerm);
            currentTerm = new StringBuffer(100);
          }
        
          keepSpaces = !(keepSpaces); // Toggle keepSpaces to its opposite value.
        }
        else if (c == ' ') {
          // If we are inside a quote-enclosed term, append the space.
          if (keepSpaces) {
            currentTerm.append(c);
          }
          // Else, add the current term to the list and start a new term.
          else {
            addTerm(terms, currentTerm);
            currentTerm = new StringBuffer(100);
          }
        }
        else {
          // Append any non-quote, non-space characters to the current term.
          currentTerm.append(c);
        }
      }
  
      // Add the final term to the list.
      addTerm(terms, currentTerm);
  
      return terms;
    }
  
  
    /**
     * Runs the Metacat query for a browse search, simple search, or advanced
     * search.
     * 
     * @param metacatURL  URL to the metacat servlet
     * @param metacat     A metacat client object, possible null.
     * @param xslPath     File path to the resultset.xsl stylesheet.
     * @return htmlString HTML string representation of the search results.
     */
    private String runQuery(final String metacatURL, 
                            Metacat metacat, 
                            final String xslPath) {
      String htmlString = "";
      Reader reader;
      String resultset = "";
      String sessionId;
      StringReader stringReader;
      Stylizer stylizer = new Stylizer();
      
      if (metacat == null) {
        try {
          metacat = MetacatFactory.createMetacatConnection(metacatURL);
        }
        catch (MetacatInaccessibleException mie) {
          System.err.println("Metacat Inaccessible:\n" + mie.getMessage());
        }
      }
      
      sessionId = metacat.getSessionId();
      
      try {
        System.err.println("Starting query...");
        stringReader = new StringReader(queryString);
        reader = metacat.query(stringReader);
        resultset = IOUtil.getAsString(reader, true);
        System.err.println("Query result:\n" + resultset);
        htmlString = stylizer.resultsetToHTML(resultset, sessionId, 
                                              metacatURL, xslPath);
      } 
      catch (Exception e) {
        System.err.println("General exception:\n" + e.getMessage());
        e.printStackTrace();
      }
  
      return(htmlString);
    }
    
  
    /**
     * Main program to run a test query from the command line.
     * 
     * Pass the server name, server port, and path to resultset.xsl as the first 
     * three command line arguments:
     * 
     * @param argv[0]   The server name, e.g. "earth.lternet.edu"
     * @param argv[1]   The server port, e.g. "8080", or 0 if no port needs
     *                    to be specified.
     * @param argv[2]   The path to the resultset.xsl stylesheet, e.g.
     *                    "C:/Tomcat5/webapps/query/style/common/resultset.xsl"
     */
    public static void main(String[] argv) {
      AdvancedSearch advancedSearch;
      AdvancedSearchBean advancedSearchBean = new AdvancedSearchBean();
      String htmlString = "";
      MetacatHelper metacatHelper = new MetacatHelper();
      String metacatURL;
      final String serverName = argv[0];
      final Integer serverPortInteger = new Integer(argv[1]);
      final int serverPort = serverPortInteger.intValue();
      final String xslPath = argv[2];
  
      advancedSearchBean.setSubjectField("ALL");
      advancedSearchBean.setSubjectValue("bird");    
      //advancedSearchBean.setCreatorSurname("Walsh");
      //advancedSearchBean.setCreatorSurnameQueryType(0);
      //advancedSearchBean.setCreatorOrganization("Georgia Coastal Ecosystems");    
      //advancedSearchBean.setTaxon("Crustacea");    
      //advancedSearchBean.setLocationName("Georgia");    
      //advancedSearchBean.setNorthBound("31.5");    
      //advancedSearchBean.setSouthBound("10"); 
      //advancedSearchBean.setEastBound("-50");
      //advancedSearchBean.setWestBound("-90");
      //advancedSearchBean.setNamedTimescale("Phanerozoic");
      //advancedSearchBean.setStartDate("2001-01-01");
      //advancedSearchBean.setEndDate("2001-07-01");
      advancedSearch = new AdvancedSearch(advancedSearchBean);
      metacatURL = metacatHelper.constructMetacatURL(serverName, serverPort);
      htmlString =advancedSearch.executeAdvancedSearch(metacatURL, null, xslPath);
    }
    
  }
  
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/AdvancedSearchBean.java
  
  Index: AdvancedSearchBean.java
  ===================================================================
  /**
   *  '$RCSfile: AdvancedSearchBean.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  import java.io.Serializable;
  
  /**
   * @author dcosta
   *
   * The AdvancedSearchBean class stores query properties and values for
   * conducting an advanced Metacat search.
   */
  public class AdvancedSearchBean implements Serializable {
    
    // Possible values for the various ___QueryType fields. These are translated
    // to the various "searchmode" values in the Metacat pathquery.
    public static final int CONTAINS = 0;     // LIKE "%word%"
    public static final int EXACT_MATCH = 1; 	// LIKE = "word"
    public static final int STARTS_WITH = 2;	// LIKE "word%"
    public static final int ENDS_WITH = 3;    // LIKE "%word"
  	
    // Possible values for subjectAllAny field
    public static final int MATCH_ALL = 0;
    public static final int MATCH_ANY = 1;
  	
    private boolean boundaryContained;
    private boolean caseSensitive;
    private String  creatorOrganization;
    private int     creatorOrganizationQueryType;
    private String  creatorSurname;
    private int     creatorSurnameQueryType;
    private String  dateField;      // "PUBLICATION", "COLLECTION", or "ALL"
    private String  eastBound;
    private String  endDate;
    private int     formAllAny;     // MATCH_ALL or MATCH_ANY
    private String  locationName;
    private String  namedTimescale;
    private int     namedTimescaleQueryType;
    private String  northBound;
    private String  southBound;
    private String  siteValue;
    private String  startDate;
    private int     subjectAllAny;  // MATCH_ALL or MATCH_ANY
    private String  subjectField;   // "ALL", "TITLE", "ABSTRACT", or "KEYWORD"
    private int     subjectQueryType;
    private String  subjectValue;
    private String  taxon;
    private int     taxonQueryType;
    private String  westBound;
  
  
    /**
     * @return Returns the creatorOrganization.
     */
    public String getCreatorOrganization() {
      return creatorOrganization;
    }
    
    
    /**
     * @return Returns the creatorOrganizationQueryType.
     */
    public int getCreatorOrganizationQueryType() {
      return creatorOrganizationQueryType;
    }
    
    
    /**
     * @return Returns the creatorSurname.
     */
    public String getCreatorSurname() {
      return creatorSurname;
    }
    
    
    /**
     * @return Returns the creatorSurnameQueryType.
     */
    public int getCreatorSurnameQueryType() {
      return creatorSurnameQueryType;
    }
    
    
    /**
     * @return Returns the dateField. Possible values: "PUBLICATION", "COLLECTION" 
     */
    public String getDateField() {
      return dateField;
    }
    
    
    /**
     * @return Returns the eastBound.
     */
    public String getEastBound() {
      return eastBound;
    }
    
    
    /**
     * @return Returns the endDate.
     */
    public String getEndDate() {
      return endDate;
    }
    
    
    /**
     * @return Returns the formAllAny value.  Possible values are 0 or 1.      
     */
    public int getFormAllAny() {
      return formAllAny;
    }
    
    
    /**
     * @return Returns the locationName.
     */
    public String getLocationName() {
      return locationName;
    }
    
    
    /**
     * @return Returns the namedTimescale.
     */
    public String getNamedTimescale() {
      return namedTimescale;
    }
    
    
    /**
     * @return Returns the namedTimescaleQueryType.
     */
    public int getNamedTimescaleQueryType() {
      return namedTimescaleQueryType;
    }
    
    
    /**
     * @return Returns the northBound.
     */
    public String getNorthBound() {
      return northBound;
    }
    
    
    /**
     * @return Returns the siteValue string.
     */
    public String getSiteValue() {
      return siteValue;
    }
    
    
    /**
     * @return Returns the southBound.
     */
    public String getSouthBound() {
      return southBound;
    }
    
    
    /**
     * @return Returns the startDate.
     */
    public String getStartDate() {
      return startDate;
    }
    
    
    /**
     * @return Returns the subjectAllAny value.  Possible values are 0 or 1.      
     */
    public int getSubjectAllAny() {
      return subjectAllAny;
    }
    
    
    /**
     * @return Returns the subjectField.  Possible values are:
     *         "ALL", "TITLE", "ABSTRACT", "KEYWORD"
     */
    public String getSubjectField() {
      return subjectField;
    }
    
    
    /**
     * @return Returns the subjectQueryType. Possible values are:
     * 0 (contains), 1 (exact match), 2 (starts with), 3 (ends with).
     */
    public int getSubjectQueryType() {
      return subjectQueryType;
    }
    
    
    /**
     * @return Returns the subjectValue.
     */
    public String getSubjectValue() {
      return subjectValue;
    }
    
    
    /**
     * @return Returns the taxon.
     */
    public String getTaxon() {
      return taxon;
    }
    
    
    /**
     * @return Returns the taxonConditonType.
     */
    public int getTaxonQueryType() {
      return taxonQueryType;
    }
    
    
    /**
     * @return Returns the westBound.
     */
    public String getWestBound() {
      return westBound;
    }
    
    
    /**
     * @return Returns the boundaryContained value.
     */
    public boolean isBoundaryContained() {
      return boundaryContained;
    }
    
  
    /**
     * @return Returns the caseSensitive value;
     */
    public boolean isCaseSensitive() {
      return caseSensitive;
    }
    
  
    /**
     * Boolean to determine whether a string is empty. A string is considered to
     * be empty if its value is either null or "".
     * 
     * @param  s      the string to check
     * @return        true if the string is empty, else false.
     */
    public boolean isEmpty(String s) {
      if (s != null && !s.equals(""))
        return false;
      else
        return true;
    }
    
    
    /**
     * @return Returns the limitedByBoundaries.
     */
    public boolean isLimitedByBoundaries() {
      if (!isEmpty(this.eastBound) && !isEmpty(this.westBound)) {
        return true;
      }
      else if (!isEmpty(this.southBound) && !isEmpty(this.northBound)) {
        return true;
      }
      else {
        return false;
      }
    }
  
    
    /**
     * @return Returns the limitedByDate.
     */
    public boolean isLimitedByDate() {
      if (!isEmpty(this.endDate) || !isEmpty(this.startDate)) {
        return true;
      }
      else {
        return false;
      }
    }
  
  
    /**
     * @param boundaryContained The boundaryContained value to set.
     */
    public void setBoundaryContained(final boolean boundaryContained) {
      this.boundaryContained = boundaryContained;
    }
    
    
    /**
     * @param caseSensitive The caseSensitive value to set.
     */
    public void setCaseSensitive(final boolean caseSensitive) {
      this.caseSensitive = caseSensitive;
    }
    
    
    /**
     * @param creatorOrganization The creatorOrganization to set.
     */
    public void setCreatorOrganization(final String creatorField) {
      this.creatorOrganization = creatorField;
    }
    
    
    /**
     * @param creatorOrganizationQueryType The creatorOrganizationQueryType to set
     */
    public void setCreatorOrganizationQueryType(final int creatorConditionType) {
      this.creatorOrganizationQueryType = creatorConditionType;
    }
    
    
    /**
     * @param creatorSurname   The creatorSurname to set.
     */
    public void setCreatorSurname(final String creatorValue) {
      this.creatorSurname = creatorValue;
    }
    
    
    /**
     * @param creatorSurnameQueryType   The creatorSurnameQueryType to set.
     */
    public void setCreatorSurnameQueryType(final int creatorSurnameQueryType) {
      this.creatorSurnameQueryType = creatorSurnameQueryType;
    }
  
  
    /**
     * @param dateField The dateField to set.
     */
    public void setDateField(final String dateField) {
      this.dateField = dateField;
    }
    
    
    /**
     * @param eastBound The eastBound to set.
     */
    public void setEastBound(final String eastBound) {
      this.eastBound = eastBound;
    }
    
    
    /**
     * @param endDate The endDate to set.
     */
    public void setEndDate(final String endDate) {
      this.endDate = endDate;
    }
    
    
    /**
     * @return Sets the formAllAny value.  Possible values are
     *         MATCH_ALL (0) or MATCH_ANY (1).  
     */
    public void setFormAllAny(final int allAny) {
      this.formAllAny = allAny;
    }
    
    
    /**
     * @param locationName The locationName to set.
     */
    public void setLocationName(final String locationName) {
      this.locationName = locationName;
    }
    
    
    /**
     * @param namedTimescale The namedTimescale to set.
     */
    public void setNamedTimescale(final String namedTimescale) {
      this.namedTimescale = namedTimescale;
    }
    
    
    /**
     * @param namedTimescaleQueryType The namedTimescaleQueryType to set.
     */
    public void setNamedTimescaleQueryType(final int namedTimescaleQueryType) {
      this.namedTimescaleQueryType = namedTimescaleQueryType;
    }
    
    
    /**
     * @param northBound The northBound to set.
     */
    public void setNorthBound(final String northBound) {
      this.northBound = northBound;
    }
  
    
    /**
     * @param siteValue    the siteValue to set.
     */
    public void setSiteValue(final String siteValue) {
      this.siteValue = siteValue;
    }
    
  
    /**
     * @param southBound The southBound to set.
     */
    public void setSouthBound(final String southBound) {
      this.southBound = southBound;
    }
    
    
    /**
     * @param startDate The startDate to set.
     */
    public void setStartDate(final String startDate) {
      this.startDate = startDate;
    }
    
    
    /**
     * Sets the subjectAllAny value.  
     * 
     * @param allAny Possible values are MATCH_ALL (0) or MATCH_ANY (1).  
     */
    public void setSubjectAllAny(final int allAny) {
      this.subjectAllAny = allAny;
    }
    
    
    /**
     * @param subjectField The subjectField to set.
     */
    public void setSubjectField(final String subjectField) {
      this.subjectField = subjectField;
    }
    
    
    /**
     * @param subjectQueryType The subjectQueryType to set. Possible values are:
     *                         0 (contains), 1 (exact match), 2 (starts with), 
     *                         3 (ends with).   
     */
    public void setSubjectQueryType(final int subjectQueryType) {
      this.subjectQueryType = subjectQueryType;
    }
    
    
    /**
     * @param subjectValue The subjectValue to set.
     */
    public void setSubjectValue(final String subjectValue) {
      this.subjectValue = subjectValue;
    }
    
    
    /**
     * @param taxon The taxon to set.
     */
    public void setTaxon(final String taxon) {
      this.taxon = taxon;
    }
    
    
    /**
     * @param taxonQueryType The taxonQueryType to set.
     */
    public void setTaxonQueryType(final int taxonQueryType) {
      this.taxonQueryType = taxonQueryType;
    }
    
    
    /**
     * @param westBound The westBound to set.
     */
    public void setWestBound(final String westBound) {
      this.westBound = westBound;
    }
  
  }
  
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/AdvancedSearchPathQuery.java
  
  Index: AdvancedSearchPathQuery.java
  ===================================================================
  /**
   *  '$RCSfile: AdvancedSearchPathQuery.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  import java.util.ArrayList;
  
  /**
   * @author dcosta
   * 
   * The AdvancedSearchPathQuery class holds the data needed to produce a 
   * valid PathQuery XML string.
   */
  public class AdvancedSearchPathQuery  {
    
    // Object variables
    private String indent;                       // String of spaces
    private final int initialLength = 500;       // Initial length of stringBuffer
    private StringBuffer stringBuffer;           // Holds the pathquery xml
    private ArrayList returnFieldList = new ArrayList(); // List of returnfields
    private AdvancedSearchQueryGroup queryGroup;         // The outer query group
    private String title;                                // The pathquery title
    
  
    /**
     * Constructor. Initializes the pathquery title, the main query group, and the
     * indent string.
     * 
     * @param title         the title of the pathquery
     * @param queryGroup    the main query group
     * @param indent        a string of spaces used for indenting output
     */
    public AdvancedSearchPathQuery(final String title, 
                                   final AdvancedSearchQueryGroup queryGroup, 
                                   final String indent) {
      this.title = title;
      this.queryGroup = queryGroup;
      this.indent = indent;
      addReturnField("dataset/title");
      addReturnField("originator/individualName/surName");
      addReturnField("dataset/creator/individualName/surName");
      addReturnField("originator/organizationName");
      addReturnField("creator/organizationName");
      addReturnField("keyword");
    }
    
  
    /**
     * Adds a returnfield to the pathquery xml.
     * 
     * @param s       the name of the returnfield to add
     */
    public void addReturnField(final String s) {
      returnFieldList.add(s);
    }
    
  
    /**
     * Creates the pathquery xml string.
     * 
     * @return  a string holding the PathQuery XML.
     */
    public String toString() {
      String returnField;
  
      stringBuffer = new StringBuffer(initialLength);
      stringBuffer.append("<?xml version=\"1.0\"?>\n");
      stringBuffer.append("<pathquery version=\"1.2\">\n");
      stringBuffer.append(indent + "<querytitle>" + 
                          title + "</querytitle>\n");
  
      for (int i = 0; i < returnFieldList.size(); i++) {
        returnField = (String) returnFieldList.get(i);
        stringBuffer.append(indent + "<returnfield>" + 
                            returnField + "</returnfield>\n");
      }
      
      stringBuffer.append(queryGroup.toString());
      stringBuffer.append("</pathquery>\n");
  
      return stringBuffer.toString();
    }
    
  }
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/AdvancedSearchQueryGroup.java
  
  Index: AdvancedSearchQueryGroup.java
  ===================================================================
  /**
   *  '$RCSfile: AdvancedSearchQueryGroup.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  import java.util.ArrayList;
  
  /**
   * @author dcosta
   * 
   * AdvancedSearchQueryGroup holds the data needed to produce a valid querygroup 
   * string. A querygroup is composed of one or more querygroups and/or 
   * queryterms.
   */
  public class AdvancedSearchQueryGroup  {
    
    // Object variables
    private boolean includeOuterQueryGroup = true;
    private String indent;                // String of spaces for indenting output
    private final int initialLength = 500; // Initial length of the stringBuffer
    private String operator;              // "INTERSECT" or "UNION" operator
    private StringBuffer stringBuffer;    // Holds the querygroup string
    private ArrayList queryGroupList = new ArrayList(); // List of querygroups
    private ArrayList queryTermList = new ArrayList();  // List of queryterms
  
  
    /**
     * Constructor. Initializes the operator and the indent.
     * 
     * @param operator       Must be either "INTERSECT" or "UNION"
     * @param indent         A string of spaces for indenting the xml output
     */
    public AdvancedSearchQueryGroup(final String operator, final String indent) {
      this.operator = operator;
      this.indent = indent;
      
      if (!((operator.equals("INTERSECT")) || (operator.equals("UNION")))) {
        System.err.println("Invalid AdvancedSearchQueryGroup operator: " + 
                           operator);
      }
    }
    
  
    /**
     * Adds a AdvancedSearchQueryGroup to this AdvancedSearchQueryGroup's list of 
     * querygroups.
     * 
     * @param queryGroup   The AdvancedSearchQueryGroup object to be added to 
     *                     the list.
     */
    public void addQueryGroup(final AdvancedSearchQueryGroup queryGroup) {
      queryGroupList.add(queryGroup);
    }
    
  
    /**
     * Adds a AdvancedSearchQueryTerm to this AdvancedSearchQueryGroup's list of 
     * queryterms.
     * 
     * @param queryTerm   The AdvancedSearchQueryTerm object to be added to the 
     *                    list.
     */
    public void addQueryTerm(final AdvancedSearchQueryTerm queryTerm) {
      queryTermList.add(queryTerm);
    }
    
   
    /**
     * Sets the boolean value of includeOuterQueryGroup. This enables an
     * optimization. If the user enter search values for only one part of the
     * advanced search form, then includeOuterQueryGroup can be set to false.
     * When false, the QueryGroup object will omit the outer query group from
     * the PathQuery, resulting in a less nested SQL statement.
     * 
     * @param b  When false, allows the outer QueryGroup to be stripped off,
     *           resulting in a less nested SQL statement.
     */
    public void setIncludeOuterQueryGroup(boolean b) {
      this.includeOuterQueryGroup = b;
    }
    
  
    /**
     * Creates the XML string that represents this AdvancedSearchQueryGroup, 
     * including the querygroups and queryterms that are descendants of this 
     * querygroup.
     * 
     * @return    A XML string fragment representing this querygroup.
     */
    public String toString() {
      AdvancedSearchQueryGroup queryGroup;
      AdvancedSearchQueryTerm queryTerm;
      
      stringBuffer = new StringBuffer(initialLength);
      
      if (includeOuterQueryGroup == true) {
        stringBuffer.append(indent + 
                            "<querygroup operator=\"" + operator + "\">\n");
      }
      
      for (int i = 0; i < queryGroupList.size(); i++) {
        queryGroup = (AdvancedSearchQueryGroup) queryGroupList.get(i);
        stringBuffer.append(queryGroup.toString());
      }
  
      for (int i = 0; i < queryTermList.size(); i++) {
        queryTerm = (AdvancedSearchQueryTerm) queryTermList.get(i);
        stringBuffer.append(queryTerm.toString());
      }
      
      if (includeOuterQueryGroup == true) {
        stringBuffer.append(indent + "</querygroup>\n");
      }
  
      return stringBuffer.toString();
    }
    
  }
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/AdvancedSearchQueryTerm.java
  
  Index: AdvancedSearchQueryTerm.java
  ===================================================================
  /**
   *  '$RCSfile: AdvancedSearchQueryTerm.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  /** 
   * @author dcosta
   * 
   * The AdvancedSearchQueryTerm class holds the data needed to produce a xml 
   * string fragment representing a single queryterm in a querygroup.
   */
  public class AdvancedSearchQueryTerm  {
  
    // Object variables
    private final String caseSensitive;//Case sensitive setting, "true" or "false"
    private final String indent;       // String of spaces for indenting output
    private final int initialLength = 100; // Initial length of the stringBuffer
    private final String pathExpr;         // The search field, e.g. "keyword"
    private final String searchMode;   // The search mode, e.g. "less-than"
    private StringBuffer stringBuffer; // Holds the queryterm xml string
    private final String value;        // The search value to match, e.g. "35"
  
  
    /**
     * Constructor. Initializes searchMode, caseSensitive, value, and indent.
     * 
     * @param searchMode       The search mode, e.g. "less-than-equals"
     * @param caseSensitive    Case sensitive setting, "true" or "false"
     * @param pathExpr         The search field, e.g. "northBoundingCoordinate"
     * @param value            The search value to match, e.g. "35"
     * @param indent           String of spaces for indenting output
     */
    public AdvancedSearchQueryTerm(final String searchMode, 
                                   final String caseSensitive, 
                                   final String pathExpr, 
                                   final String value, 
                                   final String indent
                           ) {
      this.searchMode = searchMode;
      this.caseSensitive = caseSensitive;
      this.pathExpr = pathExpr;
      this.value = value;
      this.indent = indent;
      stringBuffer = new StringBuffer(initialLength);
    }
    
  
    /**
     * Produce a xml string fragment that represents this queryterm.
     * 
     * @return    A xml string fragment that represents this queryterm.
     */
    public String toString() {
      stringBuffer.append(indent + 
                          "<queryterm searchmode=\"" + 
                          searchMode + 
                          "\" casesensitive=\"" + 
                          caseSensitive + 
                          "\">\n"
                         );
  
      stringBuffer.append(indent + "  <value>" + value + "</value>\n");
  
      // For a simple search or a browse search, the pathExpr string will be "".
      if (!pathExpr.equals("")) {
        stringBuffer.append(indent + "  <pathexpr>" + pathExpr + "</pathexpr>\n");
      }
      
      stringBuffer.append(indent + "</queryterm>\n");
  
      return stringBuffer.toString();
    }
  
  }
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/AdvancedSearchServlet.java
  
  Index: AdvancedSearchServlet.java
  ===================================================================
  /**
   *  '$RCSfile: AdvancedSearchServlet.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  import java.io.IOException;
  import java.util.Enumeration;
  
  import javax.servlet.RequestDispatcher;
  import javax.servlet.ServletContext;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  
  import edu.ucsb.nceas.metacat.client.*;
  
  /** 
   * @author dcosta
   * 
   * The AdvancedSearchServlet executes an advanced search.
   */
  public class AdvancedSearchServlet extends HttpServlet {
  
    // Instance Variables -- (Not used because they are not thread-safe.)
  
    // Methods
    
    /**
     * Executes an advanced search.
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
      AdvancedSearch advancedSearch;
      AdvancedSearchBean advancedSearchBean;
      RequestDispatcher dispatcher;
      HttpSession httpSession = request.getSession();
      Metacat metacat = (Metacat) httpSession.getAttribute("metacat");
      String metacatURL;
      String result;
      final String resultsJSP = "style/skins/default/advancedsearchresults.jsp";
      final String resultsXSL = "style/common/resultset.xsl";
      ServletContext servletContext = httpSession.getServletContext();
      String xslPath = servletContext.getRealPath(resultsXSL);
  
      // First check whether the metacat URL was set as a context-param.
      metacatURL = servletContext.getInitParameter("metacatURL");
   
      // If no metacat URL was configured, then derive the metacat URL from the
      // server name and server port.
      if (metacatURL == null || metacatURL.equals("")) {
        MetacatHelper metacatHelper = new MetacatHelper();
        String serverName = request.getServerName();
        int serverPort = request.getServerPort();
        metacatURL = metacatHelper.constructMetacatURL(serverName, serverPort);
      }
  
      // Get the advancedSearchBean object that has been loaded up with user
      // input. Pass the bean to the advancedSearch object, execute the query,
      // and return the search result HTML string.
      advancedSearchBean = 
                  (AdvancedSearchBean) request.getAttribute("advancedSearchBean");
      advancedSearch = new AdvancedSearch(advancedSearchBean);
      result = advancedSearch.executeAdvancedSearch(metacatURL, metacat, xslPath);
      
      // Store the result HTML string in the request for retrieval by
      // the metacatpathqueryresults.jsp form.
      request.setAttribute("result", result);
  		
      dispatcher = request.getRequestDispatcher(resultsJSP);
      dispatcher.forward(request, response);
    }
    
  }
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/BrowseServlet.java
  
  Index: BrowseServlet.java
  ===================================================================
  /**
   *  '$RCSfile: BrowseServlet.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  import java.io.IOException;
  
  import javax.servlet.RequestDispatcher;
  import javax.servlet.ServletContext;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  
  import edu.ucsb.nceas.metacat.client.*;
  
  /** 
   * @author dcosta
   * 
   * The BrowseServlet class executes a browse action. This is equivalent to
   * a simple search, but the user clicks on a link to determine the search term.
   */
  public class BrowseServlet extends HttpServlet {
  
    // Instance Variables -- (Not used because they are not thread-safe.)
  
    // Methods
    
    /**
     * Executes a browse-based simple search.
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {
      AdvancedSearch advancedSearch;
      String browseValue;
      RequestDispatcher dispatcher;
      HttpSession httpSession = request.getSession();
      Metacat metacat = (Metacat) httpSession.getAttribute("metacat");
      String metacatURL;
      String result = "";
      final String resultsJSP = "style/skins/default/advancedsearchresults.jsp";
      ServletContext servletContext = httpSession.getServletContext();
      String stylesheet = (String) httpSession.getAttribute("stylesheet");
      String xslPath = servletContext.getRealPath("style/common/resultset.xsl");
  
      // First check whether the metacat URL was set as a context-param.
      metacatURL = servletContext.getInitParameter("metacatURL");
  
      // If no metacat URL was configured, then derive the metacat URL from the
      // server name and server port.
      if (metacatURL == null || metacatURL.equals("")) {
        MetacatHelper metacatHelper = new MetacatHelper();
        String serverName = request.getServerName();
        int serverPort = request.getServerPort();
        metacatURL = metacatHelper.constructMetacatURL(serverName, serverPort);
      }
  
      // Tell the web server that the response is HTML
      response.setContentType("text/html");
  
      // Fetch the browseValue parameter from the request and execute a search
      advancedSearch = new AdvancedSearch(null);
      browseValue = request.getParameter("browseValue");
      result = advancedSearch.executeSearch(metacatURL, metacat, xslPath, 
                                            browseValue);
  
      // Store the result HTML string in the request for retrieval by
      // the metacatpathqueryresults.jsp form.
      request.setAttribute("result", result);
  
      dispatcher = request.getRequestDispatcher(resultsJSP);
      dispatcher.forward(request, response);
    }
    
  }
  
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/LTERSite.java
  
  Index: LTERSite.java
  ===================================================================
  /**
   *  '$RCSfile: LTERSite.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  /**
   * @author dcosta
   * 
   * The LTERSite class holds information about the LTER sites.
   */
  public class LTERSite {
  
    /* Instance variables */
    public String site;      // The three-letter uppercase acronym for this site.
    
    public final String[] sites = {
        "AND",
        "ARC",
        "BES",
        "BNZ",
        "CAP",
        "CCE",
        "CDR",
        "CWT",
        "FCE",
        "GCE",
        "HBR",
        "HFR",
        "JRN",
        "KBS",
        "KNZ",
        "LNO",
        "LUQ",
        "MCM",
        "MCR",
        "NTL",
        "NWT",
        "PAL",
        "PIE",
        "SBC",
        "SEV",
        "SGS",
        "VCR",
    };
    
    public final String[] siteKeywords = {
        "Andrews LTER",
        "Arctic LTER",
        "Baltimore Ecosystem Study",
        "Bonanza Creek",
        "Central Arizona - Phoenix Urban",
        "California Current Ecosystem",
        "Cedar Creek",
        "Coweeta",
        "Florida Coastal Everglades",
        "Georgia Coastal Ecosystems",
        "Hubbard Brook",
        "Harvard Forest",
        "Jornada Basin",
        "Kellogg Biological Station",
        "Konza Prairie",
        "LTER Network Office",
        "Luquillo",
        "McMurdo Dry Valleys",
        "Moorea Coral Reef",
        "North Temperate Lakes",
        "Niwot Ridge",
        "Palmer Station",
        "Plum Island Ecosystem",
        "Santa Barbara Coastal",
        "Sevilleta",
        "Shortgrass Steppe",
        "Virginia Coastal Reserve",
    };
  
    public final String[] siteNames = {
        "Andrews LTER",
        "Arctic LTER",
        "Baltimore Ecosystem Study",
        "Bonanza Creek LTER",
        "Central Arizona - Phoenix Urban LTER",
        "California Current Ecosystem",
        "Cedar Creek Natural History Area",
        "Coweeta LTER",
        "Florida Coastal Everglades LTER",
        "Georgia Coastal Ecosystems LTER",
        "Hubbard Brook LTER",
        "Harvard Forest LTER",
        "Jornada Basin LTER",
        "Kellogg Biological Station LTER",
        "Konza Prairie LTER",
        "LTER Network Office",
        "Luquillo LTER",
        "McMurdo Dry Valleys LTER",
        "Moorea Coral Reef",
        "North Temperate Lakes LTER",
        "Niwot Ridge LTER",
        "Palmer Station LTER",
        "Plum Island Ecosystem LTER",
        "Santa Barbara Coastal LTER",
        "Sevilleta LTER",
        "Shortgrass Steppe",
        "Virginia Coastal Reserve LTER",
    };
  
  
    /* Constructor 
     * 
     * @param site     The three-letter acronym for this LTER site.
     * 
     */
    public LTERSite(final String site) {
      if (site != null) {
        this.site = site.toUpperCase();
      }
    }
    
    
    /**
     * For a given site, return the packageId attribute search string for that
     * site's EML documents.
     * 
     * @return packageId   The first few letters that uniquely identify a site's
     *                     packageId. Typically "knb-lter-xyz", though there are
     *                     some exceptions.
     */
    public String getPackageId() {
      final String packageId;
  
      if (site == null) {
        packageId = "";
      }
      else if (site.equals("SEV")) {
        packageId = "sev.";
      }
      else {
        packageId = "knb-lter-" + site.toLowerCase();
      }
      
      return packageId;
    }
    
  
    /**
     * Get the keyword string for this site. This keyword string is OR'ed with the
     * packageId to find documents that originated from this site.
     * 
     * @return  siteKeyword  The site keyword string.
     */
    public String getSiteKeyword() {
      String siteKeyword = "";
  
      if (isValidSite()) {
        for (int i = 0; i < sites.length; i++) {
          if (site.equals(sites[i])) { 
            siteKeyword = siteKeywords[i];
            break;
          }
        }
      }
      
      return siteKeyword;
    }
  
  
    /**
     * For a given site, return system attribute search string for that
     * site's EML documents.
     * 
     * @return system  A string representing the system attribute used in a LTER
     *                 site's EML documents.
     */
    public String getSystem() {
      final String system;
      
      if (site == null) {
        system = "";
      }
      else if (site.equals("CAP")) {
        system = "ces_dataset";
      }
      else if (site.equals("CWT")) {
        system = "cwt-lter";
      }
      else {
        system = "knb";
      }
      
      return system;
    }
    
  
    /**
     * Boolean to determine whether a given string is a valid LTER site.
     */
    public boolean isValidSite() {
      boolean isValid = false;
      
      if (site != null) {   
        for (int i = 0; i < sites.length; i++) {
          if (site.equals(sites[i])) { 
            isValid = true;
            break;
          }
        }
      }
      
      return isValid;
    }
  
  }
  
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/LoginBean.java
  
  Index: LoginBean.java
  ===================================================================
  /**
   *  '$RCSfile: LoginBean.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  import java.io.Serializable;
  
  /**
   * @author dcosta
   * 
   * Bean to store login form properties and values.
   *
   */
  public class LoginBean implements Serializable {
    
    private String organization;      /* LDAP organization, e.g. "LTER" */
    private String password;          /* login password string */
    private String username;          /* login username string */
     
    /**
     * @return Returns the organization.
     */
    public String getOrganization() {
      return organization;
    }
    
    
    /**
     * @param organization The organization to set.
     */
    public void setOrganization(final String organization) {
      this.organization = organization;
    }
    
    
    /**
     * @return Returns the password.
     */
    public String getPassword() {
      return password;
    }
    
    
    /**
     * @param password The password to set.
     */
    public void setPassword(final String password) {
      this.password = password;
    }
    
    
    /**
     * @return Returns the username.
     */
    public String getUsername() {
      return username;
    }
    
    
    /**
     * @param username The username to set.
     */
    public void setUsername(final String username) {
      this.username = username;
    }
    
  }
  
  
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/LoginServlet.java
  
  Index: LoginServlet.java
  ===================================================================
  /**
   *  '$RCSfile: LoginServlet.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  import java.io.IOException;
  
  import javax.servlet.RequestDispatcher;
  import javax.servlet.ServletContext;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  
  import edu.ucsb.nceas.metacat.client.*;
  
  /** 
   * @author dcosta
   * 
   * The LoginServlet class executes a metacat login via a metacat client.
   */
  public class LoginServlet extends HttpServlet {
  
    // Instance Variables -- (Not used because they are not thread-safe.)
  
    // Methods
    
    /**
     * Executes a metacat login action. On a successful login, the metacat object
     * is stored as an attribute of the HttpSession object.
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
      RequestDispatcher dispatcher;
      HttpSession httpSession = request.getSession();
      LoginBean loginBean;
      boolean loginSuccess = false;
      Metacat metacat = (Metacat) httpSession.getAttribute("metacat");
      MetacatLogin metacatLogin;
      String metacatURL;
      String organization;
      String result;
      ServletContext servletContext = httpSession.getServletContext();
      String username;
      
      // First check whether the metacat URL was set as a context-param.
      metacatURL = servletContext.getInitParameter("metacatURL");
   
      // If no metacat URL was configured, then derive the metacat URL from the
      // server name and server port.
      if (metacatURL == null || metacatURL.equals("")) {
        MetacatHelper metacatHelper = new MetacatHelper();
        String serverName = request.getServerName();
        int serverPort = request.getServerPort();
        metacatURL = metacatHelper.constructMetacatURL(serverName, serverPort);
      }
      
      if (metacat == null) {
        try {
          metacat = MetacatFactory.createMetacatConnection(metacatURL);
        }
        catch (MetacatInaccessibleException mie) {
          System.err.println("Metacat Inaccessible:\n" + mie.getMessage());
        }
      }
      
      loginBean = (LoginBean) request.getAttribute("loginBean");
      metacatLogin = new MetacatLogin(loginBean);
      loginSuccess = metacatLogin.executeLogin(metacatURL, metacat);
      httpSession.setAttribute("metacat", metacat);
  
      // If login succeeds, forward to the simple search page. If login fails,
      // forward to the login page where an error message will be displayed.
      if (loginSuccess) {
        httpSession.setAttribute("loggedIn", new Boolean(true));
        username = loginBean.getUsername();
        httpSession.setAttribute("username", username);
        dispatcher = request.getRequestDispatcher("/metacatsearch.jsp");
      }
      else {
        request.setAttribute("loginFailure", new Boolean(true));
        dispatcher = request.getRequestDispatcher("/metacatlogin.jsp");
      }
  
      dispatcher.forward(request, response);
    }
  
  }
  
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/MetacatHelper.java
  
  Index: MetacatHelper.java
  ===================================================================
  /**
   *  '$RCSfile: MetacatHelper.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  
  /**
   * @author dcosta
   * 
   * MetacatHelper provides auxiliary methods for helping the advanced search
   * classes interact with Metacat.
   */
  public class MetacatHelper {
    
    /**
     * Constructs a DN (Distinguished Name) string for the ecoinformatics.org
     * LDAP.
     * 
     * @param username       The LDAP uid, e.g. "dcosta"
     * @param organization   The LDAP organization, e.g. "LTER"
     * @return DN            The distinguished name string.
     */
    public String constructDN(final String username, final String organization) {
      final String DN = "uid=" + username + 
                        ",o=" + organization + 
                        ",dc=ecoinformatics,dc=org";    
      
      return DN;
    }
    
  
    /**
     * Constructs a URL to the metacat servlet. Assumes that metacat is always
     * configured to run in the "knb" context (the defacto standard).
     * 
     * @param serverName   A server name, e.g. "prairie.lternet.edu"
     * @param serverPort   A server port, e.g. 8080. If no port is required in
     *                     the URL, pass a 0 and the argument will be ignored.
     * @return metacatURL  The URL to the metacat servlet.
     */
    public String constructMetacatURL(final String serverName, 
                                      final int serverPort) {
      String metacatURL = "http://" + serverName;
      
      if (serverPort > 0) {
        final Integer serverPortInteger = new Integer(serverPort);
        final String serverPortString = serverPortInteger.toString();
        metacatURL += ":" + serverPortString + "/knb/metacat";
      }
      else {
        metacatURL += "/knb/metacat";
      }
      
      return metacatURL;
    }
  
  }
  
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/MetacatLogin.java
  
  Index: MetacatLogin.java
  ===================================================================
  /**
   *  '$RCSfile: MetacatLogin.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  import edu.ucsb.nceas.metacat.client.*;
  
  
  /**
   * @author dcosta
   * 
   * MetacatLogin class executes a Metacat login using the Metacat client.
   */
  public class MetacatLogin  {
  
    /* Object variables */
    private LoginBean loginBean = null;
  
    
    /**
     * Constructor. Initializes the loginBean object variable.
     * 
     * @param loginBean  the LoginBean object, holds username and password
     */
    public MetacatLogin(final LoginBean loginBean) {
      this.loginBean = loginBean;
    }
  
    
    /**
     * Executes the Metacat login.
     * 
     * @param metacatURL      URL to the metacat servlet
     * @param metacat         a Metacat object, possibly null
     * 
     * @return loginSuccess   true if metacat login was successful, else false
     */
    public boolean executeLogin(final String metacatURL, final Metacat metacat) {
      final String DN;                            // LDAP distinguished name
      boolean loginSuccess = false;
      MetacatHelper metacatHelper = new MetacatHelper();
      String metacatResponse = "";
      final String organization = loginBean.getOrganization();
      final String password = loginBean.getPassword();
      final String username = loginBean.getUsername();
      
      if (
          username == null || 
          organization == null || 
          password == null || 
          username.equals("") || 
          organization.equals("") || 
          password.equals("")) 
      {
        return loginSuccess;
      }
      else {    
        System.err.println("Metacat URL: " + metacatURL);
  
        try {
          DN = metacatHelper.constructDN(username, organization);    
          metacatResponse = metacat.login(DN, password);
          System.err.println("metacatResponse:\n" + metacatResponse);
          
          if (metacatResponse.indexOf("Authentication successful") > -1) {
            loginSuccess = true;
          }
        } 
        catch (MetacatAuthException mae) {
          System.err.println("MetacatAuthException:\n" + mae.getMessage());
        } 
        catch (MetacatInaccessibleException mie) {
          System.err.println("Metacat Inaccessible:\n" + mie.getMessage());
        }
        catch (Exception e) {
          System.err.println("General exception:\n" + e.getMessage());
          e.printStackTrace();
        }
      }
      
      return loginSuccess;
    }
  
  }
  
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/SearchServlet.java
  
  Index: SearchServlet.java
  ===================================================================
  /**
   *  '$RCSfile: SearchServlet.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  import java.io.IOException;
  import javax.servlet.RequestDispatcher;
  import javax.servlet.ServletContext;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  
  import edu.ucsb.nceas.metacat.client.*;
  
  /** 
   * @author dcosta
   * 
   * The SearchServlet class executes a search action. This corresponds to when a
   * user fills in a simple search text box and clicks "Search".
   */
  public class SearchServlet extends HttpServlet {
  
    // Instance Variables -- (Not used because they are not thread-safe.)
  
    // Methods
    
    /**
     * Executes a simple search.
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {
      AdvancedSearch advancedSearch;
      RequestDispatcher dispatcher;
      HttpSession httpSession = request.getSession();
      Metacat metacat = (Metacat) httpSession.getAttribute("metacat");
      String metacatURL;
      String result = "";
      final String resultsJSP = "style/skins/default/advancedsearchresults.jsp";
      String searchValue;
      ServletContext servletContext = httpSession.getServletContext();
      String stylesheet = (String) httpSession.getAttribute("stylesheet");
      String xslPath = servletContext.getRealPath("style/common/resultset.xsl");
  
      // First check whether the metacat URL was set as a context-param.
      metacatURL = servletContext.getInitParameter("metacatURL");
  
      // If no metacat URL was configured, then derive the metacat URL from the
      // server name and server port.
      if (metacatURL == null || metacatURL.equals("")) {
        MetacatHelper metacatHelper = new MetacatHelper();
        String serverName = request.getServerName();
        int serverPort = request.getServerPort();
        metacatURL = metacatHelper.constructMetacatURL(serverName, serverPort);
      }
  
      // Tell the web server that the response is HTML
      response.setContentType("text/html");
  
      // Fetch the searchValue parameter from the request and execute a search
      advancedSearch = new AdvancedSearch(null);
      searchValue = request.getParameter("searchValue");
      System.err.println("Search Servlet: " + searchValue);
      result = advancedSearch.executeSearch(metacatURL, metacat, xslPath, searchValue);
  
      // Store the result HTML string in the request for retrieval by
      // the metacatpathqueryresults.jsp form.
      request.setAttribute("result", result);
  
      dispatcher = request.getRequestDispatcher(resultsJSP);
      dispatcher.forward(request, response);
    }
    
  }
  
  
  
  1.1                  metacat/src/edu/ucsb/nceas/metacat/advancedsearch/Stylizer.java
  
  Index: Stylizer.java
  ===================================================================
  /**
   *  '$RCSfile: Stylizer.java,v $'
   *  Copyright: 2005 University of New Mexico and the 
   *             Regents of the University of California and the
   *             National Center for Ecological Analysis and Synthesis
   *   '$Author: costa $'
   *     '$Date: 2005/11/16 17:57:33 $'
   * '$Revision: 1.1 $'
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  package edu.ucsb.nceas.metacat.advancedsearch;
  
  import java.io.*;
  import javax.xml.transform.Result;
  import javax.xml.transform.Source;
  import javax.xml.transform.Transformer;
  import javax.xml.transform.TransformerConfigurationException;
  import javax.xml.transform.TransformerException;
  import javax.xml.transform.TransformerFactory;
  
  /**
   * @author dcosta
   * 
   * Stylizer class applies the resultset.xsl stylesheet to the pathquery
   * results returned by Metacat.
   */
  public class Stylizer {
  
    /**
     * Applies the resultset.xsl stylesheet to the pathquery result string
     * returned by Metacat.
     * 
     * @param resultset       the pathquery result string from Metacat
     * @param sessionId       the user's session id
     * @param metacatURL      the URL to the Metacat server
     * 
     * @return htmlString     the result of the transformation from XML to HTML
     */
    public String resultsetToHTML(final String resultset, 
                                  final String sessionId,
                                  final String metacatURL,
                                  final String xslPath) {
      String htmlString = "";
      Result result;
      StringWriter stringWriter = new StringWriter();
      Transformer transformer;
      TransformerFactory transformerFactory;
      Source xmlSource;
      File xsltFile = new File(xslPath);            
      Source xsltSource;
      StringReader stringReader = new StringReader(resultset);
      
      xmlSource = new javax.xml.transform.stream.StreamSource(stringReader);
      xsltSource = new javax.xml.transform.stream.StreamSource(xsltFile);
      result = new javax.xml.transform.stream.StreamResult(stringWriter);
  
      // create an instance of TransformerFactory
      transformerFactory = TransformerFactory.newInstance();
  
      try {
        transformer = transformerFactory.newTransformer(xsltSource);
        transformer.setParameter("sessid", sessionId);
        transformer.setParameter("metacatURL", metacatURL);
        transformer.transform(xmlSource, result);
        htmlString = stringWriter.toString();
      }
      catch (TransformerConfigurationException tce) {
        // Error generated by the parser
        Throwable x = tce;  // Use the contained exception, if any
          
        if (tce.getException() != null) {
          x = tce.getException();    
        }
  
        x.printStackTrace();   
      }
      catch (TransformerException te) {
        // Error generated by the parser
        Throwable x = te;  // Use the contained exception, if any
          
        if (te.getException() != null) {
          x = te.getException();    
        }
  
        x.printStackTrace(); 
      }
        
      return htmlString;
    }
    
  }
  
  


More information about the Metacat-cvs mailing list