lucene-java-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From yo...@apache.org
Subject svn commit: r430568 [2/8] - in /lucene/java/trunk/contrib/gdata-server: ./ lib/ src/java/org/apache/lucene/gdata/data/ src/java/org/apache/lucene/gdata/search/ src/java/org/apache/lucene/gdata/search/analysis/ src/java/org/apache/lucene/gdata/search/co...
Date Thu, 10 Aug 2006 22:32:47 GMT
Added: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchema.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchema.java?rev=430568&view=auto
==============================================================================
--- lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchema.java (added)
+++ lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchema.java Thu Aug 10 15:32:40 2006
@@ -0,0 +1,524 @@
+/**
+ * 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.lucene.gdata.search.config;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.PerFieldAnalyzerWrapper;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.gdata.search.index.IndexDocument;
+import org.apache.lucene.gdata.utils.ReflectionUtils;
+
+/**
+ * This class is used to configure the indexing and search component. Each
+ * service on the GData server will have an own search index. For this purpose
+ * one single index schema will be configured in the gdata-config.xml file. This
+ * file will be mapped on this class on startup.
+ * <p>
+ * This class breaks some encapsulation of general java classes to be
+ * configurable via the xml configuration file. The will be very less type and
+ * value checking of the properties inside this file. Mandatory values must be
+ * set in the configuration file. The server won't start up if these values are
+ * missing. See definition in the xml schema file. If this class is instantiated
+ * manually the value for the name of the schema should be set before this is
+ * passed to the IndexController.
+ * </p>
+ * <p>
+ * One IndexSchema consists of multiple instances of
+ * {@link org.apache.lucene.gdata.search.config.IndexSchemaField} each of this
+ * instances describes a single field in the index and all schema informations
+ * about the field.
+ * <p>
+ * 
+ * 
+ * @see org.apache.lucene.gdata.search.config.IndexSchemaField
+ * 
+ * 
+ * @author Simon Willnauer
+ */
+public class IndexSchema {
+    private final Set<String> searchableFieldNames = new HashSet<String>();
+
+    private static final Log LOG = LogFactory.getLog(IndexSchema.class);
+
+    /**
+     * a static final value for properties are not set by the configuration file
+     * this value will be set to all long and int properties by default
+     */
+    public static final int NOT_SET_VALUE = -1;
+    private static final int DEFAULT_OPTIMIZE_COUNT = 1;
+    private static final int DEFAULT_COMMIT_COUNT = 1;
+
+    private String indexLocation;
+
+    /*
+     * this should be final change it if possible --> see commons digester /
+     * RegistryBuilder
+     */
+    private String name;
+
+    private boolean useTimedIndexer;
+
+    private long indexerIdleTime = NOT_SET_VALUE;
+
+    private Analyzer serviceAnalyzer;
+
+    private String defaultSearchField;
+
+    private PerFieldAnalyzerWrapper perFieldAnalyzer;
+
+    private Collection<IndexSchemaField> schemaFields;
+
+    private int maxBufferedDocs = NOT_SET_VALUE;
+
+    private int maxMergeDocs = NOT_SET_VALUE;
+
+    private int mergeFactor = NOT_SET_VALUE;
+
+    private int maxFieldLength = NOT_SET_VALUE;
+
+    private long writeLockTimeout = NOT_SET_VALUE;
+
+    private long commitLockTimeout = NOT_SET_VALUE;
+
+    private int commitAfterDocuments = DEFAULT_COMMIT_COUNT;
+    
+    private int optimizeAfterCommit = DEFAULT_OPTIMIZE_COUNT;
+    
+    private boolean useCompoundFile = false;
+
+    /**
+     * Creates a new IndexSchema and initialize the standard service analyzer to
+     * {@link StandardAnalyzer}
+     * 
+     */
+    public IndexSchema() {
+        this.schemaFields = new ArrayList<IndexSchemaField>();
+        /*
+         * keep as standard if omitted in the configuration
+         */
+        this.serviceAnalyzer = new StandardAnalyzer();
+
+    }
+
+    /**
+     * Initialize the schema and checks all required values
+     */
+    public void initialize() {
+        for (IndexSchemaField field : this.schemaFields) {
+            if (!field.checkRequieredValues())
+                throw new RuntimeException("Required Value for field: "
+                        + field.getName() + " is missing");
+        }
+        if (this.defaultSearchField == null)
+            throw new RuntimeException("DefaulSearchField must not be null");
+        if (this.name == null)
+            throw new RuntimeException(
+                    "Schema field is not set -- must not be null");
+        if (this.indexLocation == null)
+            throw new RuntimeException("IndexLocation must not be null");
+        if(!this.searchableFieldNames.contains(this.defaultSearchField)){
+            throw new RuntimeException("the default search field: "+this.defaultSearchField+" is registered as a field");
+        }
+
+    }
+
+    /**
+     * @return Returns the useCompoundFile.
+     */
+    public boolean isUseCompoundFile() {
+        return this.useCompoundFile;
+    }
+
+    /**
+     * @param useCompoundFile
+     *            The useCompoundFile to set.
+     */
+    public void setUseCompoundFile(boolean useCompoundFile) {
+        this.useCompoundFile = useCompoundFile;
+    }
+
+    /**
+     * Adds a new {@link IndexSchemaField} to the schema. if the fields name
+     * equals {@link IndexDocument#FIELD_ENTRY_ID} or the field is
+     * <code>null</code> it will simply ignored
+     * 
+     * @param field -
+     *            the index schema field to add as a field of this schema.
+     */
+    public void addSchemaField(final IndexSchemaField field) {
+        if (field == null)
+            return;
+        /*
+         * skip fields configured in the gdata-config.xml file if their names
+         * match a primary key field id of the IndexDocument
+         */
+        if (field.getName().equals(IndexDocument.FIELD_ENTRY_ID)
+                || field.getName().equals(IndexDocument.FIELD_FEED_ID))
+            return;
+        if (field.getAnalyzerClass() != null) {
+            /*
+             * enable per field analyzer if one is set.
+             */
+            Analyzer analyzer = getAnalyzerInstance(field.getAnalyzerClass());
+            /*
+             * null values will be omitted here
+             */
+            buildPerFieldAnalyzerWrapper(analyzer, field.getName());
+        }
+        this.schemaFields.add(field);
+        this.searchableFieldNames.add(field.getName());
+    }
+
+
+    /**
+     * @return Returns the fieldConfiguration.
+     */
+    public Collection<IndexSchemaField> getFields() {
+        return this.schemaFields;
+    }
+
+    /**
+     * @return - the analyzer instance to be used for this schema
+     */
+    public Analyzer getSchemaAnalyzer() {
+        if (this.perFieldAnalyzer == null)
+            return this.serviceAnalyzer;
+        return this.perFieldAnalyzer;
+    }
+
+    /**
+     * @return Returns the serviceAnalyzer.
+     */
+    public Analyzer getServiceAnalyzer() {
+        return this.serviceAnalyzer;
+    }
+
+    /**
+     * @param serviceAnalyzer
+     *            The serviceAnalyzer to set.
+     */
+    public void setServiceAnalyzer(Analyzer serviceAnalyzer) {
+        if (serviceAnalyzer == null)
+            return;
+        this.serviceAnalyzer = serviceAnalyzer;
+
+    }
+
+    /**
+     * @return Returns the commitLockTimout.
+     */
+    public long getCommitLockTimeout() {
+        return this.commitLockTimeout;
+    }
+
+    /**
+     * 
+     * @param commitLockTimeout
+     *            The commitLockTimeout to set.
+     */
+    public void setCommitLockTimeout(long commitLockTimeout) {
+        // TODO enable this in config
+        this.commitLockTimeout = commitLockTimeout;
+    }
+
+    /**
+     * @return Returns the maxBufferedDocs.
+     */
+    public int getMaxBufferedDocs() {
+
+        return this.maxBufferedDocs;
+    }
+
+    /**
+     * @param maxBufferedDocs
+     *            The maxBufferedDocs to set.
+     */
+    public void setMaxBufferedDocs(int maxBufferedDocs) {
+        this.maxBufferedDocs = maxBufferedDocs;
+    }
+
+    /**
+     * @return Returns the maxFieldLength.
+     */
+    public int getMaxFieldLength() {
+        return this.maxFieldLength;
+    }
+
+    /**
+     * @param maxFieldLength
+     *            The maxFieldLength to set.
+     */
+    public void setMaxFieldLength(int maxFieldLength) {
+        this.maxFieldLength = maxFieldLength;
+    }
+
+    /**
+     * @return Returns the maxMergeDocs.
+     */
+    public int getMaxMergeDocs() {
+        return this.maxMergeDocs;
+    }
+
+    /**
+     * @param maxMergeDocs
+     *            The maxMergeDocs to set.
+     */
+    public void setMaxMergeDocs(int maxMergeDocs) {
+        this.maxMergeDocs = maxMergeDocs;
+    }
+
+    /**
+     * @return Returns the mergeFactor.
+     */
+    public int getMergeFactor() {
+        return this.mergeFactor;
+    }
+
+    /**
+     * @param mergeFactor
+     *            The mergeFactor to set.
+     */
+    public void setMergeFactor(int mergeFactor) {
+        this.mergeFactor = mergeFactor;
+    }
+
+    /**
+     * @return Returns the writeLockTimeout.
+     */
+    public long getWriteLockTimeout() {
+        return this.writeLockTimeout;
+    }
+
+    /**
+     * @param writeLockTimeout
+     *            The writeLockTimeout to set.
+     */
+    public void setWriteLockTimeout(long writeLockTimeout) {
+        this.writeLockTimeout = writeLockTimeout;
+    }
+
+    /**
+     * @param fields
+     *            The fieldConfiguration to set.
+     */
+    public void setSchemaFields(Collection<IndexSchemaField> fields) {
+        this.schemaFields = fields;
+    }
+
+    /**
+     * @return Returns the name.
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (this == object)
+            return true;
+        if (object == null)
+            return false;
+        if (object instanceof IndexSchema) {
+           if(this.name ==null)
+               return super.equals(object);
+            return this.name.equals(((IndexSchema) object).getName());
+        }
+        return false;
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        if (this.name == null)
+            return super.hashCode();
+        return this.name.hashCode();
+    }
+
+    private void buildPerFieldAnalyzerWrapper(Analyzer anazlyer, String field) {
+        if (anazlyer == null || field == null || field.length() == 0)
+            return;
+        if (this.perFieldAnalyzer == null)
+            this.perFieldAnalyzer = new PerFieldAnalyzerWrapper(
+                    this.serviceAnalyzer);
+        this.perFieldAnalyzer.addAnalyzer(field, anazlyer);
+    }
+
+    private static Analyzer getAnalyzerInstance(Class<? extends Analyzer> clazz) {
+        if (!ReflectionUtils.extendsType(clazz, Analyzer.class)) {
+            LOG.warn("Can not create analyzer for class " + clazz.getName());
+            return null;
+        }
+        try {
+            return clazz.newInstance();
+        } catch (Exception e) {
+            LOG.warn("Can not create analyzer for class " + clazz.getName());
+        }
+        return null;
+    }
+
+    /**
+     * @param name
+     *            The name to set.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return Returns the indexLocation.
+     */
+    public String getIndexLocation() {
+        return this.indexLocation;
+    }
+
+    /**
+     * @param indexLocation
+     *            The indexLocation to set.
+     */
+    public void setIndexLocation(String indexLocation) {
+        this.indexLocation = indexLocation;
+    }
+
+    /**
+     * @return Returns the defaultField.
+     */
+    public String getDefaultSearchField() {
+        return this.defaultSearchField;
+    }
+
+    /**
+     * @param defaultField
+     *            The defaultField to set.
+     */
+    public void setDefaultSearchField(String defaultField) {
+        this.defaultSearchField = defaultField;
+    }
+
+    /**
+     * @return Returns the indexerIdleTime.
+     */
+    public long getIndexerIdleTime() {
+        return this.indexerIdleTime;
+    }
+
+    /**
+     * @param indexerIdleTime
+     *            The indexerIdleTime to set.
+     */
+    public void setIndexerIdleTime(long indexerIdleTime) {
+        this.indexerIdleTime = indexerIdleTime;
+    }
+
+    /**
+     * @return Returns the useTimedIndexer.
+     */
+    public boolean isUseTimedIndexer() {
+        return this.useTimedIndexer;
+    }
+
+    /**
+     * @param useTimedIndexer
+     *            The useTimedIndexer to set.
+     */
+    public void setUseTimedIndexer(boolean useTimedIndexer) {
+        this.useTimedIndexer = useTimedIndexer;
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder(this.getClass().getName())
+                .append(" ");
+        builder.append("Name: ").append(this.name).append(" ");
+        builder.append("MaxBufferedDocs: ").append(this.maxBufferedDocs)
+                .append(" ");
+        builder.append("MaxFieldLength: ").append(this.maxFieldLength).append(
+                " ");
+        builder.append("MaxMergeDocs: ").append(this.maxMergeDocs).append(" ");
+        builder.append("MergeFactor: ").append(this.mergeFactor).append(" ");
+        builder.append("CommitLockTimeout: ").append(this.commitLockTimeout)
+                .append(" ");
+        builder.append("WriteLockTimeout: ").append(this.writeLockTimeout)
+                .append(" ");
+        builder.append("indexerIdleTime: ").append(this.indexerIdleTime)
+                .append(" ");
+        builder.append("useCompoundFile: ").append(this.useCompoundFile)
+                .append(" ");
+        builder.append("Added SchemaField instances: ").append(
+                this.schemaFields.size()).append(" ");
+
+        builder.append("IndexLocation: ").append(this.indexLocation)
+                .append(" ");
+        return builder.toString();
+
+    }
+
+    /**
+     * @return Returns the searchableFieldNames.
+     */
+    public Set<String> getSearchableFieldNames() {
+        return this.searchableFieldNames;
+    }
+
+    /**
+     * Defines after how many added,removed or updated document the indexer should commit.
+     * @return Returns the commitAfterDocuments.
+     */
+    public int getCommitAfterDocuments() {
+        return this.commitAfterDocuments;
+    }
+
+    /**
+     * @param commitAfterDocuments The commitAfterDocuments to set.
+     */
+    public void setCommitAfterDocuments(int commitAfterDocuments) {
+        if(commitAfterDocuments < DEFAULT_COMMIT_COUNT)
+            return;
+        this.commitAfterDocuments = commitAfterDocuments;
+    }
+
+    /**
+     * Defines after how many commits the indexer should optimize the index
+     * @return Returns the optimizeAfterCommit.
+     */
+    public int getOptimizeAfterCommit() {
+        
+        return this.optimizeAfterCommit;
+    }
+
+    /**
+     * @param optimizeAfterCommit The optimizeAfterCommit to set.
+     */
+    public void setOptimizeAfterCommit(int optimizeAfterCommit) {
+        if(optimizeAfterCommit < DEFAULT_OPTIMIZE_COUNT )
+            return;
+        this.optimizeAfterCommit = optimizeAfterCommit;
+    }
+}

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchema.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchema.java
------------------------------------------------------------------------------
    svn:executable = *

Added: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchemaField.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchemaField.java?rev=430568&view=auto
==============================================================================
--- lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchemaField.java (added)
+++ lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchemaField.java Thu Aug 10 15:32:40 2006
@@ -0,0 +1,379 @@
+/**
+ * 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.lucene.gdata.search.config;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.Field.Index;
+import org.apache.lucene.document.Field.Store;
+import org.apache.lucene.gdata.search.analysis.ContentStrategy;
+import org.apache.lucene.gdata.search.analysis.GdataCategoryStrategy;
+import org.apache.lucene.gdata.search.analysis.GdataDateStrategy;
+import org.apache.lucene.gdata.search.analysis.HTMLStrategy;
+import org.apache.lucene.gdata.search.analysis.KeywordStrategy;
+import org.apache.lucene.gdata.search.analysis.MixedContentStrategy;
+import org.apache.lucene.gdata.search.analysis.PlainTextStrategy;
+import org.apache.lucene.gdata.search.analysis.XHtmlStrategy;
+import org.apache.lucene.gdata.utils.ReflectionUtils;
+
+/**
+ * Each field in the search index is defined by a instance of
+ * {@link IndexSchemaField}. The schema definition will be loaded at startup
+ * and the defined values will be set to instances of this class. Each
+ * constructed field will be passed to an instance of
+ * {@link org.apache.lucene.gdata.search.config.IndexSchema}.
+ * <p>
+ * IndexSchemaField contains all informations about how the content from
+ * incoming entries has to be extracted and how the actual content has to be
+ * index into the lucene index.
+ * </p>
+ * <p>
+ * Each field will have a defined
+ * {@link org.apache.lucene.gdata.search.analysis.ContentStrategy} which does
+ * process the extraction of the field content from an incoming entry.
+ * </p>
+ * @see org.apache.lucene.gdata.search.analysis.ContentStrategy
+ * @see org.apache.lucene.gdata.search.config.IndexSchema
+ * 
+ * @author Simon Willnauer
+ * 
+ */
+public class IndexSchemaField {
+    /**
+     * Default value for Field.Store 
+     * @see org.apache.lucene.document.Field
+     */
+    public static final Store DEFAULT_STORE_STRATEGY = Field.Store.NO;
+    /**
+     * Default value for Field.Index
+     * @see org.apache.lucene.document.Field
+     */
+    public static final Index DEFAULT_INDEX_STRATEGY = Field.Index.TOKENIZED;
+    private static final float DEFAULT_BOOST = 1.0f;
+    private static final float MINIMAL_BOOST = 0.1f;
+    private float boost = DEFAULT_BOOST;
+
+    private String name;
+
+    private ContentType contentType;
+
+    private Index index = DEFAULT_INDEX_STRATEGY;
+
+    private Store store = DEFAULT_STORE_STRATEGY;
+
+    private String path;
+
+    private String typePath;
+
+    private Class<? extends Analyzer> analyzerClass;
+
+    private Class<? extends ContentStrategy> fieldClass;
+
+    /**
+     * Constructs a new SchemaField <br>
+     * Default values:
+     * <ol>
+     * <li>boost: <i>1.0</i></li>
+     * <li>index: <i>TOKENIZED</i></li>
+     * <li>store: <i>NO</i></li>
+     * </ol>
+     */
+    public IndexSchemaField() {
+        super();
+    }
+    boolean checkRequieredValues(){
+        /*
+         * This class will be inst. by the reg builder.
+         * Check all values to be set. otherwise return false.
+         * false will cause a runtime exception in IndexSchema
+         */
+        boolean returnValue = (this.name != null&&this.path!=null&&this.contentType!=null&&this.index!=null&&this.store!=null&&this.boost>=MINIMAL_BOOST);
+        if(this.contentType == ContentType.CUSTOM)
+            returnValue &=this.fieldClass!=null;
+        else if(this.contentType == ContentType.MIXED)
+            returnValue &=this.typePath!=null;
+        
+        return returnValue;
+    }
+    /**
+     * @return Returns the alanyzerClass.
+     */
+    public Class<? extends Analyzer> getAnalyzerClass() {
+        return this.analyzerClass;
+    }
+
+    /**
+     * @param alanyzerClass
+     *            The alanyzerClass to set.
+     */
+    public void setAnalyzerClass(Class<? extends Analyzer> alanyzerClass) {
+        this.analyzerClass = alanyzerClass;
+    }
+
+    /**
+     * @return Returns the fieldClass.
+     */
+    public Class<? extends ContentStrategy> getFieldClass() {
+        return this.fieldClass;
+    }
+
+    /**
+     * Sets the class or strategy is used to extract this field Attention: this
+     * method set the contentTyp to {@link ContentType#CUSTOM}
+     * 
+     * @param fieldClass
+     *            The fieldClass to set.
+     */
+    public void setFieldClass(Class<? extends ContentStrategy> fieldClass) {
+        if(fieldClass == null)
+            throw new IllegalArgumentException("ContentStrategy must not be null");
+        if(!ReflectionUtils.extendsType(fieldClass,ContentStrategy.class))
+            throw new RuntimeException("The configured ContentStrategy does not extend ContentStrategy, can not use as a custom strategy -- "+fieldClass.getName());
+        if(!ReflectionUtils.hasDesiredConstructor(fieldClass,new Class[]{IndexSchemaField.class}))
+            throw new RuntimeException("Can not create instance of "+fieldClass.getName());
+        this.fieldClass = fieldClass;
+        /*
+         * set custom - field class is only needed by custom
+         */
+        this.contentType = ContentType.CUSTOM;
+    }
+
+    /**
+     * @return Returns the index.
+     */
+    public Index getIndex() {
+        return this.index;
+    }
+
+    /**
+     * @param index
+     *            The index to set.
+     */
+    public void setIndex(Index index) {
+        this.index = index;
+    }
+
+    /**
+     * @return Returns the name.
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * @param name
+     *            The name to set.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return Returns the path.
+     */
+    public String getPath() {
+        return this.path;
+    }
+
+    /**
+     * @param path
+     *            The path to set.
+     */
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    /**
+     * @return Returns the store.
+     */
+    public Store getStore() {
+        return this.store;
+    }
+
+    /**
+     * @param store
+     *            The store to set.
+     */
+    public void setStore(Store store) {
+        this.store = store;
+    }
+
+    /**
+     * @return Returns the type.
+     */
+    public ContentType getContentType() {
+        return this.contentType;
+    }
+
+    /**
+     * @param type
+     *            The type to set.
+     */
+    public void setContentType(ContentType type) {
+        this.contentType = type;
+
+    }
+
+    /**
+     * Sets the content type of this field by the name of the enum type. This
+     * method is not case sensitive.
+     * 
+     * @param type -
+     *            type name as string
+     */
+    public void setType(String type) {
+        ContentType[] types = ContentType.class.getEnumConstants();
+        for (int i = 0; i < types.length; i++) {
+            if (types[i].name().toLowerCase().equals(type)) {
+                this.contentType = types[i];
+                break;
+            }
+
+        }
+    }
+
+    /**
+     * Defines the {@link ContentStrategy} to use for a
+     * <tt>IndexSchemaField</tt> to extract the content from the entry
+     * 
+     * @author Simon Willnauer
+     * 
+     */
+    public enum ContentType {
+       
+        /**
+         * HTML content strategy {@link HTMLStrategy }
+         */
+        HTML,
+        /**
+         * XHTML content strategy {@link XHtmlStrategy }
+         */
+        XHTML,
+        /**
+         * Text content strategy {@link PlainTextStrategy }
+         */
+        TEXT,
+        /**
+         * GDataDate content strategy {@link GdataDateStrategy }
+         */
+        GDATADATE,
+        /**
+         * KEYWORD content strategy {@link KeywordStrategy }
+         */
+        KEYWORD,
+        /**
+         * Category content strategy {@link GdataCategoryStrategy }
+         */
+        CATEGORY,
+        /**
+         * Custom content strategy (user defined)
+         */
+        CUSTOM,
+        /**
+         * Mixed content strategy {@link MixedContentStrategy }
+         */
+        MIXED
+
+    }
+
+    /**
+     * @return Returns the boost.
+     */
+    public float getBoost() {
+        return this.boost;
+    }
+
+    /**
+     * @param boost
+     *            The boost to set.
+     */
+    public void setBoost(float boost) {
+        if (boost <= 0)
+            return;
+        this.boost = boost;
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder(this.getClass()
+                .getSimpleName()).append(" ");
+        builder.append("field name: ").append(this.name).append(" ");
+        builder.append("path: ").append(this.path).append(" ");
+        builder.append("content type ").append(this.contentType).append(" ");
+        builder.append("field class: ").append(this.fieldClass).append(" ");
+        builder.append("analyzer: ").append(this.analyzerClass).append(" ");
+        builder.append("boost: ").append(this.boost).append(" ");
+        builder.append("INDEX: ").append(this.index).append(" ");
+        builder.append("STORE: ").append(this.store);
+        return builder.toString();
+    }
+
+    /**
+     * Sets the Store class by simple name
+     * 
+     * @param name -
+     *            one of yes, no, compress
+     */
+    public void setStoreByName(String name) {
+        if (name.toLowerCase().equals("yes"))
+            this.store = Field.Store.YES;
+        else if (name.toLowerCase().equals("no"))
+            this.store = Field.Store.NO;
+        else if (name.toLowerCase().equals("compress"))
+            this.store = Field.Store.COMPRESS;
+    }
+
+    /**
+     * Sets the Index class by simple name
+     * 
+     * @param name -
+     *            un_tokenized, tokenized, no, no_norms
+     */
+    public void setIndexByName(String name) {
+        if (name.toLowerCase().equals("un_tokenized"))
+            this.index = Field.Index.UN_TOKENIZED;
+        else if (name.toLowerCase().equals("tokenized"))
+            this.index = Field.Index.TOKENIZED;
+        else if (name.toLowerCase().equals("no_norms"))
+            this.index = Field.Index.NO_NORMS;
+        else if (name.toLowerCase().equals("no"))
+            this.index = Field.Index.NO;
+    }
+
+    /**
+     * @return Returns the typePath.
+     */
+    public String getTypePath() {
+        return this.typePath;
+    }
+
+    /**
+     * @param typePath
+     *            The typePath to set.
+     */
+    public void setTypePath(String typePath) {
+        this.typePath = typePath;
+        /*
+         * set Mixed - this property is only needed by mixed type
+         */
+        setContentType(ContentType.MIXED);
+    }
+
+}

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchemaField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchemaField.java
------------------------------------------------------------------------------
    svn:executable = *

Added: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/package.html
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/package.html?rev=430568&view=auto
==============================================================================
--- lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/package.html (added)
+++ lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/package.html Thu Aug 10 15:32:40 2006
@@ -0,0 +1,10 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> 
+<html> 
+<head> 
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> 
+   <meta name="Author" content="Simon Willnauer"> 
+</head> 
+<body> 
+All classes used for index and search configuration
+</body> 
+</html> 
\ No newline at end of file

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/config/package.html
------------------------------------------------------------------------------
    svn:executable = *

Added: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexDocument.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexDocument.java?rev=430568&view=auto
==============================================================================
--- lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexDocument.java (added)
+++ lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexDocument.java Thu Aug 10 15:32:40 2006
@@ -0,0 +1,136 @@
+/**
+ * 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.lucene.gdata.search.index;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.gdata.search.analysis.ContentStrategy;
+import org.apache.lucene.index.Term;
+
+/**
+ * Simple implementation
+ * 
+ * @author Simon Willnauer
+ * @see org.apache.lucene.gdata.search.index.IndexDocument
+ */
+class GDataIndexDocument implements IndexDocument {
+    private final IndexAction action;
+
+    private final boolean commitAfter;
+
+    private final boolean optimizeAfter;
+
+    private String id;
+
+    protected Collection<ContentStrategy> fields;
+
+    private final String feedId;
+
+    GDataIndexDocument(final IndexAction action, final String entryId,final String feedId,final boolean commitAfter,final boolean optimizeAfter) {
+        this.action = action;
+        this.id = entryId;
+        this.feedId = feedId;
+        this.fields = new ArrayList<ContentStrategy>(10);
+        this.commitAfter = commitAfter;
+        this.optimizeAfter = optimizeAfter;
+    }
+
+    /**
+     * Adds a new field e.g. <tt>ContentStrategy</tt> to the IndexDocument
+     * 
+     * @param field -
+     *            the strategy to add
+     */
+    public void addField(ContentStrategy field) {
+        if (field == null)
+            return;
+        this.fields.add(field);
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.search.index.IndexDocument#getWriteable()
+     */
+    public Document getWriteable() {
+        Document retVal = new Document();
+        retVal.add(new Field(FIELD_ENTRY_ID, this.id, Field.Store.YES,
+                Field.Index.UN_TOKENIZED));
+        retVal.add(new Field(FIELD_FEED_ID, this.feedId, Field.Store.YES,
+                Field.Index.UN_TOKENIZED));
+        for (ContentStrategy strategy : this.fields) {
+            Field[] fieldArray = strategy.createLuceneField();
+            for (int i = 0; i < fieldArray.length; i++) {
+                retVal.add(fieldArray[i]);
+            }
+            
+        }
+        return retVal;
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.search.index.IndexDocument#getDeletealbe()
+     */
+    public Term getDeletealbe() {
+
+        return new Term(IndexDocument.FIELD_ENTRY_ID, this.id);
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.search.index.IndexDocument#isUpdate()
+     */
+    public boolean isUpdate() {
+
+        return isAction(IndexAction.UPDATE);
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.search.index.IndexDocument#isDelete()
+     */
+    public boolean isDelete() {
+
+        return isAction(IndexAction.DELETE);
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.search.index.IndexDocument#isInsert()
+     */
+    public boolean isInsert() {
+
+        return isAction(IndexAction.INSERT);
+    }
+
+    private boolean isAction(IndexAction indexAction) {
+        return this.action == indexAction;
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.search.index.IndexDocument#commitAfter()
+     */
+    public boolean commitAfter() {
+
+        return this.commitAfter;
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.search.index.IndexDocument#optimizeAfter()
+     */
+    public boolean optimizeAfter() {
+
+        return this.optimizeAfter;
+    }
+
+}

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexDocument.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexDocument.java
------------------------------------------------------------------------------
    svn:executable = *

Added: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexWriter.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexWriter.java?rev=430568&view=auto
==============================================================================
--- lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexWriter.java (added)
+++ lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexWriter.java Thu Aug 10 15:32:40 2006
@@ -0,0 +1,101 @@
+/**
+ * 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.lucene.gdata.search.index;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.gdata.search.config.IndexSchema;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.store.Directory;
+
+/**
+ * Configurable decorator for a lucene {@link IndexWriter}
+ * 
+ * @author Simon Willnauer
+ * 
+ */
+public class GDataIndexWriter extends IndexWriter {
+    private static final Log LOG = LogFactory.getLog(GDataIndexWriter.class);
+
+    private String serviceName;
+
+    private void initialize(IndexSchema config) {
+        this.serviceName = config.getName();
+        setUseCompoundFile(config.isUseCompoundFile());
+        if (config.getMaxBufferedDocs() != IndexSchema.NOT_SET_VALUE)
+            setMaxBufferedDocs(config.getMaxBufferedDocs());
+        if (config.getMaxMergeDocs() != IndexSchema.NOT_SET_VALUE)
+            setMaxMergeDocs(config.getMaxMergeDocs());
+        if (config.getMergeFactor() != IndexSchema.NOT_SET_VALUE)
+            setMergeFactor(config.getMergeFactor());
+        if (config.getMaxFieldLength() != IndexSchema.NOT_SET_VALUE)
+            setMaxFieldLength(config.getMaxFieldLength());
+        if (config.getWriteLockTimeout() != IndexSchema.NOT_SET_VALUE)
+            setWriteLockTimeout(config.getWriteLockTimeout());
+        if (config.getCommitLockTimeout() != IndexSchema.NOT_SET_VALUE)
+            setCommitLockTimeout(config.getCommitLockTimeout());
+    }
+
+    /**
+     * Creates and configures a new GdataIndexWriter
+     * 
+     * @param arg0 -
+     *            the index directory
+     * @param arg1 -
+     *            create index
+     * @param arg2 -
+     *            the index schema configuration including all parameter to set
+     *            up the index writer
+     * @throws IOException
+     *             -if the directory cannot be read/written to, or if it does
+     *             not exist, and <code>create</code> is <code>false</code>
+     */
+    protected GDataIndexWriter(Directory arg0, boolean arg1, IndexSchema arg2)
+            throws IOException {
+        /*
+         * Use Schema Analyzer rather than service analyzer. 
+         * Schema analyzer returns either the service analyzer or a per field analyzer if configured.
+         */
+        super(arg0, (arg2 == null ? new StandardAnalyzer() : arg2.getSchemaAnalyzer()), arg1);
+        if (arg2 == null) {
+            /*
+             * if no schema throw exception - schema is mandatory for the index writer.
+             */
+            try {
+                this.close();
+            } catch (IOException e) {
+                //
+            }
+            throw new IllegalArgumentException("configuration must not be null");
+
+        }
+        this.initialize(arg2);
+    }
+
+    /**
+     * @see org.apache.lucene.index.IndexWriter#close()
+     */
+    @Override
+    public void close() throws IOException {
+        super.close();
+        LOG.info("Closing GdataIndexWriter for service " + this.serviceName);
+    }
+
+}

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexWriter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexWriter.java
------------------------------------------------------------------------------
    svn:executable = *

Added: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexer.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexer.java?rev=430568&view=auto
==============================================================================
--- lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexer.java (added)
+++ lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexer.java Thu Aug 10 15:32:40 2006
@@ -0,0 +1,509 @@
+/**
+ * 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.lucene.gdata.search.index;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.search.config.IndexSchema;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.TermDocs;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.store.Directory;
+
+/**
+ * A GDataIndexer encapsulates every writing access to the search index.
+ * <p>
+ * Insert, updates and deletes to the index happens inside this class. All
+ * modification will be base on an instance of
+ * {@link org.apache.lucene.gdata.search.index.IndexDocument} which contains all
+ * informations and command for the indexer.<br>
+ * Although this class provides methods to add, remove and update document in
+ * the index all <tt>IndexDocument</tt> instances should be added to the task
+ * queue via the {@link GDataIndexer#addIndexableDocumentTask(Future)} method.
+ * Inside this class runs an instance of
+ * {@link org.apache.lucene.gdata.search.index.IndexTask} listening on this
+ * queue. The analysis of the actual documents happens inside the
+ * {@link com.sun.corba.se.impl.orbutil.closure.Future} object added to the
+ * queue. This enables the indexer to do his actual work. Documents will be
+ * build / analyzed concurrently while already finished tasks can be added to
+ * the index.
+ * </p>
+ * 
+ * 
+ * 
+ * @author Simon Willnauer
+ */
+public class GDataIndexer {
+    private static final Log LOG = LogFactory.getLog(GDataIndexer.class);
+
+    protected IndexWriter writer;
+
+    protected IndexSearcher searcher;
+
+    protected AtomicInteger committed = new AtomicInteger(0);
+
+    protected AtomicInteger optimized = new AtomicInteger(0);
+
+    private AtomicBoolean isDestroyed = new AtomicBoolean(false);
+
+    protected AtomicInteger docsAdded = new AtomicInteger();
+
+    protected AtomicInteger docsUpdated = new AtomicInteger();
+
+    protected AtomicInteger docsDeleted = new AtomicInteger();
+
+    private final Directory dir;
+
+    private final List<IndexEventListener> listeners = new ArrayList<IndexEventListener>();
+
+    protected final BlockingQueue<Future<IndexDocument>> futurQueue = new LinkedBlockingQueue<Future<IndexDocument>>(
+            100);
+
+    private final IndexSchema serviceConfiguration;
+
+    private final ExecutorService indexTaskExecutor;
+
+    protected IndexTask indexTask;
+
+    private static final Integer ZERO = new Integer(0);
+
+    private static final Integer ONE = new Integer(1);
+
+    private final Map<IndexDocument, Integer> action;
+
+    protected GDataIndexer(final IndexSchema schema, Directory dir,
+            boolean create) throws IOException {
+        if (schema == null)
+            throw new IllegalArgumentException(
+                    "IndexServiceConfiguration must not be null");
+        if (dir == null)
+            throw new IllegalArgumentException(
+                    "IndexDirectory must not be null");
+
+        this.serviceConfiguration = schema;
+        this.dir = dir;
+        openWriter(create);
+        this.indexTaskExecutor = Executors.newSingleThreadExecutor();
+        this.action = new HashMap<IndexDocument, Integer>(128);
+
+    }
+
+    protected void setIndexTask(final IndexTask task) {
+        if (task != null && this.indexTask == null)
+            this.indexTask = task;
+    }
+
+    protected void init() {
+        if (this.indexTask == null)
+            this.indexTask = new IndexTask(this, this.futurQueue);
+        this.indexTaskExecutor.execute(this.indexTask);
+
+    }
+
+    /**
+     * Adds the given future task to the queue, and waits if the queue is full.
+     * The queue size is set to 100 by default.
+     * 
+     * @param task -
+     *            the task to be scheduled
+     * @throws InterruptedException -
+     *             if the queue is interrupted
+     */
+    public void addIndexableDocumentTask(final Future<IndexDocument> task)
+            throws InterruptedException {
+        if (this.isDestroyed.get())
+            throw new IllegalStateException(
+                    "Indexer has already been destroyed");
+        this.futurQueue.put(task);
+    }
+
+    /*
+     * a added doc should not be in the index, be sure and delete possible
+     * duplicates
+     */
+    protected synchronized void addDocument(IndexDocument indexable)
+            throws IOException {
+        if (!indexable.isInsert())
+            throw new GdataIndexerException(
+                    "Index action must be set to insert");
+        setAction(indexable);
+        doWrite(indexable);
+        this.docsAdded.incrementAndGet();
+
+    }
+
+    private void setAction(IndexDocument doc) {
+        Integer docCountToKeep = this.action.get(doc);
+        if (!doc.isDelete() && (docCountToKeep == null || docCountToKeep == 0)) {
+            /*
+             * add a ONE for ONE documents to keep for this IndexDocument when
+             * doDelete. doDelete will keep the latest added document and
+             * deletes all other documents for this IndexDocument e.g. all
+             * duplicates
+             */
+            this.action.put(doc, ONE);
+        } else if (doc.isDelete()
+                && (docCountToKeep == null || docCountToKeep > 0)) {
+            /*
+             * add a zero for zero documents to keep for this IndexDocument when
+             * doDelete
+             */
+            this.action.put(doc, ZERO);
+        }
+    }
+
+    protected synchronized void updateDocument(IndexDocument indexable)
+            throws IOException {
+        if (!indexable.isUpdate())
+            throw new GdataIndexerException(
+                    "Index action must be set to update");
+        setAction(indexable);
+        doWrite(indexable);
+        this.docsUpdated.incrementAndGet();
+    }
+
+    protected synchronized void deleteDocument(IndexDocument indexable) {
+        if (!indexable.isDelete())
+            throw new GdataIndexerException(
+                    "Index action must be set to delete");
+
+        setAction(indexable);
+        this.docsDeleted.incrementAndGet();
+    }
+
+    /**
+     * This method commits all changes to the index and closes all open
+     * resources (e.g. IndexWriter and IndexReader). This method notifies all
+     * registered Commit listeners if invoked.
+     * 
+     * @param optimize -
+     *            <code>true</code> if the index should be optimized on this
+     *            commit
+     * @throws IOException -
+     *             if an IOException occurs
+     */
+    protected synchronized void commit(boolean optimize) throws IOException {
+        if (LOG.isInfoEnabled())
+            LOG.info("Commit called with optimize = " + optimize);
+
+        int changes = this.docsAdded.intValue() + this.docsDeleted.intValue()
+                + this.docsUpdated.intValue();
+        /*
+         * don't call listeners to prevent unnecessary close / open of searchers
+         */
+        if (changes == 0)
+            return;
+        this.committed.incrementAndGet();
+        if(optimize)
+            this.optimized.incrementAndGet();
+        doDeltete();
+        if (optimize) {
+            closeSearcher();
+            openWriter();
+            this.writer.optimize();
+        }
+        closeSearcher();
+        closeWriter();
+        this.docsAdded.set(0);
+        this.docsDeleted.set(0);
+        this.docsUpdated.set(0);
+        notifyCommitListeners(this.serviceConfiguration.getName());
+
+    }
+
+    /**
+     * Registers a new IndexEventListener. All registered listeners will be
+     * notified if the index has been committed.
+     * 
+     * @param listener -
+     *            the listener to register
+     * 
+     */
+    public void registerIndexEventListener(IndexEventListener listener) {
+        if (listener == null || this.listeners.contains(listener))
+            return;
+        this.listeners.add(listener);
+    }
+
+    /**
+     * Removes a registered IndexEventListener
+     * 
+     * @param listener -
+     *            the listener to remove
+     */
+    public void removeIndexEventListener(IndexEventListener listener) {
+
+        if (listener == null || !this.listeners.contains(listener))
+            return;
+        this.listeners.remove(listener);
+    }
+
+    protected void notifyCommitListeners(String serviceId) {
+        if (LOG.isInfoEnabled())
+            LOG.info("notify commit event listeners for service id: "
+                    + serviceId + " --  current size of registered listeners: "
+                    + this.listeners.size());
+        for (IndexEventListener listener : this.listeners) {
+            listener.commitCallBack(serviceId);
+        }
+    }
+
+    protected void closeWriter() throws IOException {
+        try {
+            if (this.writer != null)
+                this.writer.close();
+        } finally {
+            this.writer = null;
+        }
+    }
+
+    protected void closeSearcher() throws IOException {
+        try {
+            if (this.searcher != null)
+                this.searcher.close();
+        } finally {
+            this.searcher = null;
+        }
+    }
+
+    protected void openSearcher() throws IOException {
+        if (this.searcher == null)
+            this.searcher = new IndexSearcher(this.dir);
+    }
+
+    protected void openWriter() throws IOException {
+        openWriter(false);
+    }
+
+    private void openWriter(boolean create) throws IOException {
+        if (this.writer == null)
+            this.writer = new GDataIndexWriter(this.dir, create,
+                    this.serviceConfiguration);
+    }
+
+    /*
+     * This should only be called in a synchronized block
+     */
+    protected void doWrite(IndexDocument document) throws IOException {
+        closeSearcher();
+        openWriter();
+        this.writer.addDocument(document.getWriteable());
+
+    }
+
+    // only access synchronized
+    int[] documentNumber;
+
+    /*
+     * This should only be called in a synchronized block
+     */
+    protected void doDeltete() throws IOException {
+        if (this.action.size() == 0)
+            return;
+        if (LOG.isInfoEnabled())
+            LOG
+                    .info("Deleting documents and duplicates from index, size of IndexDocuments "
+                            + this.action.size());
+        closeWriter();
+        openSearcher();
+
+        IndexReader reader = this.searcher.getIndexReader();
+        TermDocs termDocs = reader.termDocs();
+        for (Map.Entry<IndexDocument, Integer> entry : this.action.entrySet()) {
+            IndexDocument indexDocument = entry.getKey();
+            Integer docToKeep = entry.getValue();
+            // extend the array if needed
+            if (this.documentNumber == null
+                    || docToKeep > this.documentNumber.length)
+                this.documentNumber = new int[docToKeep];
+
+            for (int i = 0; i < this.documentNumber.length; i++) {
+
+                this.documentNumber[i] = -1;
+            }
+            /*
+             * get the term to find the document from the document itself
+             */
+            termDocs.seek(indexDocument.getDeletealbe());
+
+            int pos = 0;
+
+            while (termDocs.next()) {
+                /*
+                 * if this is a pure delete just delete it an continue
+                 */
+                if (docToKeep == 0) {
+                    reader.deleteDocument(termDocs.doc());
+                    continue;
+                }
+
+                int prev = this.documentNumber[pos];
+                this.documentNumber[pos] = termDocs.doc();
+                if (prev != -1) {
+                    reader.deleteDocument(prev);
+                }
+
+                if (++pos >= docToKeep)
+                    pos = 0;
+
+            }
+        }
+        /*
+         * clear the map after all documents are processed
+         */
+        this.action.clear();
+        closeSearcher();
+    }
+
+    protected synchronized void destroy() throws IOException {
+        this.isDestroyed.set(true);
+        if (!this.indexTask.isStopped())
+            this.indexTask.stop();
+        this.futurQueue.add(new FinishingFuture());
+        this.indexTaskExecutor.shutdown();
+        closeWriter();
+        closeSearcher();
+        if (LOG.isInfoEnabled())
+            LOG.info("Destroying GdataIndexer for service -- "
+                    + this.serviceConfiguration.getName());
+
+    }
+
+    /**
+     * This factory method creates a new GDataIndexer using a instance of
+     * {@link IndexTask}
+     * 
+     * @param config -
+     *            the config to be used to configure the indexer
+     * @param dir -
+     *            the directory to index to
+     * @param create -
+     *            <code>true</code> to create a new index, <code>false</code>
+     *            to use the existing one.
+     * @return - a new GDataIndexer instance
+     * @throws IOException -
+     *             if an IOException occurs while initializing the indexer
+     */
+    public static synchronized GDataIndexer createGdataIndexer(
+            final IndexSchema config, Directory dir, boolean create)
+            throws IOException {
+        GDataIndexer retVal = new GDataIndexer(config, dir, create);
+        retVal.setIndexTask(new IndexTask(retVal, retVal.futurQueue));
+        retVal.init();
+        return retVal;
+    }
+
+    /**
+     * This factory method creates a new GDataIndexer using a instance of
+     * {@link TimedIndexTask}. This indexer will automatically commit the index
+     * if no modification to the index occur for the given time. The used time
+     * unit is {@link TimeUnit#SECONDS}. Values less than the default value
+     * will be ignored. For the default value see {@link TimedIndexTask}.
+     * 
+     * @param config -
+     *            the config to be used to configure the indexer
+     * @param dir -
+     *            the directory to index to
+     * @param create -
+     *            <code>true</code> to create a new index, <code>false</code>
+     *            to use the existing one.
+     * @param commitTimeout -
+     *            the amount of seconds to wait until a commit should be
+     *            scheduled
+     * @return - a new GDataIndexer instance
+     * @throws IOException -
+     *             if an IOException occurs while initializing the indexer
+     */
+    public static synchronized GDataIndexer createTimedGdataIndexer(
+            final IndexSchema config, Directory dir, boolean create,
+            long commitTimeout) throws IOException {
+
+        GDataIndexer retVal = new GDataIndexer(config, dir, create);
+        retVal.setIndexTask(new TimedIndexTask(retVal, retVal.futurQueue,
+                commitTimeout));
+        retVal.init();
+        return retVal;
+    }
+
+    @SuppressWarnings("unused")
+    static final class FinishingFuture implements Future<IndexDocument> {
+
+        /**
+         * @see java.util.concurrent.Future#cancel(boolean)
+         */
+        public boolean cancel(boolean arg0) {
+
+            return false;
+        }
+
+        /**
+         * @see java.util.concurrent.Future#isCancelled()
+         */
+        public boolean isCancelled() {
+
+            return false;
+        }
+
+        /**
+         * @see java.util.concurrent.Future#isDone()
+         */
+        public boolean isDone() {
+
+            return true;
+        }
+
+        /**
+         * @see java.util.concurrent.Future#get()
+         */
+        @SuppressWarnings("unused")
+        public IndexDocument get() throws InterruptedException,
+                ExecutionException {
+
+            return null;
+        }
+
+        /**
+         * @see java.util.concurrent.Future#get(long,
+         *      java.util.concurrent.TimeUnit)
+         */
+        @SuppressWarnings("unused")
+        public IndexDocument get(long arg0, TimeUnit arg1)
+                throws InterruptedException, ExecutionException,
+                TimeoutException {
+
+            return null;
+        }
+
+    }
+
+}

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexer.java
------------------------------------------------------------------------------
    svn:executable = *

Added: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GdataIndexerException.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GdataIndexerException.java?rev=430568&view=auto
==============================================================================
--- lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GdataIndexerException.java (added)
+++ lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GdataIndexerException.java Thu Aug 10 15:32:40 2006
@@ -0,0 +1,74 @@
+/**
+ * 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.lucene.gdata.search.index;
+
+/**
+ * This exception will be thrown if an exception in the indexing component
+ * occurs
+ * 
+ * @author Simon Willnauer
+ * 
+ */
+public class GdataIndexerException extends RuntimeException {
+
+    private static final long serialVersionUID = -8245420079471690182L;
+
+    /**
+     * Creates a new GdataIndexerException
+     */
+    public GdataIndexerException() {
+        super();
+
+    }
+
+    /**
+     * Creates a new GdataIndexerException with a new exception message
+     * 
+     * @param arg0 -
+     *            exception message
+     */
+    public GdataIndexerException(String arg0) {
+        super(arg0);
+
+    }
+
+    /**
+     * Creates a new GdataIndexerException with a new exception message and a
+     * root cause
+     * 
+     * @param arg0 -
+     *            exception message
+     * @param arg1 -
+     *            the root cause
+     */
+    public GdataIndexerException(String arg0, Throwable arg1) {
+        super(arg0, arg1);
+
+    }
+
+    /**
+     * Creates a new GdataIndexerException with a root cause
+     * 
+     * @param arg0 -
+     *            the root cause
+     */
+    public GdataIndexerException(Throwable arg0) {
+        super(arg0);
+
+    }
+
+}

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GdataIndexerException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/GdataIndexerException.java
------------------------------------------------------------------------------
    svn:executable = *

Added: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexAction.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexAction.java?rev=430568&view=auto
==============================================================================
--- lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexAction.java (added)
+++ lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexAction.java Thu Aug 10 15:32:40 2006
@@ -0,0 +1,37 @@
+/**
+ * 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.lucene.gdata.search.index;
+
+/**
+ * This enum defines all possible actions on a GData index.
+ * 
+ * @see org.apache.lucene.gdata.search.index.IndexDocument
+ * @see org.apache.lucene.gdata.search.index.IndexDocumentBuilderTask
+ * @author Simon Willnauer
+ * 
+ */
+public enum IndexAction {
+    /**
+     * update action
+     */
+    UPDATE, /**
+             * delete action
+             */
+    DELETE, /**
+             * insert / add action
+             */
+    INSERT
+}

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexAction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexAction.java
------------------------------------------------------------------------------
    svn:executable = *

Added: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexController.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexController.java?rev=430568&view=auto
==============================================================================
--- lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexController.java (added)
+++ lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexController.java Thu Aug 10 15:32:40 2006
@@ -0,0 +1,511 @@
+/**
+ * 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.lucene.gdata.search.index;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.data.ServerBaseEntry;
+import org.apache.lucene.gdata.search.GDataSearcher;
+import org.apache.lucene.gdata.search.SearchComponent;
+import org.apache.lucene.gdata.search.StandardGdataSearcher;
+import org.apache.lucene.gdata.search.config.IndexSchema;
+import org.apache.lucene.gdata.server.registry.Component;
+import org.apache.lucene.gdata.server.registry.ComponentType;
+import org.apache.lucene.gdata.server.registry.EntryEventListener;
+import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
+import org.apache.lucene.gdata.server.registry.ProvidedService;
+import org.apache.lucene.gdata.utils.ReferenceCounter;
+import org.apache.lucene.index.IndexFileNameFilter;
+import org.apache.lucene.search.Filter;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+
+/**
+ * Default implementation of the {@link SearchComponent} interface. All actions
+ * on the index will be controlled from this class. Only this class grants read
+ * or write actions access to the index.
+ * 
+ * @author Simon Willnauer
+ * 
+ */
+@Component(componentType = ComponentType.SEARCHCONTROLLER)
+public class IndexController implements SearchComponent, IndexEventListener,
+        EntryEventListener {
+    static final Log LOG = LogFactory.getLog(IndexController.class);
+
+    private final AtomicBoolean isInitialized = new AtomicBoolean(false);
+
+    private final AtomicBoolean destroyed = new AtomicBoolean(false);
+
+    protected Map<String, ServiceIndex> indexerMap;
+
+    private final ExecutorService taskExecutor;
+
+    /**
+     * Creates a new IndexController -- call
+     * {@link IndexController#initialize()} to set up the controller.
+     */
+    public IndexController() {
+        this.taskExecutor = Executors.newCachedThreadPool();
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.search.SearchComponent#initialize()
+     */
+    public synchronized void initialize() {
+        if (this.isInitialized.get())
+            throw new IllegalStateException(
+                    "IndexController is already initialized");
+        this.destroyed.set(false);
+        /*
+         * if this fails the server must not startup --> throw runtime exception
+         */
+        GDataServerRegistry.getRegistry().registerEntryEventListener(this);
+
+        GDataServerRegistry.getRegistry().registerEntryEventListener(this);
+        Collection<ProvidedService> services = GDataServerRegistry
+                .getRegistry().getServices();
+        this.indexerMap = new ConcurrentHashMap<String, ServiceIndex>(services
+                .size());
+       
+        for (ProvidedService service : services) {
+            IndexSchema schema = service.getIndexSchema();
+            /*
+             * initialize will fail if mandatory values are not set. This is
+             * just a
+             */
+            schema.initialize();
+            addIndexSchema(schema);
+        }
+        this.isInitialized.set(true);
+        
+
+    }
+
+    /*
+     * add a schema to the index controller and create the indexer. create
+     * directories and check out existing indexes
+     */
+    protected void addIndexSchema(IndexSchema schema) {
+        if (this.destroyed.get())
+            throw new IllegalStateException(
+                    "IndexController has been destroyed");
+        if (schema.getName() == null)
+            throw new IllegalStateException(
+                    "schema has no name -- is not associated with any service");
+        if (this.indexerMap.containsKey(schema.getName()))
+            throw new IllegalStateException("schema for service "
+                    + schema.getName() + " is already registered");
+        if (LOG.isInfoEnabled())
+            LOG.info("add new IndexSchema for service " + schema.getName()
+                    + " -- " + schema);
+        try {
+            ServiceIndex bean = createIndexer(schema);
+            ReferenceCounter<IndexSearcher> searcher = getNewServiceSearcher(bean.getDirectory());
+            bean.setSearcher(searcher);
+            this.indexerMap.put(schema.getName(), bean);
+        } catch (IOException e) {
+            LOG.error("Can not create indexer for service " + schema.getName(),
+                    e);
+            throw new GdataIndexerException(
+                    "Can not create indexer for service " + schema.getName(), e);
+        }
+
+    }
+
+    protected ServiceIndex createIndexer(IndexSchema schema) throws IOException {
+        GDataIndexer indexer;
+        File indexLocation = createIndexLocation(schema.getIndexLocation(),
+                schema.getName());
+        boolean create = createIndexDirectory(indexLocation);
+        Directory dir = FSDirectory.getDirectory(indexLocation, create);
+        if (LOG.isInfoEnabled())
+            LOG.info("Create new Indexer for IndexSchema: " + schema);
+        /*
+         * timed or committed indexer?! keep the possibility to let users decide
+         * to use scheduled commits
+         */
+        if (schema.isUseTimedIndexer())
+            indexer = GDataIndexer.createTimedGdataIndexer(schema, dir, create,
+                    schema.getIndexerIdleTime());
+        else
+            indexer = GDataIndexer.createGdataIndexer(schema, dir, create);
+        indexer.registerIndexEventListener(this);
+        return new ServiceIndex(schema, indexer, dir);
+    }
+
+    /*
+     * if this fails the server must not startup!!
+     */
+    protected File createIndexLocation(String path, String name) {
+        if (path == null || name == null)
+            throw new GdataIndexerException(
+                    "Path or Name of the index location is not set Path: "
+                            + path + " name: " + name);
+        /*
+         * check if parent e.g. the configured path is a directory
+         */
+        File parent = new File(path);
+        if (!parent.isDirectory())
+            throw new IllegalArgumentException(
+                    "the given path is not a directory -- " + path);
+        /*
+         * try to create and throw ex if fail
+         */
+        if (!parent.exists())
+            if (!parent.mkdir())
+                throw new RuntimeException("Can not create directory -- "
+                        + path);
+        /*
+         * try to create and throw ex if fail
+         */
+        File file = new File(parent, name);
+        if (file.isFile())
+            throw new IllegalArgumentException(
+                    "A file with the name"
+                            + name
+                            + " already exists in "
+                            + path
+                            + " -- a file of the name of the service must not exist in the index location");
+
+        if (!file.exists()) {
+            if (!file.mkdir())
+                throw new RuntimeException("Can not create directory -- "
+                        + file.getAbsolutePath());
+        }
+        return file;
+    }
+
+    protected boolean createIndexDirectory(File file) {
+        /*
+         * use a lucene filename filter to figure out if there is an existing
+         * index in the defined directory
+         */
+        String[] luceneFiles = file.list(new IndexFileNameFilter());
+        return !(luceneFiles.length > 0);
+
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.search.index.IndexEventListener#commitCallBack(java.lang.String)
+     */
+    public synchronized void commitCallBack(String service) {
+        if (this.destroyed.get())
+            throw new IllegalStateException(
+                    "IndexController has been destroyed");
+        if(LOG.isInfoEnabled())
+            LOG.info("CommitCallback triggered - register new searcher for service: "+service);
+        /*
+         * get the old searcher and replace it if possible.
+         */
+        ServiceIndex index = this.indexerMap.get(service);
+        ReferenceCounter<IndexSearcher> searcher = index.getSearcher();
+
+        try {
+            index.setSearcher(getNewServiceSearcher(index.getDirectory()));
+        } catch (IOException e) {
+            LOG.fatal("Can not create new Searcher -- keep the old one ", e);
+            return;
+        }
+        /*
+         * if new searcher if registered decrement old one to get it destroyed if unused
+         */
+        searcher.decrementRef();
+    }
+    /*
+     * create a new ReferenceCounter for the indexSearcher.
+     * The reference is already incremented before returned
+     */
+    private ReferenceCounter<IndexSearcher> getNewServiceSearcher(Directory dir)
+            throws IOException {
+        if(LOG.isInfoEnabled())
+            LOG.info("Create new ServiceSearcher");
+        IndexSearcher searcher = new IndexSearcher(dir);
+        ReferenceCounter<IndexSearcher> holder = new ReferenceCounter<IndexSearcher>(
+                searcher) {
+
+            @Override
+            protected void close() {
+                try {
+                    LOG
+                            .info("Close IndexSearcher -- Zero references remaining");
+                    this.resource.close();
+                } catch (IOException e) {
+                    LOG.warn("Can not close IndexSearcher -- ", e);
+                }
+            }
+
+        };
+        holder.increamentReference();
+        return holder;
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.server.registry.EntryEventListener#fireUpdateEvent(org.apache.lucene.gdata.data.ServerBaseEntry)
+     */
+    public void fireUpdateEvent(ServerBaseEntry entry) {
+        createNewIndexerTask(entry, IndexAction.UPDATE);
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.server.registry.EntryEventListener#fireInsertEvent(org.apache.lucene.gdata.data.ServerBaseEntry)
+     */
+    public void fireInsertEvent(ServerBaseEntry entry) {
+        createNewIndexerTask(entry, IndexAction.INSERT);
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.server.registry.EntryEventListener#fireDeleteEvent(org.apache.lucene.gdata.data.ServerBaseEntry)
+     */
+    public void fireDeleteEvent(ServerBaseEntry entry) {
+        createNewIndexerTask(entry, IndexAction.DELETE);
+
+    }
+
+    // TODO add test for this method!!
+    private void createNewIndexerTask(ServerBaseEntry entry, IndexAction action) {
+        if (this.destroyed.get())
+            throw new IllegalStateException(
+                    "IndexController has been destroyed");
+        if(!this.isInitialized.get())
+            throw new IllegalStateException(
+            "IndexController has not been initialized");
+
+        String serviceName = entry.getServiceConfig().getName();
+        if (LOG.isInfoEnabled())
+            LOG.info("New Indexer Task submitted - Action: " + action
+                    + " for service: " + serviceName);
+        ServiceIndex bean = this.indexerMap.get(serviceName);
+        if (bean == null)
+            throw new RuntimeException("no indexer for service " + serviceName
+                    + " registered");
+        /*
+         * lock on service to synchronize the event order. This lock has
+         * fairness parameter set to true. Grant access to the longest waiting
+         * thread. Using fairness is slower but is acceptable in this context
+         */
+        Lock lock = bean.getLock();
+        lock.lock();
+        try {
+            IndexSchema schema = bean.getSchema();
+            boolean commitAfter = bean.incrementActionAndReset(schema.getCommitAfterDocuments());
+            IndexDocumentBuilder<IndexDocument> callable = new IndexDocumentBuilderTask<IndexDocument>(
+                    entry, bean.getSchema(), action, commitAfter,bean.getOptimize(schema.getOptimizeAfterCommit()));
+            Future<IndexDocument> task = this.taskExecutor.submit(callable);
+            GDataIndexer indexer = bean.getIndexer();
+            try {
+                indexer.addIndexableDocumentTask(task);
+            } catch (InterruptedException e) {
+                throw new GdataIndexerException(
+                        "Can not accept any index tasks -- interrupted. ", e);
+
+            }
+        } finally {
+            /*
+             * make sure to unlock
+             */
+            lock.unlock();
+        }
+
+    }
+
+    
+
+    /**
+     * @see org.apache.lucene.gdata.search.SearchComponent#getServiceSearcher(org.apache.lucene.gdata.server.registry.ProvidedService)
+     */
+    public GDataSearcher<String> getServiceSearcher(ProvidedService service) {
+        if (this.destroyed.get())
+            throw new IllegalStateException(
+                    "IndexController has been destroyed");
+        /*
+         * get and increment. searcher will be decremented if GdataSearcher is
+         * closed
+         */
+        ReferenceCounter<IndexSearcher> searcher;
+        synchronized (this) {
+            ServiceIndex serviceIndex = this.indexerMap.get(service.getName());
+            if(serviceIndex == null)
+                throw new RuntimeException("no index for service "+service.getName());
+            searcher = serviceIndex.getSearcher();
+            searcher.increamentReference();
+        }
+
+        return new StandardGdataSearcher(searcher);
+    }
+
+    /**
+     * @see org.apache.lucene.gdata.search.SearchComponent#destroy()
+     */
+    public synchronized void destroy() {
+        if (this.destroyed.get())
+            throw new IllegalStateException(
+                    "IndexController has been destroyed");
+        if (!this.isInitialized.get())
+            return;
+        this.destroyed.set(true);
+        this.isInitialized.set(false);
+        LOG.info("Shutting down IndexController -- destroy has been called");
+        Set<Entry<String, ServiceIndex>> entrySet = this.indexerMap.entrySet();
+        for (Entry<String, ServiceIndex> entry : entrySet) {
+            ServiceIndex bean = entry.getValue();
+            bean.getSearcher().decrementRef();
+            GDataIndexer indexer = bean.getIndexer();
+            try {
+                indexer.destroy();
+            } catch (IOException e) {
+                LOG.warn("Can not destroy indexer for service: "
+                        + bean.getSchema().getName(), e);
+            }
+        }
+        this.taskExecutor.shutdown();
+        this.indexerMap.clear();
+    }
+
+    static class ServiceIndex {
+        private AtomicInteger actionCount = new AtomicInteger(0);
+        
+        private AtomicInteger commitCount = new AtomicInteger(0);
+        
+        private final Lock lock;
+
+        private final IndexSchema schema;
+
+        private final GDataIndexer indexer;
+
+        private final Directory directory;
+        
+        private Filter addedDocumentFilter;
+        
+        private ReferenceCounter<IndexSearcher> searcher;
+
+        // private final Map<String,IndexAction> actionMap;
+
+       
+
+        ServiceIndex(final IndexSchema schema, GDataIndexer indexer,
+                Directory directory) {
+            this.schema = schema;
+            this.indexer = indexer;
+            this.lock = new ReentrantLock(true);
+            this.directory = directory;
+            // this.actionMap = new HashMap<String,IndexAction>(128);
+        }
+
+        Lock getLock() {
+            return this.lock;
+        }
+
+        /**
+         * @return Returns the indexer.
+         */
+        GDataIndexer getIndexer() {
+            return this.indexer;
+        }
+
+        /**
+         * @return Returns the schema.
+         */
+        IndexSchema getSchema() {
+            return this.schema;
+        }
+
+        // public void addAction(IndexAction action,ServerBaseEntry entry){
+        //            
+        // }
+        /**
+         * Counts how many actions have been executed on this index
+         * 
+         * @param reset - count mod reset value equals 0 causes a commit
+         *            
+         * @return <code>true</code> if the count mod reset value equals 0, otherwise
+         *         false;
+         */
+        boolean incrementActionAndReset(int reset) {
+            if (this.actionCount.incrementAndGet()%reset == 0) {
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * @return Returns the directory.
+         */
+        public Directory getDirectory() {
+            return this.directory;
+        }
+        /**
+         * @return Returns the addedDocumentFilter.
+         */
+        public Filter getAddedDocumentFilter() {
+            return this.addedDocumentFilter;
+        }
+
+        /**
+         * @param addedDocumentFilter The addedDocumentFilter to set.
+         */
+        public void setAddedDocumentFilter(Filter addedDocumentFilter) {
+            this.addedDocumentFilter = addedDocumentFilter;
+        }
+
+        /**
+         * @return Returns the searcher.
+         */
+        public ReferenceCounter<IndexSearcher> getSearcher() {
+            return this.searcher;
+        }
+
+        /**
+         * @param searcher The searcher to set.
+         */
+        public void setSearcher(ReferenceCounter<IndexSearcher> searcher) {
+            this.searcher = searcher;
+        }
+
+        /**
+         * @return Returns the commitCount.
+         */
+        public int commitCountIncrement() {
+            return this.commitCount.incrementAndGet();
+        }
+        /**
+         * @param reset - the number after how many commits the index should be optimized
+         * @return <code>true</code> if and only if the commit count mod reset equals 0, otherwise <code>false</code>.
+         */
+        public boolean getOptimize(int reset){
+            if(this.commitCount.get()%reset == 0){
+                return true;
+            }
+            return false;
+        }
+    }
+}

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexController.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexController.java
------------------------------------------------------------------------------
    svn:executable = *

Added: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocument.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocument.java?rev=430568&view=auto
==============================================================================
--- lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocument.java (added)
+++ lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocument.java Thu Aug 10 15:32:40 2006
@@ -0,0 +1,100 @@
+/** 
+ * 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.lucene.gdata.search.index;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.index.Term;
+
+/**
+ * IndexDocument encapsulates the acual entity to store, update or delete. All
+ * infomation to process the action on this document are provided via this
+ * interface.
+ * <p>
+ * This enables the GDataIndexer to index every kind of document. All the
+ * processing of the original document happens somewhere behind this facade.
+ * {@link org.apache.lucene.gdata.search.index.IndexDocumentBuilderTask} passed
+ * to the {@link org.apache.lucene.gdata.search.index.GDataIndexer} task queue
+ * produce instances of this interface concurrently.
+ * </p>
+ * 
+ * @author Simon Willnauer
+ * 
+ * 
+ */
+public interface IndexDocument {
+    /**
+     * the index field to identify a document in the index. This acts as a
+     * primary key to fetch the entire entry from the storage
+     */
+    public static final String FIELD_ENTRY_ID = "enryId";
+    /**
+     * the index field to associate a document with a specific feed 
+     */
+    public static final String FIELD_FEED_ID = "feedId";
+    public static final String GDATA_MANDATORY_FIELD_UPDATED = "updated";
+    public static final String GDATA_MANDATORY_FIELD_CATEGORY = "category";
+
+    /**
+     * @return <code>true</code> if and only if this document is an update,
+     *         otherwise <code>false</code>
+     */
+    public abstract boolean isUpdate();
+
+    /**
+     * @return <code>true</code> if and only if this document is a delete,
+     *         otherwise <code>false</code>
+     */
+    public abstract boolean isDelete();
+
+    /**
+     * @return <code>true</code> if and only if this document is an insert,
+     *         otherwise <code>false</code>
+     */
+    public abstract boolean isInsert();
+
+    /**
+     * 
+     * @return - the lucene document to write to the index if the action is
+     *         insert or updated, otherwise it will return <code>null</code>;
+     */
+    public abstract Document getWriteable();
+
+    /**
+     * @return - a term that identifies this document in the index to delete
+     *         this document on a update or delete
+     */
+    public abstract Term getDeletealbe();
+
+    /**
+     * Indicates that the index should be commited after this document has been
+     * processed
+     * 
+     * @return <code>true</code> if the index should be commited after this
+     *         document, otherwise <code>false</code>
+     */
+    public abstract boolean commitAfter();
+
+    /**
+     * Indicates that the index should be optimized after this document has been
+     * processed
+     * 
+     * 
+     * @return <code>true</code> if the index should be optimized after this
+     *         document, otherwise <code>false</code>
+     */
+    public abstract boolean optimizeAfter();
+    
+}

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocument.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/java/trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocument.java
------------------------------------------------------------------------------
    svn:executable = *



Mime
View raw message