You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-dev@jakarta.apache.org by lu...@apache.org on 2004/10/18 11:27:36 UTC

cvs commit: jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions AbstractExpression.java BetweenExpression.java EqExpression.java GtExpression.java IsCollectionExpression.java IsDefinedExpression.java IsPrincipalExpression.java LikeExpression.java LtExpression.java MergeExpression.java PropcontainsExpression.java

luetzkendorf    2004/10/18 02:27:36

  Added:       src/stores/org/apache/slide/index/lucene Index.java
                        IndexConfiguration.java IndexException.java
                        LuceneExpressionFactory.java
                        LucenePropertiesIndexer.java
               src/stores/org/apache/slide/index/lucene/expressions
                        AbstractExpression.java BetweenExpression.java
                        EqExpression.java GtExpression.java
                        IsCollectionExpression.java
                        IsDefinedExpression.java IsPrincipalExpression.java
                        LikeExpression.java LtExpression.java
                        MergeExpression.java PropcontainsExpression.java
  Log:
  added first version of lucene based properties indexer
  
  Revision  Changes    Path
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/Index.java
  
  Index: Index.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/Index.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene;
  
  import java.io.File;
  import java.io.IOException;
  import java.text.DecimalFormat;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.Iterator;
  import java.util.Locale;
  import java.util.Map;
  import java.util.Set;
  
  import org.apache.lucene.analysis.Analyzer;
  import org.apache.lucene.document.Document;
  import org.apache.lucene.index.IndexReader;
  import org.apache.lucene.index.IndexWriter;
  import org.apache.lucene.index.Term;
  import org.apache.lucene.search.BooleanQuery;
  import org.apache.lucene.search.IndexSearcher;
  import org.apache.lucene.store.Directory;
  import org.apache.lucene.store.FSDirectory;
  
  import org.apache.slide.util.logger.Logger;
  
  /**
   * Wrapper for Lucene index.
   */
  public class Index
  {
      public static final String KEY_FIELD_NAME = "SLIDE_KEY";
      public static final String URI_FIELD_NAME = "SLIDE_URI";
      public static final String SCOPE_FIELD_NAME = "SLIDE_SCOPE";
      public static final String VERSION_FIELD_NAME = "SLIDE_VERSION";
      public static final String IS_DEFINED_FIELD_NAME = "SLIDE_ISDEFINED";
      
      protected static final SimpleDateFormat DATE_INDEX_FORMAT = 
          new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.UK);
      protected static final DecimalFormat INT_INDEX_FORMAT = 
          new DecimalFormat("b0000000000000000000;a0000000000000000000");
      
      public static final String DATE_LOWER_BOUND = DATE_INDEX_FORMAT.format(new Date(0));
      public static final String DATE_UPPER_BOUND = DATE_INDEX_FORMAT.format(new Date(Long.MAX_VALUE));
      public static final String INT_LOWER_BOUND = INT_INDEX_FORMAT.format(Long.MIN_VALUE);
      public static final String INT_UPPER_BOUND = INT_INDEX_FORMAT.format(Long.MAX_VALUE);
  
      
      private Analyzer analyzer;
      
      private IndexConfiguration configuration;
  
      private String directoryName;
      
      private Logger logger;
      
  
      public Index(String directoryName, Analyzer analyzer, Logger logger) throws IndexException
      {
          this.directoryName = directoryName;
          this.analyzer = analyzer;
          this.logger = logger;
          
          this.configuration = new IndexConfiguration();
          this.configuration.initDefaultConfiguration();
  
          File file = new File(this.directoryName);
          if (!file.exists() && !file.mkdirs()) {
              throw new IndexException(
                      "Error can't get or create index directory: ",
                      this.directoryName);
          }
  
          try {
              Directory directory = getDirectory();
              if (IndexReader.indexExists(directory)) {
                  if (IndexReader.isLocked(directory)) {
                      IndexReader.unlock(directory);
                  }                
              } else {
                  IndexWriter writer = new IndexWriter(directory, 
                          this.analyzer, true);
                  writer.close();
              }
          } catch (IOException e) {
              throw new IndexException("Error while creating index: ", 
                      this.directoryName, e);
          }
          
          // TODO make configurable
          BooleanQuery.setMaxClauseCount(10000);
      }
      
      public IndexConfiguration getConfiguration() {
          return this.configuration;
      }
      
      public Logger getLogger() {
          return this.logger;
      }
  
      
      public IndexSearcher getSearcher() throws IOException {
          // TODO can this be reused?
          return new IndexSearcher(this.directoryName);
      }
  
  
      private Directory getDirectory() throws IOException
      {
          // file system based directory
          return FSDirectory.getDirectory(this.directoryName, false);
      }
      
      synchronized void addIndexJob(Map toAdd, Set toRemove) throws IOException {
          // TODO make async by option
          if (toRemove.size() > 0) {
              IndexReader reader = IndexReader.open(getDirectory());
              for(Iterator i = toRemove.iterator(); i.hasNext();) {
                  String key = (String)i.next();
                  reader.delete(new Term(Index.KEY_FIELD_NAME, key));
              }
              reader.close();
          }
  
          if (toAdd.size() > 0) {
              IndexWriter writer = new IndexWriter(getDirectory(), 
                      this.analyzer, false);
              
              for(Iterator i = toAdd.values().iterator(); i.hasNext(); ) {
                  Document doc = (Document)i.next();
                  writer.addDocument(doc);
              }
              
              writer.close();
          }
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/IndexConfiguration.java
  
  Index: IndexConfiguration.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/IndexConfiguration.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene;
  
  import java.text.ParseException;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Locale;
  import java.util.Map;
  import java.util.Set;
  
  import org.apache.lucene.analysis.Analyzer;
  
  import org.apache.slide.common.Uri;
  import org.apache.slide.content.NodeProperty;
  import org.apache.slide.content.NodeRevisionNumber;
  import org.jdom.Element;
  
  /**
   */
  public class IndexConfiguration
  {
       
      private Set keywordProperties = new HashSet();
      private Set textProperties = new HashSet();
      private Set dateProperties = new HashSet();
      private Set intProperties = new HashSet();
      private Set supportsIsdefinedProperties = new HashSet();
      private Set indexedProperties = new HashSet();
      private Map analyzers = new HashMap();
      
      public void addKeywordProperty(String namespace, String name) {
          String key = namespace + name;
          this.keywordProperties.add(key);
          this.indexedProperties.add(key);
      }
      public boolean isKeywordProperty(NodeProperty property) {
          return this.keywordProperties.contains(
                  property.getNamespace() + property.getName());
      }
      
      public void addTextProperty(String namespace, String name) {
          String key = namespace + name;
          this.textProperties.add(key);
          this.indexedProperties.add(key);
      }
      public boolean isTextProperty(NodeProperty property) {
          return this.textProperties.contains(
                  property.getNamespace() + property.getName());
      }
      
      public void addDateProperty(String namespace, String name) {
          String key = namespace + name;
          this.dateProperties.add(key);
          this.indexedProperties.add(key);
      }
      public boolean isDateProperty(String namespace, String name) {
          return this.dateProperties.contains(namespace + name);
      }
      public boolean isDateProperty(NodeProperty property) {
          return isDateProperty(property.getNamespace(), property.getName());
      }
      public boolean isDateProperty(Element element) {
          return isDateProperty(element.getNamespaceURI(), element.getName());
      }
      
      
      public void addIntProperty(String namespace, String name) {
          String key = namespace + name;
          this.intProperties.add(key);
          this.indexedProperties.add(key);
      }
      public boolean isIntProperty(String namespace, String name) {
          return this.intProperties.contains(namespace + name);
      }
      public boolean isIntProperty(NodeProperty property) {
          return isIntProperty(property.getNamespace(), property.getName());
      }
      public boolean isIntProperty(Element element) {
          return isIntProperty(element.getNamespaceURI(), element.getName());
      }
      
      public void addSupportsIsdefinedProperty(String namespace, String name) {
          String key = namespace + name;
          this.supportsIsdefinedProperties.add(key);
          this.indexedProperties.add(key);
      }
      
      public boolean supportsIsDefined(String namespace, String name) {
          return this.supportsIsdefinedProperties.contains(namespace + name);
      }
      public boolean supportsIsDefined(NodeProperty property) {
          return supportsIsDefined(property.getNamespace(), property.getName());
      }
      public boolean supportsIsDefined(Element element) {
          return supportsIsDefined(element.getNamespaceURI(), element.getName());
      }
  
      public boolean isIndexedProperty(String namespace, String name) {
          return this.indexedProperties.contains(namespace + name);
      }
      public boolean isIndexedProperty(NodeProperty property) {
          return isIndexedProperty(property.getNamespace(), property.getName());
      }
      
      public void addAnalyzer(String namespace, String name, Analyzer analyzer) {
          this.analyzers.put(namespace + name, analyzer);
      }
          
      void initDefaultConfiguration() {
          
          addKeywordProperty("DAV:", "displayname");
          addKeywordProperty("DAV:", "getcontenttype");
          addSupportsIsdefinedProperty("DAV:", "getcontenttype");
          addKeywordProperty("DAV:", "getcontentlanguage");
          
          addKeywordProperty("DAV:", "owner");
          addSupportsIsdefinedProperty("DAV:", "owner");
          addKeywordProperty("DAV:", "modificationuser");
          addSupportsIsdefinedProperty("DAV:", "modificationuser");
          
          addIntProperty("DAV:", "getcontentlength");
  
          addDateProperty("DAV:", "getlastmodified");
          addDateProperty("DAV:", "creationdate");
          addDateProperty("DAV:", "modificationdate");
      }
      
      // ------ data type helper -------------------------------------------------
      
      /**
       * Generates a field name for "normal fields".
       */
      public String generateFieldName(String namespaceUri, String name) {
          return namespaceUri + name;
      }
      public String generateFieldName(NodeProperty property) {
          return generateFieldName(property.getNamespace(), property.getName());
      }
      public String generateFieldName(Element element) {
          return generateFieldName(element.getNamespaceURI(), element.getName());
      }
          
      public String generateKey(Uri uri, NodeRevisionNumber number) {
          return uri.toString() + "#" + number;
      }
      
      public String dateToIndexString(Date date) {
          synchronized (Index.DATE_INDEX_FORMAT) {
              return Index.DATE_INDEX_FORMAT.format(date);
          }
      }
      
      public static String intToIndexString(long value) {
          synchronized (Index.INT_INDEX_FORMAT) {
              if (value >= 0) {
                  return Index.INT_INDEX_FORMAT.format(value);
              } else {
                  return Index.INT_INDEX_FORMAT.format(-(Long.MAX_VALUE + value));
              }
          }
      }
      
      
      private static final SimpleDateFormat formats[] = {
              new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
              new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US),
              new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
              new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US),
              new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
          };
      /**
       * Helper that converts property values to dates.
       * @param value 
       * @return a date of <code>null</code> if value can't convert
       */
      public static Date getDateValue(Object value) {
          if (value instanceof Date) {
              return (Date)value;
          } else {
              String valstr = value.toString();
              // Parsing the HTTP Date
              for (int i = 0; i < formats.length; i++) {
                  try {
                      synchronized (formats[i]) {
                          return formats[i].parse(valstr);
                      }
                  } catch (ParseException e) {
                  }
              }
              return null;
          }
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/IndexException.java
  
  Index: IndexException.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/IndexException.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene;
  
  import java.text.MessageFormat;
  
  
  /**
   */
  class IndexException extends Exception
  {
  
      public IndexException()
      {
          super();
      }
  
      public IndexException(String message)
      {
          super(message);
      }
      
      public IndexException(String message, Object param)
      {
          super(MessageFormat.format(message, new Object[]{param}));
      }
      
      public IndexException(String message, Object param1, Object param2)
      {
          super(MessageFormat.format(message, new Object[]{param1, param2}));
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/LuceneExpressionFactory.java
  
  Index: LuceneExpressionFactory.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/LuceneExpressionFactory.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene;
  
  import java.util.Collection;
  
  import org.apache.slide.content.NodeProperty;
  import org.apache.slide.index.lucene.expressions.AbstractExpression;
  import org.apache.slide.index.lucene.expressions.BetweenExpression;
  import org.apache.slide.index.lucene.expressions.EqExpression;
  import org.apache.slide.index.lucene.expressions.GtExpression;
  import org.apache.slide.index.lucene.expressions.IsCollectionExpression;
  import org.apache.slide.index.lucene.expressions.IsDefinedExpression;
  import org.apache.slide.index.lucene.expressions.IsPrincipalExpression;
  import org.apache.slide.index.lucene.expressions.LikeExpression;
  import org.apache.slide.index.lucene.expressions.LtExpression;
  import org.apache.slide.index.lucene.expressions.MergeExpression;
  import org.apache.slide.index.lucene.expressions.PropcontainsExpression;
  import org.apache.slide.search.BadQueryException;
  import org.apache.slide.search.PropertyProvider;
  import org.apache.slide.search.basic.BasicExpressionFactory;
  import org.apache.slide.search.basic.IBasicExpression;
  import org.apache.slide.search.basic.IBasicQuery;
  import org.apache.slide.search.basic.Literals;
  import org.jdom.Element;
  
  /**
   */
  public class LuceneExpressionFactory extends BasicExpressionFactory {
  
      private Index index; 
  
      /**
       * Constructor
       *
       */
      public LuceneExpressionFactory(Index index) {
          this.index = index;
      }
  
      public IBasicExpression createMergeExpression (String mergeOperator,
                                                     String namespace,
                                                     Collection expressionsToMerge)
          throws BadQueryException
      {
          IBasicExpression result = null;
          
          // TODO what if expressionsToMerge contains non lucene expressions
          
          if (namespace.equals (NodeProperty.NamespaceCache.DEFAULT_URI)) {
              if (mergeOperator.equals(Literals.OR)) {
                  result = new MergeExpression(this.index, false, expressionsToMerge);
              } 
              else if (mergeOperator.equals(Literals.AND)) {
                  result = new MergeExpression(this.index, true, expressionsToMerge);
              }
              else {
                  // TODO
              }
          }
          if (result != null) {
              result.setFactory(this);
          }
          // TODO 
          return result;
      }
  
      public IBasicExpression createExpression (Element element)
          throws BadQueryException
      {
          IBasicExpression result = null;
  
          if (element == null)
          {
              throw new BadQueryException ("expected a where criteria");
          }
          else
          {
              String namespace = element.getNamespace().getURI();
              if (namespace.equals (NodeProperty.NamespaceCache.DEFAULT_URI)) {
                  result = createDAVExpression(element);
              }
              else if (namespace.equals(NodeProperty.NamespaceCache.SLIDE_URI)) {
                  result = createSlideExpression(element);
              }
              else {
                  result = super.createExpression(element);                
              }
          }
          if (result != null) {
              result.setFactory(this);
          }
          return result;
      }
  
  
      private IBasicExpression createDAVExpression (Element e) 
          throws BadQueryException
      {
          String name = e.getName();
  
          if (name.equals(Literals.EQ)) {
              return new EqExpression(this.index, e, false);
          } 
          else if (name.equals(Literals.NOT_EQ)) {
              return new EqExpression(this.index, e, true);
          } 
          else if (name.equals(Literals.LT) || name.equals(Literals.NOT_GTE)) {
              return new LtExpression(this.index, e, false);
          }
          else if (name.equals(Literals.LTE) || name.equals(Literals.NOT_GT)) {
              return new LtExpression(this.index, e, true);
          }
          else if (name.equals(Literals.GT) || name.equals(Literals.NOT_LTE)) {
              return new GtExpression(this.index, e, false);
          }
          else if (name.equals(Literals.GTE) || name.equals(Literals.NOT_LT)) {
              return new GtExpression(this.index, e, true);
          }
          else if (name.equals(Literals.ISCOLLECTION)) {
              return new IsCollectionExpression(this.index, false);
          }
          else if (name.equals(Literals.NOT_ISCOLLECTION)) {
              return new IsCollectionExpression(this.index, true);
          }
          else if (name.equals(Literals.LIKE)) {
              return new LikeExpression(this.index, e);
          }
          else if (name.equals(Literals.ISDEFINED)) {
              Element property = AbstractExpression.getPropertyElement(e);
              if (index.getConfiguration().supportsIsDefined(property)) {
                  return new IsDefinedExpression(this.index, e, false);
              }
          }
          else if (name.equals(Literals.NOT_ISDEFINED)) {
              Element property = AbstractExpression.getPropertyElement(e);
              if (index.getConfiguration().supportsIsDefined(property)) {
                  return new IsDefinedExpression(this.index, e, true);
              }
          }
          return super.createExpression(e);
      }
      
      private IBasicExpression createSlideExpression (Element e) 
          throws BadQueryException
      {
          String name = e.getName();
          
          if (name.equals(Literals.ISPRINCIPAL)) {
              return new IsPrincipalExpression(this.index, false);
          }
          if (name.equals(Literals.NOT_ISPRINCIPAL)) {
              return new IsPrincipalExpression(this.index, true);
          }
          if (name.equals(Literals.PROPCONTAINS)) {
              return new PropcontainsExpression(this.index, e);
          }
          if (name.equals("between")) {
              return new BetweenExpression(this.index, e, false);
          }
          if (name.equals("between-inclusive")) {
              return new BetweenExpression(this.index, e, true);
          }
          
          return super.createExpression(e);
      }
  
      /**
       * called by BasicExpressionCompiler after construction.
       *
       * @param    query               the associated BasicQuery
       * @param    propertyProvider    the PropertyProvider for this expression.
       *
       * @throws   BadQueryException
       *
       */
      public void init(IBasicQuery query, PropertyProvider propertyProvider)
          throws BadQueryException
      {
          this.query = (IBasicQuery) query;
          this.propertyProvider = propertyProvider;
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/LucenePropertiesIndexer.java
  
  Index: LucenePropertiesIndexer.java
  ===================================================================
  /*
   *
   * ====================================================================
   *
   * Copyright 2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  
  package org.apache.slide.index.lucene;
  
  import java.io.IOException;
  import java.text.MessageFormat;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Date;
  import java.util.Enumeration;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Hashtable;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Set;
  import java.util.StringTokenizer;
  
  import javax.transaction.xa.XAException;
  import javax.transaction.xa.XAResource;
  import javax.transaction.xa.Xid;
  
  import org.apache.commons.transaction.util.LoggerFacade;
  import org.apache.commons.transaction.util.xa.AbstractTransactionalResource;
  import org.apache.commons.transaction.util.xa.AbstractXAResource;
  import org.apache.commons.transaction.util.xa.TransactionalResource;
  
  import org.apache.lucene.analysis.Analyzer;
  import org.apache.lucene.analysis.standard.StandardAnalyzer;
  import org.apache.lucene.document.Document;
  import org.apache.lucene.document.Field;
  
  import org.apache.slide.common.AbstractServiceBase;
  import org.apache.slide.common.NamespaceAccessToken;
  import org.apache.slide.common.ServiceAccessException;
  import org.apache.slide.common.ServiceConnectionFailedException;
  import org.apache.slide.common.ServiceDisconnectionFailedException;
  import org.apache.slide.common.ServiceInitializationFailedException;
  import org.apache.slide.common.ServiceParameterErrorException;
  import org.apache.slide.common.ServiceParameterMissingException;
  import org.apache.slide.common.ServiceResetFailedException;
  import org.apache.slide.common.Uri;
  import org.apache.slide.content.NodeProperty;
  import org.apache.slide.content.NodeRevisionContent;
  import org.apache.slide.content.NodeRevisionDescriptor;
  import org.apache.slide.content.NodeRevisionNumber;
  import org.apache.slide.search.IndexException;
  import org.apache.slide.search.basic.IBasicExpressionFactory;
  import org.apache.slide.store.IndexStore;
  import org.apache.slide.util.logger.Logger;
  import org.apache.slide.util.logger.TxLogger;
  
  /**
   * IndexStore implementation for indexing properties based on Jakarta Lucene.
   */
  public class LucenePropertiesIndexer extends AbstractServiceBase implements
          IndexStore
  {
  
      private static final String LOG_CHANNEL = LucenePropertiesIndexer.class
              .getName();
  
      private static final String INDEX_PATH = "indexpath";
  
      private static final String INCLUDES = "includes";
  
      private static final String ANALYZER = "analyzer";
  
      public static final String URI_FIELD = "uri";
  
      public static final String CONTENT_TEXT = "content";
  
      //------------------
  
      private String indexpath = "";
  
      private Collection includes;
  
      private String analyzerClassName;
  
      private boolean started = false;
  
      protected Index index = null;
  
      private XAResourceImpl xaResource = null;
  
      /**
       * Create Index, if not yet done.
       * 
       * @param token
       *           a NamespaceAccessToken
       * 
       * @throws org.apache.slide.common.ServiceInitializationFailedException
       *  
       */
      public void initialize(NamespaceAccessToken token)
              throws ServiceInitializationFailedException
      {
          debug("initialize");
  
          TxLogger txLogger = new TxLogger(getLogger(), LOG_CHANNEL);
          this.xaResource = new XAResourceImpl(txLogger);
          
          try {
              this.index = new Index(this.indexpath, initAnalyzer(), getLogger());
          } 
          catch (org.apache.slide.index.lucene.IndexException e) {
              throw new ServiceInitializationFailedException(this, e);
          }
      }
  
      /**
       * Index an object content.
       * 
       * @param uri
       *           Uri
       * @exception IndexException
       *               Error accessing the Data Source
       */
      public void createIndex(Uri uri,
              NodeRevisionDescriptor revisionDescriptor,
              NodeRevisionContent revisionContent) throws IndexException
      {
          debug("createIndex {0} {1}", uri, revisionDescriptor.getRevisionNumber());
          
          TransactionalIndexResource indexResource = xaResource.getCurrentTxn();
          
          Document doc = createLuceneDocument(uri, revisionDescriptor);
          
          indexResource.addIndexJob(uri, 
                  revisionDescriptor.getRevisionNumber(), doc);
          
      }
  
      /**
       * Method updateIndex
       * 
       * @param uri
       *           an Uri
       * @param revisionDescriptor
       *           a NodeRevisionDescriptor
       * @param revisionContent
       *           a NodeRevisionContent
       * 
       * @throws IndexException
       *  
       */
      public void updateIndex(Uri uri,
              NodeRevisionDescriptor revisionDescriptor,
              NodeRevisionContent revisionContent) throws IndexException
      {
          debug("updateIndex {0} {1}", uri, revisionDescriptor
                  .getRevisionNumber());
  
          boolean needsUpdate = false;
          for(Enumeration e = revisionDescriptor.enumerateUpdatedProperties();e.hasMoreElements();) {
              NodeProperty property = (NodeProperty)e.nextElement();
              if(index.getConfiguration().isIndexedProperty(property)) {
                  needsUpdate = true; 
                  break;
              }
          }
          for(Enumeration e = revisionDescriptor.enumerateUpdatedProperties();!needsUpdate && e.hasMoreElements();) {
              NodeProperty property = (NodeProperty)e.nextElement();
              if(index.getConfiguration().isIndexedProperty(property)) {
                  needsUpdate = true; 
                  break;
              }
          }
          
          if (needsUpdate) {
              TransactionalIndexResource indexResource = xaResource.getCurrentTxn();
              
              Document doc = createLuceneDocument(uri, revisionDescriptor);
              
              indexResource.addRemoveJob(uri, revisionDescriptor.getRevisionNumber());
              indexResource.addIndexJob(uri, revisionDescriptor.getRevisionNumber(), doc);
          }
      }
  
      /**
       * Drop an object revision from the index.
       * 
       * @param uri
       *           Uri
       * @exception IndexException
       */
      public void dropIndex(Uri uri, NodeRevisionNumber number)
              throws IndexException
      {
          debug("dropIndex {0} {1}", uri, number);
  
          TransactionalIndexResource indexResource = xaResource.getCurrentTxn();
          
          indexResource.addRemoveJob(uri, number);
      }
  
      private Field unstoredString(String fieldName, String value) {
          return new Field(fieldName, value, false, true, false);
      }
      private Field storedString(String fieldName, String value) {
          return new Field(fieldName, value, true, true, false);
      }
      private Document createLuceneDocument(Uri uri, NodeRevisionDescriptor descriptor) {
          
          Document doc = new Document();
          
          IndexConfiguration config = index.getConfiguration();
          
          doc.add(unstoredString(Index.KEY_FIELD_NAME, 
                  config.generateKey(uri, descriptor.getRevisionNumber())));
          doc.add(storedString(Index.URI_FIELD_NAME, uri.toString()));
          for(Enumeration e = uri.getScopes(); e.hasMoreElements();) {
              doc.add(unstoredString(Index.SCOPE_FIELD_NAME, e.nextElement().toString()));
          }
          
          doc.add(unstoredString(Index.VERSION_FIELD_NAME, 
                  descriptor.getRevisionNumber().toString()));
          
          String rtype = descriptor.getResourceType();
          if (rtype.indexOf("collection") != -1) {
              doc.add(unstoredString(config.generateFieldName(
                  NodeProperty.DEFAULT_NAMESPACE, "resourcetype"), 
                  "collection"));
              if (rtype.indexOf("principal") != -1) {
                  doc.add(unstoredString(config.generateFieldName(
                      NodeProperty.DEFAULT_NAMESPACE, "resourcetype"), 
                      "principal"));
              }
          }
          
          for(Enumeration e = descriptor.enumerateProperties(); e.hasMoreElements();) {
              NodeProperty property = (NodeProperty)e.nextElement();
              Object value = property.getValue();
              
              if (value == null) continue;
              
              if (config.isKeywordProperty(property)) {
                  doc.add(unstoredString(config.generateFieldName(property), value.toString()));
              }
              if (config.isDateProperty(property)) {
                  Date date = config.getDateValue(value);
                  if (date != null) {
                      doc.add(unstoredString(config.generateFieldName(property), 
                              config.dateToIndexString(date)));
                  }
              }
              if (config.isIntProperty(property)) {
                  try {
                      doc.add(unstoredString(config.generateFieldName(property),
                              config.intToIndexString(Long.parseLong(value.toString()))));
                  } catch (NumberFormatException ex)  {
                      // TODO log warning
                  }
              }
              if (config.supportsIsDefined(property)) {
                  doc.add(unstoredString(Index.IS_DEFINED_FIELD_NAME, 
                          config.generateFieldName(property)));
              }
          }
          
          return doc;
      }
      
      
      
      
      /**
       * Method getFactory
       * 
       * @return an IBasicExpressionFactory
       *  
       */
      public IBasicExpressionFactory getBasicExpressionFactory()
      {
          return new LuceneExpressionFactory(this.index);
      }
  
      /**
       * Connects to the underlying data source (if any is needed).
       * 
       * @exception ServiceConnectionFailedException
       *               Connection failed
       */
      public void connect() throws ServiceConnectionFailedException
      {
          debug("connect");
          started = true;
      }
  
      /**
       * This function tells whether or not the service is connected.
       * 
       * @return boolean true if we are connected
       * @exception ServiceAccessException
       *               Service access error
       */
      public boolean isConnected() throws ServiceAccessException
      {
          return started;
      }
  
      /**
       * Parametrize the service. This index store expects a parameter
       * "indexpath" to contain the path to the directory to store the index.
       * Another optional parameter "includes" lists the paths of resources that
       * are to be indexed in a comma-separated format. Everything under an
       * included path is indexed. If not specified all resources will be
       * indexed.
       * 
       * @param parameters
       *           Hashtable containing the parameters' names and associated
       *           values
       * @exception ServiceParameterErrorException
       *               Incorrect service parameter
       * @exception ServiceParameterMissingException
       *               Service parameter missing
       */
      public void setParameters(Hashtable parameters)
              throws ServiceParameterErrorException,
              ServiceParameterMissingException
      {
          indexpath = (String) parameters.get(INDEX_PATH);
          if (indexpath == null || indexpath.length() == 0) {
              throw new ServiceParameterMissingException(this, INDEX_PATH);
          }
          String includes = (String) parameters.get(INCLUDES);
          if (includes != null && includes.length() > 0) {
              StringTokenizer tokenizer = new StringTokenizer(includes, ",");
              this.includes = new ArrayList(tokenizer.countTokens());
              while (tokenizer.hasMoreTokens()) {
                  this.includes.add(tokenizer.nextToken());
              }
          }
          analyzerClassName = (String) parameters.get(ANALYZER);
      }
  
      /**
       * Disconnects from the underlying data source.
       * 
       * @exception ServiceDisconnectionFailedException
       *               Disconnection failed
       */
      public void disconnect() throws ServiceDisconnectionFailedException
      {
          debug("disconnect");
          started = false;
      }
  
      /**
       * Deletes service underlying data source, if possible (and meaningful).
       * 
       * @exception ServiceResetFailedException
       *               Reset failed
       */
      public void reset() throws ServiceResetFailedException
      {
          debug("reset");
      }
  
      protected Enumeration readProperties(
              NodeRevisionDescriptor revisionDescriptor,
              NodeRevisionContent revisionContent) throws IOException
      {
          Enumeration em = revisionDescriptor.enumerateProperties();
          return em;
  
      }
  
      protected boolean isIncluded(String uri)
      {
          if (includes == null)
              return true;
          Iterator iter = includes.iterator();
          while (iter.hasNext()) {
              if (uri.startsWith((String) iter.next())) {
                  return true;
              }
          }
          return false;
      }
  
      protected Analyzer initAnalyzer() throws ServiceInitializationFailedException
      {
  
          if (analyzerClassName == null || analyzerClassName.length() == 0) {
              info("using Lucene StandardAnalyzer");
              return new StandardAnalyzer();
  
          } else {
              info("using Lucene analyzer: {0}", analyzerClassName);
  
              try {
                  Class analyzerClazz = Class.forName(analyzerClassName);
                  return (Analyzer) analyzerClazz.newInstance();
  
              } catch (ClassNotFoundException e) {
                  error("Error while instantiating analyzer {0} {1}",
                                  analyzerClassName, e.getMessage());
                  throw new ServiceInitializationFailedException(this, e);
  
              } catch (InstantiationException e) {
                  error("Error while instantiating analyzer {0} {1}",
                                  analyzerClassName, e.getMessage());
                  throw new ServiceInitializationFailedException(this, e);
  
              } catch (IllegalAccessException e) {
                  error("Error while instantiating analyzer {0} {1}",
                          analyzerClassName, e.getMessage());
                  throw new ServiceInitializationFailedException(this, e);
              }
          }
      }
  
      // -------------------------------------------------------------------------
      // XAResource interface, all request are deletgated to this.xaResource
  
      public void commit(Xid xid, boolean onePhase) throws XAException
      {
          this.xaResource.commit(xid, onePhase);
      }
  
      public void end(Xid xid, int flags) throws XAException
      {
          this.xaResource.end(xid, flags);
      }
  
      public void forget(Xid xid) throws XAException
      {
          this.xaResource.forget(xid);
      }
  
      public int getTransactionTimeout() throws XAException
      {
          return this.xaResource.getTransactionTimeout();
      }
  
      public boolean isSameRM(XAResource xares) throws XAException
      {
          return this.xaResource != null && this.xaResource.isSameRM(xares); // ??
      }
  
      public int prepare(Xid xid) throws XAException
      {
          return this.xaResource.prepare(xid);
      }
  
      public Xid[] recover(int flag) throws XAException
      {
          return this.xaResource.recover(flag);
      }
  
      public void rollback(Xid xid) throws XAException
      {
          this.xaResource.rollback(xid);
      }
  
      public boolean setTransactionTimeout(int sec) throws XAException
      {
          return this.xaResource.setTransactionTimeout(sec);
      }
  
      public void start(Xid xid, int flags) throws XAException
      {
          this.xaResource.start(xid, flags);
      }
      
      
  
      private class XAResourceImpl extends AbstractXAResource
      {
  
          private LoggerFacade loggerFacade;
  
          XAResourceImpl(LoggerFacade loggerFacade)
          {
              this.loggerFacade = loggerFacade;
          }
  
          protected TransactionalResource createTransactionResource(Xid xid)
                  throws Exception
          {
              return new TransactionalIndexResource(xid, index);
          }
          
          TransactionalIndexResource getCurrentTxn() {
              return (TransactionalIndexResource)getCurrentlyActiveTransactionalResource();
          }
  
          protected LoggerFacade getLoggerFacade()
          {
              return this.loggerFacade;
          }
  
          protected boolean includeBranchInXid()
          {
              return true;
          }
  
          public boolean isSameRM(XAResource xares) throws XAException
          {
              return xares == this;
          }
  
          public Xid[] recover(int flag) throws XAException
          {
              // TODO Auto-generated method stub
              return null;
          }
  
          public int getTransactionTimeout() throws XAException
          {
              return 0;
          }
  
          public boolean setTransactionTimeout(int seconds) throws XAException
          {
              return false;
          }
      }
  
      private static class TransactionalIndexResource extends
              AbstractTransactionalResource
      {
          private Index idx;
          private Map indexJobs = new HashMap();
          private Set removeJobs = new HashSet();
  
          TransactionalIndexResource(Xid xid, Index index)
          {
              super(xid);
              this.idx = index;
          }
          
          void addIndexJob(Uri uri, NodeRevisionNumber version, Document doc) {
              String key = idx.getConfiguration().generateKey(uri, version);
              this.indexJobs.put(key, doc);
          }
          void addRemoveJob(Uri uri, NodeRevisionNumber version) {
              String key = idx.getConfiguration().generateKey(uri, version);
              this.indexJobs.remove(key);
              this.removeJobs.add(key);
          }
  
          public void begin() throws XAException
          {
          }
  
          public void commit() throws XAException
          {
              try {
                  this.idx.addIndexJob(this.indexJobs, this.removeJobs);
              } catch (IOException e) {
                  throw new XAException(e.toString());
              }
          }
  
          public int prepare() throws XAException
          {
              return 0;
          }
  
          public void resume() throws XAException
          {
          }
  
          public void rollback() throws XAException
          {
          }
  
          public void suspend() throws XAException
          {
          }
      }
  
      void info(String msg)
      {
          if (this.getLogger().isEnabled(Logger.INFO)) {
              this.getLogger().log(msg, LOG_CHANNEL, Logger.INFO);
          }
      }
  
      void info(String msg, Object o)
      {
          if (this.getLogger().isEnabled(Logger.INFO)) {
              Object[] args = { o};
              this.getLogger().log(MessageFormat.format(msg, args), LOG_CHANNEL,
                      Logger.INFO);
          }
      }
  
      void debug(String msg)
      {
          if (this.getLogger().isEnabled(Logger.DEBUG)) {
              this.getLogger().log(msg, LOG_CHANNEL, Logger.DEBUG);
          }
      }
  
      void debug(String msg, Object o1, Object o2)
      {
          if (this.getLogger().isEnabled(Logger.DEBUG)) {
              Object[] args = { o1, o2};
              this.getLogger().log(MessageFormat.format(msg, args), LOG_CHANNEL,
                      Logger.DEBUG);
          }
      }
  
      void error(String msg, Object o1)
      {
          if (this.getLogger().isEnabled(Logger.ERROR)) {
              Object[] args = { o1};
              this.getLogger().log(MessageFormat.format(msg, args), LOG_CHANNEL,
                      Logger.ERROR);
          }
      }
      void error(String msg, Object o1, Object o2)
      {
          if (this.getLogger().isEnabled(Logger.ERROR)) {
              Object[] args = { o1, o2};
              this.getLogger().log(MessageFormat.format(msg, args), LOG_CHANNEL,
                      Logger.ERROR);
          }
      }
  }
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/AbstractExpression.java
  
  Index: AbstractExpression.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/AbstractExpression.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene.expressions;
  
  import java.io.IOException;
  import java.util.List;
  
  import org.apache.lucene.document.Document;
  import org.apache.lucene.index.Term;
  import org.apache.lucene.search.BooleanQuery;
  import org.apache.lucene.search.Hits;
  import org.apache.lucene.search.IndexSearcher;
  import org.apache.lucene.search.Query;
  import org.apache.lucene.search.TermQuery;
  
  import org.apache.slide.common.SlideException;
  import org.apache.slide.content.NodeProperty;
  import org.apache.slide.index.lucene.Index;
  import org.apache.slide.search.BadQueryException;
  import org.apache.slide.search.InvalidScopeException;
  import org.apache.slide.search.RequestedResource;
  import org.apache.slide.search.SearchException;
  import org.apache.slide.search.basic.BasicResultSetImpl;
  import org.apache.slide.search.basic.ComparableResourceImpl;
  import org.apache.slide.search.basic.IBasicExpression;
  import org.apache.slide.search.basic.IBasicExpressionFactory;
  import org.apache.slide.search.basic.IBasicQuery;
  import org.apache.slide.search.basic.IBasicResultSet;
  import org.apache.slide.structure.ObjectNode;
  import org.apache.slide.structure.SubjectNode;
  import org.apache.slide.util.logger.Logger;
  import org.jdom.Element;
  
  
  /**
   * @author Stefan L�tzkendorf
   */
  public abstract class AbstractExpression implements IBasicExpression
  {
  
      static final String LOG_CHANNEL = "org.apache.slide.index.lucene.expressions";
      
      protected IBasicExpressionFactory factory;
      protected Index index;
      
      private Query query;
      
      public AbstractExpression(Index index) {
          this.index = index;
      }
  
      protected final void setQuery(Query query) {
          this.query = query;
      }
      protected final Query getQuery() {
          return this.query;
      }
  
      public IBasicExpressionFactory getFactory()
      {
          return factory;
      }
  
      public void setFactory(IBasicExpressionFactory factory)
      {
          this.factory = factory;
      }
  
      
      public IBasicResultSet execute() throws SearchException
      {
          Query luceneQuery = this.getQuery();
          
          IBasicQuery q = factory.getQuery();
          String scope = q.getSearchToken().getSlideContext().getSlidePath(q.getScope().getHref());
  
          if (!scope.equals("/")) {
              // add a scope restriction
              BooleanQuery booleanQuery = new BooleanQuery();
              booleanQuery.add(luceneQuery, true, false);
              booleanQuery.add(new TermQuery(new Term(Index.SCOPE_FIELD_NAME, scope)), true, false);
              luceneQuery = booleanQuery;
          }
  
          IndexSearcher searcher = null;
          try {
              index.getLogger().log("start query execution: " + luceneQuery.toString(), LOG_CHANNEL, Logger.DEBUG);
              long start = System.currentTimeMillis();
      
              searcher = this.index.getSearcher();
              Hits hits = searcher.search(luceneQuery);
              
              index.getLogger().log("finished: " + hits.length() + " hits (" + 
                      (System.currentTimeMillis() - start) + "s)" , LOG_CHANNEL, Logger.DEBUG);
  
              IBasicResultSet result = new BasicResultSetImpl(false);
  
              for (int i = 0, l = hits.length(); i < l; i++) {
                  Document doc = hits.doc(i);
                  String uri = doc.get(Index.URI_FIELD_NAME);
                  RequestedResource resource = createResource(uri);
                  result.add(resource);
              }
              
              return result;
          } catch (InvalidScopeException e) {
              throw e;
          } catch (SearchException e) {
              throw e;
          } catch (IOException e) {
              throw new SearchException(e);
          } finally {
              if (searcher != null) {
                  try {
                      searcher.close();
                  } catch (IOException e1) {
                      // ignore
                  }
              }
          }
      }
      
      protected Query getNegatedQuery(Query query) {
          BooleanQuery booleanQuery = new BooleanQuery();
          booleanQuery.add(
                  new TermQuery(new Term(Index.SCOPE_FIELD_NAME, "/")), 
                  true, false);
          booleanQuery.add(
                  query, 
                  false, true);
          return booleanQuery;
      }
  
      protected RequestedResource createResource(String uri) throws SearchException
      {
          ObjectNode node = new SubjectNode(uri); // this will return the root
                                                  // folder
          RequestedResource resource = null;
          IBasicQuery query = factory.getQuery();
          
          try {
              resource = new ComparableResourceImpl(node, query.getSearchToken(),
                      query.getScope(), factory.getPropertyProvider());
          } catch (SlideException e) {
              throw new SearchException(e);
          }
          return resource;
      }
  
      protected static Element getFirstElement(Element node)
      {
          List children = node.getChildren();
          
          for (int i = 0; i < children.size(); i++) {
              if (children.get(i) instanceof Element) {
                  return (Element)children.get(i); 
              }
          }
          return null;
      }
      
      /**
       * Returns the first <code>D:prop</code> element. 
       * @param operator
       * @return Element 
       * @throws BadQueryException if element not found
       */
      public static Element getPropertyElement(Element operator) throws BadQueryException
      {
          Element prop = operator.getChild("prop", 
                  NodeProperty.NamespaceCache.DEFAULT_NAMESPACE);
          if (prop == null) throw new BadQueryException("Missing prop element"); 
          
          prop = getFirstElement(prop);
          if (prop == null) throw new BadQueryException("Empty prop element given");
          return prop;
      }
      /**
       * Retruns the first <code>D:literal</code> element.
       * @param operator
       * @return
       * @throws BadQueryException if element not found
       */
      protected Element getLiteralElement(Element operator) throws BadQueryException
      {
          Element literal = operator.getChild("literal", 
                  NodeProperty.NamespaceCache.DEFAULT_NAMESPACE);
          if (literal == null) throw new BadQueryException("Missing literal element");
          return literal;
      }    
  
      protected Element getLiteral2Element(Element operator) throws BadQueryException
      {
          List children = operator.getChildren("literal", 
                  NodeProperty.NamespaceCache.DEFAULT_NAMESPACE);
          if (children.size() > 1) {
              return (Element)children.get(1);
          } else {
              throw new BadQueryException("Missing second literal element");
          }
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/BetweenExpression.java
  
  Index: BetweenExpression.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/BetweenExpression.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene.expressions;
  
  import org.apache.lucene.index.Term;
  import org.apache.lucene.search.RangeQuery;
  import org.apache.lucene.search.TermQuery;
  
  import org.apache.slide.index.lucene.Index;
  import org.apache.slide.index.lucene.IndexConfiguration;
  import org.apache.slide.search.BadQueryException;
  import org.jdom.Element;
  
  
  /**
   * Implements a slide specific <code>between</code> operator.
   * 
   * <p>
   * With lucene <code>(between prop val1 val2)</code> will be much more efficient 
   * than <code>(and (gt prop1 val1) (lt prop val2))</code>.
   * 
   * <p>TODO May be could optimize such expressions by transformation.   
   * 
   * <p>Usage:
   * <pre>
   *  &lt;searchrequest xmlns:D="DAV:" xmlns:S="http://jakarta.apache.org/slide/"> 
   *  &lt;S:between>
   *    &lt;D:prop>&lt;D:getlastmodified/>&lt;/D:prop>
   *    &lt;D:literal>Fri, 14 Oct 2004 10:00:00 GMT&lt;/D:literal>
   *    &lt;D:literal>Fri, 15 Oct 2004 10:00:00 GMT&lt;/D:literal>
   *  &lt;/S:between>
   * </pre>
   */
  public class BetweenExpression extends AbstractExpression
  {
  
      public BetweenExpression(Index index, Element element, boolean inclusive)
          throws BadQueryException
      {
          super(index);
          
          IndexConfiguration config = index.getConfiguration();
          Element prop = getPropertyElement(element);
          String field = config.generateFieldName(prop);
          Element literal1 = getLiteralElement(element);
          Element literal2 = getLiteral2Element(element);
  
          String value1;
          String value2;
          if (index.getConfiguration().isDateProperty(prop)) {
              value1 = config.dateToIndexString(
                      config.getDateValue(literal1.getTextTrim()));
              value2 = config.dateToIndexString(
                      config.getDateValue(literal2.getTextTrim()));
          } 
          else if (index.getConfiguration().isIntProperty(prop)) { 
              value1 = config.intToIndexString(Long.parseLong(literal1.getTextTrim()));
              value2 = config.intToIndexString(Long.parseLong(literal2.getTextTrim()));
          } 
          else {
              value1 = literal1.getTextTrim();
              value2 = literal2.getTextTrim();
          }
          
          int comp =  value1.compareTo(value2);
  
          if (comp == 0) {
              // value1 == value2
              setQuery(new TermQuery(new Term(field, value1)));
          } else if (comp < 0) {
              // value1 < value2
              setQuery(new RangeQuery(
                      new Term(field, value1),
                      new Term(field, value2),
                      inclusive)); // inclusive or not 
          } else {
              // value1 > value2
              setQuery(new RangeQuery(
                      new Term(field, value2),
                      new Term(field, value1),
                      inclusive)); // inclusive or not 
          }
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/EqExpression.java
  
  Index: EqExpression.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/EqExpression.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene.expressions;
  
  import org.apache.lucene.index.Term;
  import org.apache.lucene.search.TermQuery;
  
  import org.apache.slide.index.lucene.Index;
  import org.apache.slide.index.lucene.IndexConfiguration;
  import org.apache.slide.search.BadQueryException;
  import org.jdom.Element;
  
  /**
   * Implements <code>eq</code> and <code>not-eq</code>.
   */
  public class EqExpression extends AbstractExpression
  {
  
      public EqExpression(Index index, Element element, boolean negated)
          throws BadQueryException
      {
          super(index);
          
          IndexConfiguration config = index.getConfiguration();
          Element prop = getPropertyElement(element);
          String field = config.generateFieldName(prop);
          Element literal = getLiteralElement(element);
  
          String value;
          if (index.getConfiguration().isDateProperty(prop)) {
              value = config.dateToIndexString(config.getDateValue(literal.getTextTrim()));
          } 
          else if (index.getConfiguration().isIntProperty(prop)) { 
              value = config.intToIndexString(Long.parseLong(literal.getTextTrim()));
          } 
          else {
              value = literal.getTextTrim();
          }
          
          Term term = new Term(field, value);
          
          setQuery(new TermQuery(term));
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/GtExpression.java
  
  Index: GtExpression.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/GtExpression.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene.expressions;
  
  import java.util.Date;
  
  import org.apache.lucene.index.Term;
  import org.apache.lucene.search.RangeQuery;
  
  import org.apache.slide.index.lucene.Index;
  import org.apache.slide.index.lucene.IndexConfiguration;
  import org.apache.slide.search.BadQueryException;
  import org.jdom.Element;
  
  /**
   * Implements <code>gt</code> and <code>gte</code> expression.
   */
  public class GtExpression extends AbstractExpression
  {
      public GtExpression(Index index, Element element, boolean inclusive) 
          throws BadQueryException 
      {
          super(index);
  
          IndexConfiguration config = index.getConfiguration();
          Element prop = getPropertyElement(element);
          String field = config.generateFieldName(prop);
          Element literal = getLiteralElement(element);
  
          String value;
          String upperBound;
          if (index.getConfiguration().isDateProperty(prop)) {
              Date date = config.getDateValue(literal.getTextTrim());
              value = config.dateToIndexString(date);
              upperBound = Index.DATE_UPPER_BOUND;
          } 
          else if (index.getConfiguration().isIntProperty(prop)) { 
              value = config.intToIndexString(Long.parseLong(literal.getTextTrim()));
              upperBound = Index.INT_UPPER_BOUND;
          } 
          else {
              value = literal.getTextTrim();
              upperBound = "ZZZZZZZZ"; //TODO
          }
          
          
          RangeQuery rangeQuery = new RangeQuery(
                  new Term(field, value),
                  new Term(field, upperBound),
                  inclusive); // inclusive or not 
          
          setQuery(rangeQuery);
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/IsCollectionExpression.java
  
  Index: IsCollectionExpression.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/IsCollectionExpression.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene.expressions;
  
  import org.apache.lucene.index.Term;
  import org.apache.lucene.search.TermQuery;
  
  import org.apache.slide.content.NodeProperty;
  import org.apache.slide.index.lucene.Index;
  import org.apache.slide.index.lucene.IndexConfiguration;
  
  /**
   * Implements the <code>is-collection</code> and the <code>not-is-collection</code>
   * expression. 
   */
  public class IsCollectionExpression extends AbstractExpression
  {
      public IsCollectionExpression(Index index, boolean negated)
      {
          super(index);
          
          IndexConfiguration config = index.getConfiguration();
          setQuery(new TermQuery(new Term(config.generateFieldName(
                  NodeProperty.DEFAULT_NAMESPACE, "resourcetype"),
                  "collection")));
          
          if (negated) {
              setQuery(getNegatedQuery(getQuery()));
          }
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/IsDefinedExpression.java
  
  Index: IsDefinedExpression.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/IsDefinedExpression.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene.expressions;
  
  import org.apache.lucene.index.Term;
  import org.apache.lucene.search.TermQuery;
  
  import org.apache.slide.index.lucene.Index;
  import org.apache.slide.index.lucene.IndexConfiguration;
  import org.apache.slide.search.BadQueryException;
  import org.jdom.Element;
  
  
  /**
   * @author Stefan L�tzkendorf
   */
  public class IsDefinedExpression extends AbstractExpression
  {
  
      public IsDefinedExpression(Index index, Element element, boolean negated) 
          throws BadQueryException
      {
          super(index);
  
          IndexConfiguration config = index.getConfiguration();
          Element prop = getPropertyElement(element);
          String field = config.generateFieldName(prop);
          
          
          if (config.supportsIsDefined(prop)) {
              setQuery(new TermQuery(new Term(Index.IS_DEFINED_FIELD_NAME, field)));
          }
          
          if (negated) {
              setQuery(getNegatedQuery(getQuery()));
          }
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/IsPrincipalExpression.java
  
  Index: IsPrincipalExpression.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/IsPrincipalExpression.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene.expressions;
  
  import org.apache.lucene.index.Term;
  import org.apache.lucene.search.TermQuery;
  
  import org.apache.slide.content.NodeProperty;
  import org.apache.slide.index.lucene.Index;
  import org.apache.slide.index.lucene.IndexConfiguration;
  
  /**
   * Implements the <code>is-pricipal</code> and the <code>not-is-pricipal</code>
   * expression. 
   */
  public class IsPrincipalExpression extends AbstractExpression
  {
      public IsPrincipalExpression(Index index, boolean negated)
      {
          super(index);
          
          IndexConfiguration config = index.getConfiguration();
          setQuery(new TermQuery(new Term(config.generateFieldName(
                  NodeProperty.DEFAULT_NAMESPACE, "resourcetype"),
                  "principal")));
          
          if (negated) {
              setQuery(getNegatedQuery(getQuery()));
          }
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/LikeExpression.java
  
  Index: LikeExpression.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/LikeExpression.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene.expressions;
  
  import org.apache.lucene.index.Term;
  import org.apache.lucene.search.PrefixQuery;
  import org.apache.lucene.search.WildcardQuery;
  import org.apache.lucene.search.WildcardTermEnum;
  
  import org.apache.slide.index.lucene.Index;
  import org.apache.slide.index.lucene.IndexConfiguration;
  import org.apache.slide.search.BadQueryException;
  import org.jdom.Element;
  
  
  /**
   * Implements the <code>like</code> operator.
   * 
   */
  public class LikeExpression extends AbstractExpression
  {
  
      public LikeExpression(Index index, Element element) throws BadQueryException
      {
          super(index);
          
          IndexConfiguration config = index.getConfiguration();
          Element prop = getPropertyElement(element);
          String field = config.generateFieldName(prop);
          Element literal = getLiteralElement(element);
          String text = literal.getTextTrim();
          
          // TODO check what to do with Date or Int fields
          
          if (text.indexOf('_') == -1 && text.indexOf('%') == text.length()-1) {
              // some thing line "apple%"
              setQuery(new PrefixQuery(new Term(field, 
                      text.substring(0, text.length()-1))));
          } else {
              setQuery(new WildcardQuery(new Term(field, 
                      transformQuerytext(text))));
          }
      }
      
      private String transformQuerytext(String text)
              throws BadQueryException
      {
          
          StringBuffer result = new StringBuffer(text.length());
          
          for(int i = 0, l = text.length(); i<l; i++) {
              char c = text.charAt(i);
              switch(c) {
                  case '%':
                      result.append(WildcardTermEnum.WILDCARD_STRING);
                      break;
                  case '_':
                      result.append(WildcardTermEnum.WILDCARD_CHAR);
                      break;
                  default:
                      result.append(c);
              }
          }
          
          return result.toString();
      }
      
      public static void main(String[] a) {
          System.out.println("abc".indexOf("c"));
          System.out.println("abc".substring(0, "abc".length()-1));
      }
  
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/LtExpression.java
  
  Index: LtExpression.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/LtExpression.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene.expressions;
  
  import java.util.Calendar;
  import java.util.Date;
  
  import org.apache.lucene.index.Term;
  import org.apache.lucene.search.RangeQuery;
  
  import org.apache.slide.index.lucene.Index;
  import org.apache.slide.index.lucene.IndexConfiguration;
  import org.apache.slide.search.BadQueryException;
  import org.jdom.Element;
  
  /**
   * Implements <code>lt</code> and <code>lte</code> expression.
   */
  public class LtExpression extends AbstractExpression
  {
      
      public LtExpression(Index index, Element element, boolean inclusive) 
          throws BadQueryException 
      {
          super(index);
  
          IndexConfiguration config = index.getConfiguration();
          Element prop = getPropertyElement(element);
          String field = config.generateFieldName(prop);
          Element literal = getLiteralElement(element);
  
          String value;
          String lowerBound;
          if (index.getConfiguration().isDateProperty(prop)) {
              Date date = config.getDateValue(literal.getTextTrim());
              Calendar c = Calendar.getInstance();
              c.setTime(date);
              inclusive =  c.get(Calendar.SECOND) > 0;
              value = config.dateToIndexString(date);
              lowerBound = Index.DATE_LOWER_BOUND;
          } 
          else if (index.getConfiguration().isIntProperty(prop)) { 
              value = config.intToIndexString(Long.parseLong(literal.getTextTrim()));
              lowerBound = Index.INT_LOWER_BOUND;
          } 
          else {
              value = literal.getTextTrim();
              lowerBound = ""; //TODO
          }
          
          
          RangeQuery rangeQuery = new RangeQuery(
                  new Term(field, lowerBound),
                  new Term(field, value),
                  inclusive); // inclusive or not
          
          setQuery(rangeQuery);
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/MergeExpression.java
  
  Index: MergeExpression.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/MergeExpression.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene.expressions;
  
  import java.util.Collection;
  import java.util.Iterator;
  
  import org.apache.lucene.search.BooleanQuery;
  import org.apache.lucene.search.Query;
  
  import org.apache.slide.index.lucene.Index;
  
  
  /**
   * Implements <code>and</code> and <code>or</code>.
   */
  public class MergeExpression extends AbstractExpression
  {
      /**
       * Constructor.
       * @param index The index to be searched.
       * @param and <code>true</code> if AND or <code>false</code> if OR
       * @param expressions list of expressions
       */
      public MergeExpression(Index index, boolean and, Collection expressions)
      {
          super(index);
          
          if (expressions.size() > 0) {
              BooleanQuery booleanQuery = new BooleanQuery();
              
              for(Iterator i = expressions.iterator(); i.hasNext();) {
                  Object e = i.next();
                  if (e instanceof AbstractExpression) {
                      Query q = ((AbstractExpression)e).getQuery();
                      booleanQuery.add(q, and, false);
                  } else {
                      // TODO
                      System.out.println("merge with non lucene expression");
                  }
              }
              
              setQuery(booleanQuery);
          } else {
              // TODO
              System.out.println("merge without expressions");
          }
      }
  }
  
  
  
  1.1                  jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/PropcontainsExpression.java
  
  Index: PropcontainsExpression.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-slide/src/stores/org/apache/slide/index/lucene/expressions/PropcontainsExpression.java,v 1.1 2004/10/18 09:27:36 luetzkendorf Exp $
   * $Revision: 1.1 $
   * $Date: 2004/10/18 09:27:36 $
   *
   * ====================================================================
   *
   * Copyright 1999-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.index.lucene.expressions;
  
  import org.apache.lucene.index.Term;
  import org.apache.lucene.search.WildcardQuery;
  
  import org.apache.slide.index.lucene.Index;
  import org.apache.slide.index.lucene.IndexConfiguration;
  import org.apache.slide.search.BadQueryException;
  import org.jdom.Element;
  
  
  /**
   * Implements the <code>propcontains</code> operator.
   * 
   */
  public class PropcontainsExpression extends AbstractExpression
  {
  
      public PropcontainsExpression(Index index, Element element) throws BadQueryException
      {
          super(index);
          
          IndexConfiguration config = index.getConfiguration();
          Element prop = getPropertyElement(element);
          String field = config.generateFieldName(prop);
          Element literal = getLiteralElement(element);
          String text = literal.getTextTrim();
          
          setQuery(new WildcardQuery(new Term(field, "*" + text + "*")));
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: slide-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: slide-dev-help@jakarta.apache.org