Index: gdata-server/webroot/WEB-INF/classes/gdata-config.xsd =================================================================== --- gdata-server/webroot/WEB-INF/classes/gdata-config.xsd (revision 426779) +++ gdata-server/webroot/WEB-INF/classes/gdata-config.xsd (working copy) @@ -1,26 +1,23 @@ - + + + This Schema defines the configuration for the + gdata-config.xml file. + + + - - - - - - - - @@ -30,6 +27,8 @@ minOccurs="1" /> + @@ -37,7 +36,18 @@ use="required" /> + + + + + + + + + + @@ -55,6 +65,10 @@ maxOccurs="unbounded" /> + + + + @@ -66,5 +80,162 @@ minOccurs="1" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: gdata-server/webroot/WEB-INF/classes/gdata-config.xml =================================================================== --- gdata-server/webroot/WEB-INF/classes/gdata-config.xml (revision 426779) +++ gdata-server/webroot/WEB-INF/classes/gdata-config.xml (working copy) @@ -6,6 +6,64 @@ com.google.gdata.data.ExtensionProfile + + + + org.apache.lucene.analysis.StandardAnalyzer + + /tmp/search + true + 10 + 1000 + 2147483647 + 10000 + + + + /entry/title + + org.apache.lucene.analysis.SimpleAnalyzer + + + + /entry/summary + + org.apache.lucene.analysis.SimpleAnalyzer + + + + /entry/content + /entry/content/@type + + org.apache.lucene.analysis.StopAnalyzer + + YES + TOKENIZED + + + /entry/author/name + + org.apache.lucene.analysis.StopAnalyzer + + + + /entry/updated + + + /entry/category/@term + + + + @@ -17,19 +75,69 @@ com.google.gdata.data.ExtensionProfile + + + + + org.apache.lucene.analysis.StandardAnalyzer + + /tmp/search + false + 10 + 1000 + 10000 + 10000 + + + /entry/title + + org.apache.lucene.analysis.SimpleAnalyzer + + + + /entry/summary + + org.apache.lucene.analysis.SimpleAnalyzer + + + + /entry/content + /entry/content/@type + + org.apache.lucene.analysis.StopAnalyzer + + YES + TOKENIZED + + + /entry/author/name + + org.apache.lucene.analysis.StopAnalyzer + + + + /entry/updated + + + /entry/category/@term + + + - org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController + org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController 20 20 20 - /tmp/storage + + /tmp/storage + true - false + false @@ -38,6 +146,11 @@ + + org.apache.lucene.gdata.search.index.IndexController + + + org.apache.lucene.gdata.server.ServiceFactory Index: gdata-server/lib/xercesImpl.jar =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: gdata-server/lib/xercesImpl.jar ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: gdata-server/lib/nekohtml.jar =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: gdata-server/lib/nekohtml.jar ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: gdata-server/src/test/org/apache/lucene/gdata/utils/ProvidedServiceStub.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/utils/ProvidedServiceStub.java (revision 426779) +++ gdata-server/src/test/org/apache/lucene/gdata/utils/ProvidedServiceStub.java (working copy) @@ -1,5 +1,6 @@ package org.apache.lucene.gdata.utils; +import org.apache.lucene.gdata.search.config.IndexSchema; import org.apache.lucene.gdata.server.registry.ProvidedService; import com.google.gdata.data.Entry; @@ -9,6 +10,7 @@ public class ProvidedServiceStub implements ProvidedService { public static final String SERVICE_NAME = "service"; + private IndexSchema indexSchema; public ProvidedServiceStub() { super(); @@ -37,5 +39,13 @@ public void destroy() { } + public void setIndexSchema(IndexSchema schema){ + this.indexSchema = schema; + this.indexSchema.setName(SERVICE_NAME); + } + public IndexSchema getIndexSchema() { + + return this.indexSchema; + } } Index: gdata-server/src/test/org/apache/lucene/gdata/servlet/handler/TestAbstractFeedHandler.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/servlet/handler/TestAbstractFeedHandler.java (revision 426779) +++ gdata-server/src/test/org/apache/lucene/gdata/servlet/handler/TestAbstractFeedHandler.java (working copy) @@ -27,6 +27,7 @@ import org.apache.lucene.gdata.data.GDataAccount; import org.apache.lucene.gdata.data.ServerBaseFeed; +import org.apache.lucene.gdata.server.GDataResponse; import org.apache.lucene.gdata.server.ServiceException; import org.apache.lucene.gdata.server.ServiceFactory; import org.apache.lucene.gdata.server.administration.AdminService; @@ -184,7 +185,7 @@ .getParameter(AbstractFeedHandler.PARAMETER_ACCOUNT), this.accountName); a.setName("helloworld"); - this.adminServiceMockControl.expectAndDefaultThrow(this.adminService.getAccount(this.accountName),new ServiceException() ); + this.adminServiceMockControl.expectAndDefaultThrow(this.adminService.getAccount(this.accountName),new ServiceException(GDataResponse.BAD_REQUEST) ); this.requestMockControl.replay(); this.adminServiceMockControl.replay(); handler = new InsertFeedHandler(); Index: gdata-server/src/test/org/apache/lucene/gdata/storage/db4o/TestDb4oStorage.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/storage/db4o/TestDb4oStorage.java (revision 426779) +++ gdata-server/src/test/org/apache/lucene/gdata/storage/db4o/TestDb4oStorage.java (working copy) @@ -541,7 +541,8 @@ account.setName("simon"); account.setPassword("newPass"); storage.updateAccount(account); - + container.close(); + container = getContainer(); q = container.query(); q.constrain(GDataAccount.class); q.descend("name").constrain(account.getName()); @@ -570,7 +571,8 @@ assertEquals(1, set.size()); storage.deleteAccount(account.getName()); - + container.close(); + container = getContainer(); q = container.query(); q.constrain(GDataAccount.class); q.descend("name").constrain(account.getName()); Index: gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestGdataCategoryStrategy.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestGdataCategoryStrategy.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestGdataCategoryStrategy.java (revision 0) @@ -0,0 +1,105 @@ +/** + * 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.analysis; + +import junit.framework.TestCase; + +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.apache.lucene.gdata.search.index.GdataIndexerException; + +/** + * @author Simon Willnauer + * + */ +public class TestGdataCategoryStrategy extends TestCase { + private static final String FIELD = "foo"; + + private static final float BOOST = 2.0f; + + GdataCategoryStrategy strategy; + + private IndexSchemaField field; + + protected void setUp() throws Exception { + this.field = new IndexSchemaField(); + field.setName(FIELD); + //store and index will be ignored + field.setStore(Field.Store.NO); + field.setIndex(Field.Index.TOKENIZED); + field.setBoost(BOOST); + field.setPath("/path"); + this.strategy = new GdataCategoryStrategy(field); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.analysis.PlainTextStrategy.processIndexable(Indexable)' + */ + public void testProcessIndexable() throws NotIndexableException { + IndexableStub stub = new IndexableStub(); + stub.setReturnNull(true); + try { + this.strategy.processIndexable(stub); + fail("retun value is null must fail"); + } catch (NotIndexableException e) { + } + assertNull(this.strategy.content); + try { + this.strategy.createLuceneField(); + fail("content is not set"); + } catch (GdataIndexerException e) { + } + + String content = "fooBar"; + stub.setReturnNull(false); + stub.setReturnValueTextContent(content); + this.strategy.processIndexable(stub); + assertNotNull(this.strategy.content); + assertNotNull(this.strategy.categoryScheme); + assertEquals(content, this.strategy.content); + assertEquals(content, this.strategy.categoryScheme); + + Field[] fields = this.strategy.createLuceneField(); + assertEquals(2, fields.length); + assertEquals(this.field.getName(), fields[0].name()); + assertEquals(content, fields[0].stringValue()); + assertEquals(this.strategy.categorySchemeField, fields[1].name()); + assertEquals(content, fields[1].stringValue()); + // this is also stored an untok. + assertTrue(fields[0].isStored()); + assertFalse(fields[0].isTokenized()); + // test for xpath exc. + this.field.setPath(null); + this.strategy = new GdataCategoryStrategy(field); + try { + this.strategy.processIndexable(stub); + fail("path is null must fail"); + } catch (NotIndexableException e) { + } + try { + this.strategy.createLuceneField(); + fail("content is not set"); + } catch (GdataIndexerException e) { + } + } + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestGdataDateStrategy.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestGdataDateStrategy.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestGdataDateStrategy.java (revision 0) @@ -0,0 +1,115 @@ +/** + * 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.analysis; + +import junit.framework.TestCase; + +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.apache.lucene.gdata.search.index.GdataIndexerException; + +import com.google.gdata.data.DateTime; + +/** + * @author Simon Willnauer + * + */ +public class TestGdataDateStrategy extends TestCase { + private static final String FIELD = "foo"; + + private static final float BOOST = 2.0f; + + ContentStrategy strategy; + + private IndexSchemaField field; + + protected void setUp() throws Exception { + this.field = new IndexSchemaField(); + field.setName(FIELD); + field.setStore(Field.Store.NO); + field.setIndex(Field.Index.TOKENIZED); + field.setBoost(BOOST); + field.setPath("/path"); + this.strategy = new GdataDateStrategy(field); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.analysis.PlainTextStrategy.processIndexable(Indexable)' + */ + public void testProcessIndexable() throws NotIndexableException { + IndexableStub stub = new IndexableStub(); + stub.setReturnNull(true); + try { + this.strategy.processIndexable(stub); + fail("retun value is null must fail"); + } catch (NotIndexableException e) { + } + assertNull(this.strategy.content); + try { + this.strategy.createLuceneField(); + fail("content is not set"); + } catch (GdataIndexerException e) { + } + // test with proper date + String content = "2005-01-09T08:00:00Z"; + String parsedConent = Long.toString(DateTime.parseDateTime(content) + .getValue()); + stub.setReturnNull(false); + stub.setReturnValueTextContent(content); + this.strategy.processIndexable(stub); + assertNotNull(this.strategy.content); + assertEquals(parsedConent, this.strategy.content); + + Field[] fields = this.strategy.createLuceneField(); + assertEquals(1, fields.length); + assertEquals(this.field.getName(), fields[0].name()); + assertEquals(parsedConent, fields[0].stringValue()); + // timestamp is stored and untok. + assertTrue(fields[0].isStored()); + assertFalse(fields[0].isTokenized()); + + this.strategy = new GdataDateStrategy(this.field); + content = "2005-01-09T##08:00:00Z"; + stub.setReturnValueTextContent(content); + try { + this.strategy.processIndexable(stub); + fail("unparsable date must fail"); + } catch (NotIndexableException e) { + } + + + // test for xpath exc. + this.field.setPath(null); + this.strategy = new GdataDateStrategy(this.field); + try { + this.strategy.processIndexable(stub); + fail("path is null must fail"); + } catch (NotIndexableException e) { + } + try { + this.strategy.createLuceneField(); + fail("content is not set"); + } catch (GdataIndexerException e) { + } + + } +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestHTMLStrategy.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestHTMLStrategy.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestHTMLStrategy.java (revision 0) @@ -0,0 +1,75 @@ +/** + * 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.analysis; + +import junit.framework.TestCase; + +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.search.config.IndexSchemaField; + +/** + * @author Simon Willnauer + * + */ +public class TestHTMLStrategy extends TestCase { + private static final String FIELD = "foo"; + private static final float BOOST = 2.0f; + ContentStrategy strategy; + private IndexSchemaField field; + protected void setUp() throws Exception { + this.field = new IndexSchemaField(); + field.setName(FIELD); + field.setStore(Field.Store.YES); + field.setIndex(Field.Index.UN_TOKENIZED); + field.setBoost(BOOST); + field.setPath("/path"); + this.strategy = new HTMLStrategy(field); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + /* + * Test method for 'org.apache.lucene.gdata.search.analysis.PlainTextStrategy.processIndexable(Indexable)' + */ + public void testProcessIndexable() throws NotIndexableException { + IndexableStub stub = new IndexableStub(); + stub.setReturnNull(true); + try{ + this.strategy.processIndexable(stub); + fail("retun value is null must fail"); + }catch (NotIndexableException e) {} + assertNull(this.strategy.content); + String content = "fooBar"; + //just to make sure the filter is applied. + String htmlContent = ""+content+""; + stub.setReturnNull(false); + stub.setReturnValueTextContent(htmlContent); + this.strategy.processIndexable(stub); + assertNotNull(this.strategy.content); + assertEquals(content,this.strategy.content); + + + // test for xpath exc. + this.field.setPath(null); + try{ + this.strategy.processIndexable(stub); + fail("path is null must fail"); + }catch (NotIndexableException e) {} + } + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestKeywordStrategy.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestKeywordStrategy.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestKeywordStrategy.java (revision 0) @@ -0,0 +1,104 @@ +/** + * 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.analysis; + +import junit.framework.TestCase; + +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.apache.lucene.gdata.search.index.GdataIndexerException; + +/** + * @author Simon Willnauer + * + */ +public class TestKeywordStrategy extends TestCase { + private static final String FIELD = "foo"; + + private static final float BOOST = 2.0f; + + ContentStrategy strategy; + + private IndexSchemaField field; + + protected void setUp() throws Exception { + this.field = new IndexSchemaField(); + field.setName(FIELD); + field.setStore(Field.Store.NO); + field.setIndex(Field.Index.TOKENIZED); + field.setBoost(BOOST); + field.setPath("/path"); + + this.strategy = new KeywordStrategy(field); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.analysis.PlainTextStrategy.processIndexable(Indexable)' + */ + public void testProcessIndexable() throws NotIndexableException { + IndexableStub stub = new IndexableStub(); + stub.setReturnNull(true); + try { + this.strategy.processIndexable(stub); + fail("retun value is null must fail"); + } catch (NotIndexableException e) { + } + assertNull(this.strategy.content); + try { + this.strategy.createLuceneField(); + fail("content is not set"); + } catch (GdataIndexerException e) { + } + + String content = "fooBar"; + stub.setReturnNull(false); + stub.setReturnValueTextContent(content); + this.strategy.processIndexable(stub); + assertNotNull(this.strategy.content); + assertEquals(content, this.strategy.content); + + Field[] fields = this.strategy.createLuceneField(); + assertEquals(1, fields.length); + assertEquals(this.field.getName(), fields[0].name()); + assertEquals(content, fields[0].stringValue()); + // this is also stored an untok. + assertTrue(fields[0].isStored()); + assertFalse(fields[0].isTokenized()); + + + // test for xpath exc. + this.field.setPath(null); + this.strategy = new KeywordStrategy(field); + try { + this.strategy.processIndexable(stub); + fail("path is null must fail"); + } catch (NotIndexableException e) { + } + try { + this.strategy.createLuceneField(); + fail("content is not set"); + } catch (GdataIndexerException e) { + } + + } + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/analysis/IndexableStub.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/analysis/IndexableStub.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/analysis/IndexableStub.java (revision 0) @@ -0,0 +1,80 @@ +/** + * 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.analysis; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import javax.xml.xpath.XPathExpressionException; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * @author Simon Willnauer + * + */ +public class IndexableStub extends Indexable { + + private String content; + private boolean retNull; + IndexableStub() { + super(null); + + } + public void setReturnNull(boolean returnNull){ + this.retNull = returnNull; + } + public void setReturnValueTextContent(String content){ + this.content = content; + } + @Override + public Node applyPath(String xPath) throws XPathExpressionException { + if(xPath == null) + throw new XPathExpressionException("path is null"); + if(this.retNull) + return null; + return (Node)Proxy.newProxyInstance(this.getClass().getClassLoader(),new Class[] {Node.class,NamedNodeMap.class},new Handler(this.content)); + + } + + private static class Handler implements InvocationHandler{ + String returnValue; + public Handler(String toReturn){ + this.returnValue = toReturn; + } + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if(method.getReturnType() == String.class) + return this.returnValue; + if(method.getReturnType() == Node.class) + return (Node)Proxy.newProxyInstance(this.getClass().getClassLoader(),new Class[] {Node.class,NamedNodeMap.class},new Handler(this.returnValue)); + if(method.getReturnType() == NamedNodeMap.class) + return (NamedNodeMap)Proxy.newProxyInstance(this.getClass().getClassLoader(),new Class[] {Node.class,NamedNodeMap.class},new Handler(this.returnValue)); + return null; + } + + } + +// public static void main(String[] args) throws XPathExpressionException { +// IndexableStub stub = new IndexableStub(); +// stub.setReturnValueTextContent("foobar"); +// System.out.println(stub.applyPath("/path")); +// System.out.println(stub.applyPath("/path").getAttributes().getNamedItem("test").getTextContent()); +// } + +} + Index: gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestMixedStrategy.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestMixedStrategy.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestMixedStrategy.java (revision 0) @@ -0,0 +1,102 @@ +/** + * 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.analysis; + +import junit.framework.TestCase; + +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.search.config.IndexSchemaField; + +/** + * @author Simon Willnauer + * + */ +public class TestMixedStrategy extends TestCase { + private static final String FIELD = "foo"; + + private static final float BOOST = 2.0f; + + MixedContentStrategy strategy; + + private IndexSchemaField field; + + protected void setUp() throws Exception { + this.field = new IndexSchemaField(); + field.setName(FIELD); + + field.setStore(Field.Store.YES); + field.setIndex(Field.Index.UN_TOKENIZED); + field.setBoost(BOOST); + field.setPath("/path"); + field.setTypePath("/path"); + this.strategy = new MixedContentStrategy(field); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.analysis.PlainTextStrategy.processIndexable(Indexable)' + */ + public void testProcessIndexable() throws NotIndexableException { + IndexableStub stub = new IndexableStub(); + stub.setReturnNull(true); + try { + this.strategy.processIndexable(stub); + fail("retun value is null must fail"); + } catch (NotIndexableException e) { + } + assertNull(this.strategy.content); + String content = "fooBar"; + stub.setReturnNull(false); + stub.setReturnValueTextContent(content); + this.strategy.processIndexable(stub); + assertNotNull(this.strategy.strategy.content); + assertEquals(content, this.strategy.strategy.content); + assertEquals(this.strategy.strategy.getClass(), PlainTextStrategy.class); + + + + content = "html"; + stub.setReturnNull(false); + stub.setReturnValueTextContent(content); + this.strategy.processIndexable(stub); + assertNotNull(this.strategy.strategy.content); + assertEquals(content, this.strategy.strategy.content); + assertEquals(this.strategy.strategy.getClass(), HTMLStrategy.class); + + content = "xhtml"; + stub.setReturnNull(false); + stub.setReturnValueTextContent(content); + this.strategy.processIndexable(stub); + assertNotNull(this.strategy.strategy.content); + assertEquals(content, this.strategy.strategy.content); + assertEquals(this.strategy.strategy.getClass(), XHtmlStrategy.class); + + + // test for xpath exc. + this.field.setPath(null); + try { + this.strategy.processIndexable(stub); + fail("path is null must fail"); + } catch (NotIndexableException e) { + } + } + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestDomIndexable.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestDomIndexable.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestDomIndexable.java (revision 0) @@ -0,0 +1,81 @@ +/** + * 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.analysis; + +import javax.xml.xpath.XPathExpressionException; + +import junit.framework.TestCase; + +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.apache.lucene.gdata.server.registry.ProvidedServiceConfig; +import org.apache.lucene.gdata.utils.ProvidedServiceStub; +import org.w3c.dom.Attr; +import org.w3c.dom.Node; + +import com.google.gdata.data.HtmlTextConstruct; + +public class TestDomIndexable extends TestCase { + + + public void testConstructor(){ + try { + new DomIndexable(new ServerBaseEntry()); + fail("no service config"); + } catch (NotIndexableException e) { + + + } + ServerBaseEntry e = new ServerBaseEntry(); + e.setServiceConfig(new ProvidedServiceConfig()); + try { + new DomIndexable(e); + fail("no extension profile"); + } catch (IllegalStateException e1) { + + + } catch (NotIndexableException e2) { + + fail("unexp. exception"); + } + e.setServiceConfig(new ProvidedServiceStub()); + try { + new DomIndexable(e); + } catch (NotIndexableException e1) { + fail("unexp. exception"); + + } + } + /* + * Test method for 'org.apache.lucene.gdata.search.analysis.DomIndexable.applyPath(String)' + */ + public void testApplyPath() throws NotIndexableException, XPathExpressionException { + String content = "fooo bar
"; + ServerBaseEntry entry = new ServerBaseEntry(); + entry.setContent(new HtmlTextConstruct(content)); + entry.setServiceConfig(new ProvidedServiceStub()); + + Indexable ind = new DomIndexable(entry); + Node n = ind.applyPath("/entry/content"); + assertNotNull(n); + assertEquals(content,n.getTextContent()); + Node attr = ind.applyPath("/entry/content/@type"); + assertNotNull(attr); + assertEquals("html",attr.getTextContent()); + assertTrue(attr instanceof Attr); + + } + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestPlainTextStrategy.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestPlainTextStrategy.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestPlainTextStrategy.java (revision 0) @@ -0,0 +1,73 @@ +/** + * 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.analysis; + +import junit.framework.TestCase; + +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.search.config.IndexSchemaField; + +/** + * @author Simon Willnauer + * + */ +public class TestPlainTextStrategy extends TestCase { + private static final String FIELD = "foo"; + private static final float BOOST = 2.0f; + ContentStrategy strategy; + private IndexSchemaField field; + protected void setUp() throws Exception { + this.field = new IndexSchemaField(); + field.setName(FIELD); + field.setStore(Field.Store.YES); + field.setIndex(Field.Index.UN_TOKENIZED); + field.setBoost(BOOST); + field.setPath("/path"); + this.strategy = new PlainTextStrategy(field); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + /* + * Test method for 'org.apache.lucene.gdata.search.analysis.PlainTextStrategy.processIndexable(Indexable)' + */ + public void testProcessIndexable() throws NotIndexableException { + IndexableStub stub = new IndexableStub(); + stub.setReturnNull(true); + try{ + this.strategy.processIndexable(stub); + fail("retun value is null must fail"); + }catch (NotIndexableException e) {} + assertNull(this.strategy.content); + String content = "fooBar"; + stub.setReturnNull(false); + stub.setReturnValueTextContent(content); + this.strategy.processIndexable(stub); + assertNotNull(this.strategy.content); + assertEquals(content,this.strategy.content); + + + // test for xpath exc. + this.field.setPath(null); + try{ + this.strategy.processIndexable(stub); + fail("path is null must fail"); + }catch (NotIndexableException e) {} + } + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestContentStrategy.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestContentStrategy.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/analysis/TestContentStrategy.java (revision 0) @@ -0,0 +1,130 @@ +/** + * 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.analysis; + +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.data.ServerBaseEntry; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.apache.lucene.gdata.search.index.GdataIndexerException; +import org.w3c.dom.Node; + +import junit.framework.TestCase; + +public class TestContentStrategy extends TestCase { + private static final String FIELD = "foo"; + private static final float BOOST = 2.0f; + ContentStrategy strategy; + + protected void setUp() throws Exception { + IndexSchemaField field = new IndexSchemaField(); + field.setName(FIELD); + field.setStore(Field.Store.YES); + field.setIndex(Field.Index.UN_TOKENIZED); + field.setBoost(BOOST); + this.strategy = new TestStrategy(field); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + public void testContentStrategyIndexStoreField() throws NotIndexableException{ + IndexSchemaField field = new IndexSchemaField(); + field.setName(FIELD); + + + this.strategy = new TestStrategy(Field.Index.UN_TOKENIZED,Field.Store.YES,field); + this.strategy.processIndexable(null); + Field f = this.strategy.createLuceneField()[0]; + assertEquals(FIELD,f.name()); + assertEquals(TestStrategy.CONTENT,f.stringValue()); + assertEquals(1.0f,f.getBoost()); + assertTrue(f.isIndexed()); + assertTrue(f.isStored()); + assertFalse(f.isTokenized()); + assertFalse(f.isCompressed()); + } + + /* + * Test method for 'org.apache.lucene.gdata.search.analysis.ContentStrategy.ContentStrategy(Index, Store, IndexSchemaField)' + */ + public void testContentStrategyIndexSchemaField() throws NotIndexableException { + IndexSchemaField field = new IndexSchemaField(); + field.setName(FIELD); + + + this.strategy = new TestStrategy(field); + this.strategy.processIndexable(null); + Field f = this.strategy.createLuceneField()[0]; + + assertEquals(FIELD,f.name()); + assertEquals(TestStrategy.CONTENT,f.stringValue()); + assertEquals(1.0f,f.getBoost()); + assertTrue(f.isIndexed()); + assertFalse(f.isStored()); + assertTrue(f.isTokenized()); + assertFalse(f.isCompressed()); + } + + /* + * Test method for 'org.apache.lucene.gdata.search.analysis.ContentStrategy.createLuceneField()' + */ + public void testCreateLuceneField() throws NotIndexableException { + try{ + this.strategy.createLuceneField(); + fail("processIndexable is not called"); + }catch (GdataIndexerException e) { + // + } + this.strategy.processIndexable(null); + Field f = this.strategy.createLuceneField()[0]; + + assertEquals(FIELD,f.name()); + assertEquals(TestStrategy.CONTENT,f.stringValue()); + assertEquals(BOOST,f.getBoost()); + assertTrue(f.isIndexed()); + assertTrue(f.isStored()); + assertFalse(f.isTokenized()); + assertFalse(f.isCompressed()); + + + + } + + private static class TestStrategy extends ContentStrategy{ + + private static final String CONTENT = "someString"; + + + protected TestStrategy(Index index, Store store, IndexSchemaField fieldConfig) { + super(index, store, fieldConfig); + + } + + protected TestStrategy(IndexSchemaField fieldConfiguration) { + super(fieldConfiguration); + + } + + @Override + public void processIndexable(Indexable indexable) throws NotIndexableException { + this.content = CONTENT; + } + + } + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/index/TestGdataIndexer.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/index/TestGdataIndexer.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/index/TestGdataIndexer.java (revision 0) @@ -0,0 +1,470 @@ +/** + * 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.concurrent.CountDownLatch; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import junit.framework.TestCase; + +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.search.config.IndexSchema; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.Hits; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.RAMDirectory; + +/** + * @author Simon Willnauer + * + */ +public class TestGdataIndexer extends TestCase { + private GDataIndexer indexer; + + private Directory dir; + + private static IndexSchema config; + + private static String FIELD_ID = "id"; + + static { + config = new IndexSchema(); + config.setName("testService"); + config.setCommitLockTimeout(-1); + config.setServiceAnalyzer(new StandardAnalyzer()); + config.setMaxBufferedDocs(-1); + config.setMaxFieldLength(-1); + config.setMaxMergeDocs(-1); + config.setWriteLockTimeout(-1); + config.setMergeFactor(-1); + } + + /** + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + this.dir = new RAMDirectory(); + this.indexer = GDataIndexer.createGdataIndexer(config, this.dir, true); + super.setUp(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + this.indexer.destroy(); + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.GDataIndexer(IndexServiceConfiguration, + * Directory, boolean)' + */ + public void testGDataIndexer() throws InterruptedException, IOException { + try { + new GDataIndexer(null, dir, true); + fail("config is null"); + } catch (IllegalArgumentException e) { + // + } + + try { + new GDataIndexer(config, null, true); + fail("dir is null"); + } catch (IllegalArgumentException e) { + // + } + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.addIndexableDocumentTask(Future)' + */ + public void testAddIndexableDocumentTask() throws InterruptedException, + IOException { + String id = "myID"; + Field f = new Field(FIELD_ID, id, Field.Store.YES, + Field.Index.UN_TOKENIZED); + Document doc = new Document(); + doc.add(f); + Term delTerm = new Term(FIELD_ID, id); + /* + * Latch will be decremented in FutureStub#get() and + * IndexDocumentStub#getIndexable + */ + CountDownLatch l = new CountDownLatch(2); + IndexDocument iDoc = new IndexDocumentStub(doc, delTerm, + IndexAction.INSERT, l); + Future future = new FutureStub(iDoc, l); + + this.indexer.addIndexableDocumentTask(future); + // wait for the latch do decrement + l.await(5000, TimeUnit.MILLISECONDS); + + this.indexer.commit(false); + IndexSearcher s = new IndexSearcher(this.dir); + Hits h = s.search(new TermQuery(delTerm)); + assertEquals(1, h.length()); + s.close(); + // test for update + /* + * Latch will be decremented in FutureStub#get() and + * IndexDocumentStub#getIndexable + */ + l = new CountDownLatch(2); + iDoc = new IndexDocumentStub(doc, delTerm, IndexAction.UPDATE, l); + future = new FutureStub(iDoc, l); + this.indexer.addIndexableDocumentTask(future); + l.await(5000, TimeUnit.MILLISECONDS); + this.indexer.commit(false); + s = new IndexSearcher(this.dir); + h = s.search(new TermQuery(delTerm)); + assertEquals(1, h.length()); + s.close(); + + // test for delete + /* + * Latch will be decremented in FutureStub#get() + */ + l = new CountDownLatch(1); + iDoc = new IndexDocumentStub(doc, delTerm, IndexAction.DELETE, l); + future = new FutureStub(iDoc, l); + + this.indexer.addIndexableDocumentTask(future); + /* + * wait for the indexer task to add the deleted + */ + while (this.indexer.docsDeleted.get() == 0) + l.await(5000, TimeUnit.MILLISECONDS); + + this.indexer.commit(false); + s = new IndexSearcher(this.dir); + h = s.search(new TermQuery(delTerm)); + assertEquals(0, h.length()); + s.close(); + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.addDocument(IndexDocument)' + */ +public void testAddDocument() throws IOException { + String id = "myID"; + Field f = new Field(FIELD_ID, id, Field.Store.YES, + Field.Index.UN_TOKENIZED); + Document doc = new Document(); + doc.add(f); + Term delTerm = new Term(FIELD_ID, id); + IndexDocument iDoc = new IndexDocumentStub(doc,delTerm, + IndexAction.INSERT); + + this.indexer.addDocument(iDoc); + assertEquals(1,this.indexer.docsAdded.get()); + assertEquals(0,this.indexer.docsDeleted.get()); + assertEquals(0,this.indexer.docsUpdated.get()); + + this.indexer.commit(false); + + + IndexSearcher s = new IndexSearcher(this.dir); + Hits h = s.search(new TermQuery(delTerm)); + assertEquals(1, h.length()); + s.close(); + + } + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.updateDocument(IndexDocument)' + */ + public void testUpdateDocument() throws IOException { + + String id = "myID"; + Field f = new Field(FIELD_ID, id, Field.Store.YES, + Field.Index.UN_TOKENIZED); + Document doc = new Document(); + doc.add(f); + Term delTerm = new Term(FIELD_ID, id); + IndexDocument iDoc = new IndexDocumentStub(doc,delTerm, + IndexAction.INSERT); + /* + * write doc to index + */ + this.indexer.writer.addDocument(doc); + this.indexer.closeWriter(); + IndexSearcher s = new IndexSearcher(this.dir); + Hits h = s.search(new TermQuery(delTerm)); + assertEquals(1, h.length()); + s.close(); + + /* + * updateDoc via indexer + */ + this.indexer.updateDocument(iDoc); + assertEquals(0,this.indexer.docsAdded.get()); + assertEquals(0,this.indexer.docsDeleted.get()); + assertEquals(1,this.indexer.docsUpdated.get()); + + this.indexer.commit(false); + + + s = new IndexSearcher(this.dir); + h = s.search(new TermQuery(delTerm)); + assertEquals(1, h.length()); + s.close(); + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.deleteDocument(IndexDocument)' + */ + public void testDeleteDocument() throws IOException { + String id = "myID"; + Field f = new Field(FIELD_ID, id, Field.Store.YES, + Field.Index.UN_TOKENIZED); + Document doc = new Document(); + doc.add(f); + Term delTerm = new Term(FIELD_ID, id); + IndexDocument iDoc = new IndexDocumentStub(doc,delTerm, + IndexAction.INSERT); + /* + * write doc to index + */ + this.indexer.writer.addDocument(doc); + this.indexer.closeWriter(); + IndexSearcher s = new IndexSearcher(this.dir); + Hits h = s.search(new TermQuery(delTerm)); + assertEquals(1, h.length()); + s.close(); + + /* + * del doc via indexer + */ + this.indexer.deleteDocument(iDoc); + assertEquals(0,this.indexer.docsAdded.get()); + assertEquals(1,this.indexer.docsDeleted.get()); + assertEquals(0,this.indexer.docsUpdated.get()); + this.indexer.commit(false); + s = new IndexSearcher(this.dir); + h = s.search(new TermQuery(delTerm)); + assertEquals(0, h.length()); + s.close(); + + /* + * test insert / del without commit + */ + this.indexer.addDocument(iDoc); + this.indexer.deleteDocument(iDoc); + this.indexer.commit(false); + s = new IndexSearcher(this.dir); + h = s.search(new TermQuery(delTerm)); + assertEquals(0, h.length()); + s.close(); + + /* + * test insert / update / del without commit + */ + this.indexer.addDocument(iDoc); + this.indexer.updateDocument(iDoc); + this.indexer.deleteDocument(iDoc); + this.indexer.commit(false); + s = new IndexSearcher(this.dir); + h = s.search(new TermQuery(delTerm)); + assertEquals(0, h.length()); + s.close(); + + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.commit(boolean)' + */ + public void testCommit() throws IOException { + String id = "myID"; + Field f = new Field(FIELD_ID, id, Field.Store.YES, + Field.Index.UN_TOKENIZED); + Document doc = new Document(); + doc.add(f); + Term delTerm = new Term(FIELD_ID, id); + IndexDocument iDoc = new IndexDocumentStub(doc,delTerm, + IndexAction.INSERT); + this.indexer.addDocument(iDoc); + this.indexer.updateDocument(iDoc); + this.indexer.deleteDocument(iDoc); + IndexEventListenerStub evListener = new IndexEventListenerStub(); + this.indexer.registerIndexEventListener(evListener); + assertEquals(1,this.indexer.docsAdded.get()); + assertEquals(1,this.indexer.docsDeleted.get()); + assertEquals(1,this.indexer.docsUpdated.get()); + assertEquals(0,evListener.getCalledCount()); + this.indexer.commit(false); + assertEquals(1,evListener.getCalledCount()); + assertEquals(0,this.indexer.docsAdded.get()); + assertEquals(0,this.indexer.docsDeleted.get()); + assertEquals(0,this.indexer.docsUpdated.get()); + IndexSearcher s = new IndexSearcher(this.dir); + Hits h = s.search(new TermQuery(delTerm)); + assertEquals(0, h.length()); + s.close(); + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.registerIndexEventListener(IndexEventListener)' + */ + public void testRegisterIndexEventListener() { + IndexEventListenerStub evListener = new IndexEventListenerStub(); + this.indexer.registerIndexEventListener(evListener); + assertEquals(0,evListener.getCalledCount()); + this.indexer.notifyCommitListeners("someId"); + this.indexer.notifyCommitListeners("someId"); + assertEquals(2,evListener.getCalledCount()); + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.removeIndexEventListener(IndexEventListener)' + */ + public void testRemoveIndexEventListener() { + IndexEventListenerStub evListener = new IndexEventListenerStub(); + this.indexer.registerIndexEventListener(evListener); + assertEquals(0,evListener.getCalledCount()); + this.indexer.notifyCommitListeners("someId"); + assertEquals(1,evListener.getCalledCount()); + this.indexer.removeIndexEventListener(evListener); + this.indexer.notifyCommitListeners("someId"); + assertEquals(1,evListener.getCalledCount()); + + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.notifyCommitListeners(String)' + */ + public void testNotifyCommitListeners() { + IndexEventListenerStub evListener = new IndexEventListenerStub(); + IndexEventListenerStub evListener1 = new IndexEventListenerStub(); + IndexEventListenerStub evListener2 = new IndexEventListenerStub(); + this.indexer.registerIndexEventListener(evListener); + this.indexer.registerIndexEventListener(evListener1); + this.indexer.registerIndexEventListener(evListener2); + assertEquals(0,evListener.getCalledCount()); + this.indexer.notifyCommitListeners("someId"); + assertEquals(1,evListener.getCalledCount()); + assertEquals(1,evListener1.getCalledCount()); + assertEquals(1,evListener2.getCalledCount()); + this.indexer.removeIndexEventListener(evListener); + this.indexer.notifyCommitListeners("someId"); + assertEquals(1,evListener.getCalledCount()); + assertEquals(2,evListener1.getCalledCount()); + assertEquals(2,evListener2.getCalledCount()); + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.closeWriter()' + */ + public void testCloseWriter() throws IOException{ + assertNotNull(this.indexer.writer); + this.indexer.closeWriter(); + assertNull(this.indexer.writer); + + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.closeSearcher()' + */ + public void testCloseSearcher() throws IOException { + this.indexer.openSearcher(); + assertNotNull(this.indexer.searcher); + this.indexer.closeSearcher(); + assertNull(this.indexer.searcher); + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.openSearcher()' + */ + public void testOpenSearcher() throws IOException { + this.indexer.searcher = null; + this.indexer.openSearcher(); + assertNotNull(this.indexer.searcher); + } + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.openWriter()' + */ + public void testOpenWriter() throws IOException { + this.indexer.closeWriter(); + assertNull(this.indexer.writer); + this.indexer.openWriter(); + assertNotNull(this.indexer.writer); + } + + + /* + * Test method for + * 'org.apache.lucene.gdata.search.index.GDataIndexer.destroy()' + */ + public void testDestroy() throws InterruptedException, IOException { + this.indexer.destroy(); + String id = "myID"; + Field f = new Field(FIELD_ID, id, Field.Store.YES, + Field.Index.UN_TOKENIZED); + Document doc = new Document(); + doc.add(f); + Term delTerm = new Term(FIELD_ID, id); + IndexDocument iDoc = new IndexDocumentStub(doc, delTerm, + IndexAction.INSERT); + Future future = new FutureStub(iDoc); + try{ + this.indexer.addIndexableDocumentTask(future); + fail("indexer already closed exc. expected"); + }catch (IllegalStateException e) {} + this.indexer = GDataIndexer.createGdataIndexer(config, dir, true); + CountDownLatch documentLatch = new CountDownLatch(1); + iDoc = new IndexDocumentStub(doc, delTerm, + IndexAction.INSERT,documentLatch); + + CountDownLatch latch = new CountDownLatch(1); + future = new FutureStub(iDoc,latch,true); + this.indexer.addIndexableDocumentTask(future); + this.indexer.destroy(); + latch.countDown(); + documentLatch.await(5000,TimeUnit.MILLISECONDS); + // wait active for the commit + while(this.indexer.writer != null){} + + IndexSearcher s = new IndexSearcher(this.dir); + Hits h = s.search(new TermQuery(delTerm)); + assertEquals(1, h.length()); + s.close(); + + + } + + + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/index/TestindexDocumentBuilderTask.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/index/TestindexDocumentBuilderTask.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/index/TestindexDocumentBuilderTask.java (revision 0) @@ -0,0 +1,138 @@ +package org.apache.lucene.gdata.search.index; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import junit.framework.TestCase; + +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.apache.lucene.gdata.search.config.IndexSchema; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.apache.lucene.gdata.search.config.IndexSchemaField.ContentType; +import org.apache.lucene.gdata.utils.ProvidedServiceStub; + +import com.google.gdata.data.PlainTextConstruct; + +public class TestindexDocumentBuilderTask extends TestCase { + IndexDocumentBuilder fineBuilder; + IndexDocumentBuilder failInStrategyBuilder; + IndexDocumentBuilder builder; + IndexDocumentBuilderTask zeroFields; + static String ID = "someId"; + static String CONTENT_FIELD = "someId"; + static String CONTENT = "foo bar"; + protected void setUp() throws Exception { + ServerBaseEntry entry = new ServerBaseEntry(); + entry.setVersionId("1"); + entry.setId(ID); + entry.setContent(new PlainTextConstruct(CONTENT)); + entry.setServiceConfig(new ProvidedServiceStub()); + IndexSchema schema = new IndexSchema(); + schema.setName("mySchema"); + IndexSchemaField field = new IndexSchemaField(); + field.setName(CONTENT_FIELD); + field.setPath("/entry/content"); + field.setContentType(ContentType.TEXT); + schema.addSchemaField(field); + this.fineBuilder = new IndexDocumentBuilderTask(entry,schema,IndexAction.INSERT,false); + + /* + * two fields, one will fail due to broken xpath. + * One will remain. + */ + schema = new IndexSchema(); + schema.setName("mySchema"); + field = new IndexSchemaField(); + field.setName("someContent"); + //broken xpath + field.setPath("/entry///wrongXPath"); + field.setContentType(ContentType.TEXT); + schema.addSchemaField(field); + field = new IndexSchemaField(); + field.setName(CONTENT_FIELD); + field.setPath("/entry/content"); + field.setContentType(ContentType.TEXT); + schema.addSchemaField(field); + this.failInStrategyBuilder = new IndexDocumentBuilderTask(entry,schema,IndexAction.INSERT,false); + //fail with no fields + schema = new IndexSchema(); + schema.setName("mySchema"); + this.zeroFields = new IndexDocumentBuilderTask(entry,schema,IndexAction.INSERT,false); + + + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + /* + * Test method for 'org.apache.lucene.gdata.search.index.IndexDocumentBuilderTask.IndexDocumentBuilderTask(ServerBaseEntry, IndexSchema, IndexAction, boolean)' + */ + public void testIndexDocumentBuilderTask() { + IndexDocument doc = this.fineBuilder.call(); + assertNotNull(doc.getDeletealbe()); + assertNotNull(doc.getWriteable()); + assertEquals(IndexDocument.FIELD_ENTRY_ID,doc.getDeletealbe().field()); + assertEquals(ID,doc.getDeletealbe().text()); + assertEquals(ID,doc.getWriteable().getField(IndexDocument.FIELD_ENTRY_ID).stringValue()); + assertNotNull(doc.getWriteable().getField(CONTENT_FIELD).stringValue()); + + /* + * the broken xpath fails but the other fields will be indexed + */ + doc = this.failInStrategyBuilder.call(); + assertNotNull(doc.getDeletealbe()); + assertNotNull(doc.getWriteable()); + assertEquals(IndexDocument.FIELD_ENTRY_ID,doc.getDeletealbe().field()); + assertEquals(ID,doc.getDeletealbe().text()); + assertEquals(ID,doc.getWriteable().getField(IndexDocument.FIELD_ENTRY_ID).stringValue()); + assertNotNull(doc.getWriteable().getField(CONTENT_FIELD).stringValue()); + + try{ + this.zeroFields.call(); + fail("zero fields in document"); + }catch (GdataIndexerException e) {} + } + + /* + * Test method for 'org.apache.lucene.gdata.search.index.IndexDocumentBuilderTask.call()' + */ + public void testCall() throws InterruptedException, ExecutionException { + ExecutorService service = Executors.newSingleThreadExecutor(); + Future future = service.submit(this.fineBuilder); + IndexDocument doc = future.get(); + assertNotNull(doc.getDeletealbe()); + assertNotNull(doc.getWriteable()); + assertEquals(IndexDocument.FIELD_ENTRY_ID,doc.getDeletealbe().field()); + assertEquals(ID,doc.getDeletealbe().text()); + assertEquals(ID,doc.getWriteable().getField(IndexDocument.FIELD_ENTRY_ID).stringValue()); + assertNotNull(doc.getWriteable().getField(CONTENT_FIELD).stringValue()); + + /* + * the broken xpath fails but the other fields will be indexed + */ + future = service.submit(this.failInStrategyBuilder); + doc = future.get(); + + assertNotNull(doc.getDeletealbe()); + assertNotNull(doc.getWriteable()); + assertEquals(IndexDocument.FIELD_ENTRY_ID,doc.getDeletealbe().field()); + assertEquals(ID,doc.getDeletealbe().text()); + assertEquals(ID,doc.getWriteable().getField(IndexDocument.FIELD_ENTRY_ID).stringValue()); + assertNotNull(doc.getWriteable().getField(CONTENT_FIELD).stringValue()); + future = service.submit(this.zeroFields); + + try{ + future.get(); + fail("zero fields in document"); + }catch (ExecutionException e) { + assertTrue(e.getCause().getClass() == GdataIndexerException.class); + + } + service.shutdownNow(); + } + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/index/IndexDocumentStub.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/index/IndexDocumentStub.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/index/IndexDocumentStub.java (revision 0) @@ -0,0 +1,112 @@ +/** + * 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.concurrent.CountDownLatch; + +import org.apache.lucene.document.Document; +import org.apache.lucene.index.Term; + +/** + * @author Simon Willnauer + * + */ +public class IndexDocumentStub implements IndexDocument { + Document document; + Term deleteTerm; + IndexAction action; + CountDownLatch latch; + boolean commitAfter; + boolean optimizeAfter; + /** + * + */ + public IndexDocumentStub(Document doc, Term deleteTerm, IndexAction action, CountDownLatch latch) { + this.document = doc; + this.deleteTerm = deleteTerm; + this.action = action; + this.latch = latch; + } + public IndexDocumentStub(Document doc, Term deleteTerm, IndexAction action) { + this(doc,deleteTerm,action,null); + } + + /** + * @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 currentAction){ + return this.action == currentAction; + } + /** + * @see org.apache.lucene.gdata.search.index.IndexDocument#getWriteable() + */ + public Document getWriteable() { + if(latch != null) + latch.countDown(); + return this.document; + } + + /** + * @see org.apache.lucene.gdata.search.index.IndexDocument#getDeletealbe() + */ + public Term getDeletealbe() { + if(latch != null) + latch.countDown(); + return this.deleteTerm; + } + public boolean commitAfter() { + + return this.commitAfter; + } + public boolean optimizeAfter() { + + return this.optimizeAfter; + } + /** + * @param commitAfter The commitAfter to set. + */ + public void setCommitAfter(boolean commitAfter) { + this.commitAfter = commitAfter; + } + /** + * @param optimizeAfter The optimizeAfter to set. + */ + public void setOptimizeAfter(boolean optimizeAfter) { + this.optimizeAfter = optimizeAfter; + } + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/index/TestGdataIndexWriter.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/index/TestGdataIndexWriter.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/index/TestGdataIndexWriter.java (revision 0) @@ -0,0 +1,79 @@ +/** + * 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 junit.framework.TestCase; + +import org.apache.lucene.analysis.PerFieldAnalyzerWrapper; +import org.apache.lucene.analysis.StopAnalyzer; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.gdata.search.config.IndexSchema; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.apache.lucene.store.RAMDirectory; + +/** + * @author Simon Willnauer + * + */ +public class TestGdataIndexWriter extends TestCase { + IndexSchema schemaNoPerFielAnalyzer; + IndexSchema schemaPerFielAnalyzer; + long VALUE_GT_DEFAULT_LONG = 15000; + int VALUE_GT_DEFAULT_INT = 10000; + + protected void setUp() throws Exception { + this.schemaNoPerFielAnalyzer = new IndexSchema(); + this.schemaPerFielAnalyzer = new IndexSchema(); + IndexSchemaField field = new IndexSchemaField(); + field.setName("someField"); + field.setAnalyzerClass(StopAnalyzer.class); + this.schemaPerFielAnalyzer.addSchemaField(field); + this.schemaPerFielAnalyzer.setCommitLockTimeout(VALUE_GT_DEFAULT_LONG); + this.schemaPerFielAnalyzer.setMaxBufferedDocs(VALUE_GT_DEFAULT_INT); + this.schemaPerFielAnalyzer.setMaxFieldLength(VALUE_GT_DEFAULT_INT); + this.schemaPerFielAnalyzer.setMaxMergeDocs(VALUE_GT_DEFAULT_INT); + this.schemaPerFielAnalyzer.setMergeFactor(VALUE_GT_DEFAULT_INT); + this.schemaPerFielAnalyzer.setWriteLockTimeout(VALUE_GT_DEFAULT_LONG); + this.schemaPerFielAnalyzer.setUseCompoundFile(true); + } + + + /** + * Test method for 'org.apache.lucene.gdata.search.index.GDataIndexWriter.GDataIndexWriter(Directory, boolean, IndexSchema)' + * @throws IOException + */ + public void testGDataIndexWriter() throws IOException { + try{ + new GDataIndexWriter(new RAMDirectory(),true,null); + fail("no index schema"); + }catch (IllegalArgumentException e) {} + GDataIndexWriter writer = new GDataIndexWriter(new RAMDirectory(),true,this.schemaNoPerFielAnalyzer); + assertTrue(writer.getAnalyzer().getClass() == StandardAnalyzer.class); + + writer = new GDataIndexWriter(new RAMDirectory(),true,this.schemaPerFielAnalyzer); + assertTrue(writer.getAnalyzer().getClass() == PerFieldAnalyzerWrapper.class); + assertEquals(VALUE_GT_DEFAULT_LONG,writer.getCommitLockTimeout()); + assertEquals(VALUE_GT_DEFAULT_LONG,writer.getWriteLockTimeout()); + assertEquals(VALUE_GT_DEFAULT_INT,writer.getMaxBufferedDocs()); + assertEquals(VALUE_GT_DEFAULT_INT,writer.getMaxMergeDocs()); + assertEquals(VALUE_GT_DEFAULT_INT,writer.getMaxFieldLength()); + assertEquals(VALUE_GT_DEFAULT_INT,writer.getMergeFactor()); + assertTrue(writer.getUseCompoundFile()); + } + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/index/FutureStub.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/index/FutureStub.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/index/FutureStub.java (revision 0) @@ -0,0 +1,103 @@ +/** + * 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.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * @author Simon Willnauer + * + */ +public class FutureStub implements Future{ + T object; + CountDownLatch latch; + boolean wait; + + /** + * + */ + public FutureStub(T returnObject, CountDownLatch latch) { + this(returnObject,latch,false); + } + /** + * + */ + public FutureStub(T returnObject, CountDownLatch latch, boolean wait) { + super(); + this.object = returnObject; + this.latch =latch; + this.wait =wait; + } + public FutureStub(T returnObject) { + this(returnObject,null); + } + + /** + * @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() + */ + public T get() throws InterruptedException, ExecutionException { + doLatch(); + return this.object; + } + + /** + * @see java.util.concurrent.Future#get(long, java.util.concurrent.TimeUnit) + */ + public T get(long arg0, TimeUnit arg1) throws InterruptedException, + ExecutionException, TimeoutException { + doLatch(); + return this.object; + } + + private void doLatch() throws InterruptedException{ + if(latch != null){ + if(!wait) + this.latch.countDown(); + else + this.latch.await(5000,TimeUnit.MILLISECONDS); + } + } + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/index/TestIndexController.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/index/TestIndexController.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/index/TestIndexController.java (revision 0) @@ -0,0 +1,179 @@ +/** + * 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 junit.framework.TestCase; + +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.search.config.IndexSchema; +import org.apache.lucene.gdata.search.index.IndexController.ServiceIndex; +import org.apache.lucene.gdata.server.registry.GDataServerRegistry; +import org.apache.lucene.gdata.utils.ProvidedServiceStub; +import org.apache.lucene.index.IndexWriter; + +public class TestIndexController extends TestCase { + IndexController controller; + IndexSchema schema; + File indexLocation; + protected void setUp() throws Exception { + this.controller = new IndexController(); + GDataServerRegistry reg = GDataServerRegistry.getRegistry(); + + this.indexLocation = new File(System.getProperty("java.io.tmpdir")); + ProvidedServiceStub stub = new ProvidedServiceStub(); + this.schema = new IndexSchema(); + //must be set + this.schema.setDefaultSearchField("content"); + this.schema.setIndexLocation("/tmp/"); + this.schema.setName(ProvidedServiceStub.SERVICE_NAME); + this.schema.setIndexLocation(this.indexLocation.getAbsolutePath()); + stub.setIndexSchema(this.schema); + + reg.registerService(stub); + } + + protected void tearDown() throws Exception { + super.tearDown(); + GDataServerRegistry.getRegistry().destroy(); + this.controller.destroy(); + /* + * this file will be created by the controller + */ + File toDel = new File(this.indexLocation,ProvidedServiceStub.SERVICE_NAME); + delAllFiles(toDel); + } + /* + * del all created files + */ + private void delAllFiles(File dir){ + if(dir == null || !dir.exists()) + return; + File[] files = dir.listFiles(); + for (int i = 0; i < files.length; i++) { + while(!files[i].canWrite()){}; + files[i].delete(); + } + dir.delete(); + } + + /* + * Test method for 'org.apache.lucene.gdata.search.index.IndexController.initialize()' + */ + public void testInitialize() { + this.controller.initialize(); + assertTrue(this.controller.indexerMap.containsKey(ProvidedServiceStub.SERVICE_NAME)); + ServiceIndex bean = this.controller.indexerMap.get(ProvidedServiceStub.SERVICE_NAME); + assertNotNull(bean); + assertNotNull(bean.getIndexer()); + assertSame(this.schema,bean.getSchema()); + assertTrue(GDataServerRegistry.getRegistry().getEntryEventMediator().isListenerRegistered(this.controller)); + + } + /* + * Test method for 'org.apache.lucene.gdata.search.index.IndexController.initialize()' + */ + public void testInitializeValueMissing() { + this.schema.setIndexLocation(null); + try{ + + this.controller.initialize(); + fail("missing index location"); + }catch (RuntimeException e) {} + } + + /* + * Test method for 'org.apache.lucene.gdata.search.index.IndexController.addIndexSchema(IndexSchema)' + */ + public void testAddIndexSchema() { + this.controller.initialize(); + assertEquals(1,this.controller.indexerMap.size()); + try{ + this.controller.addIndexSchema(this.schema); + fail("schema already added"); + }catch (IllegalStateException e) { + + } + this.schema.setName(null); + try{ + this.controller.addIndexSchema(this.schema); + fail("schema name is null"); + }catch (IllegalStateException e) { + + } + + this.schema.setName("someOthername"); + this.controller.addIndexSchema(this.schema); + assertEquals(2,this.controller.indexerMap.size()); + + + } + + /* + * Test method for 'org.apache.lucene.gdata.search.index.IndexController.createIndexer(IndexSchema)' + */ + public void testCreateIndexDirectory() throws IOException { + File f = new File(System.getProperty("java.io.tmpdir"),"gdataindexdir"+System.currentTimeMillis()); + f.mkdir(); + f.deleteOnExit(); + IndexWriter w = new IndexWriter(f,new StandardAnalyzer(),true); + Document d = new Document(); + d.add(new Field("test","test",Field.Store.NO,Field.Index.TOKENIZED)); + w.addDocument(d); + w.close(); + assertFalse(this.controller.createIndexDirectory(f)); + //throw away files in the directory + delAllFiles(f); + File f1 = new File(System.getProperty("java.io.tmpdir"),"newIndexDir"+System.currentTimeMillis()); + f1.mkdir(); + f1.deleteOnExit(); + assertTrue(this.controller.createIndexDirectory(f1)); + } + + /* + * Test method for 'org.apache.lucene.gdata.search.index.IndexController.createIndexLocation(String, String)' + */ + public void testCreateIndexLocation() throws IOException { + File f = new File(System.getProperty("java.io.tmpdir"),"gdatadir"+System.currentTimeMillis()); + f.mkdir(); + f.deleteOnExit(); + + assertEquals(f.getAbsolutePath(),this.controller.createIndexLocation(f.getParent(),f.getName()).getAbsolutePath());; + File pFile = new File(System.getProperty("java.io.tmpdir"),"gdatafile"+System.currentTimeMillis()); + assertTrue(pFile.createNewFile()); + pFile.deleteOnExit(); + try{ + this.controller.createIndexLocation(pFile.getParent(),pFile.getName()); + fail("file is not a directory"); + }catch (IllegalArgumentException e) { + // TODO: handle exception + } + + } + + /* + * Test method for 'org.apache.lucene.gdata.search.index.IndexController.getServiceSearcher(ProvidedService)' + */ + public void testGetServiceSearcher() { + //TODO add when search is available + } + + +} Index: gdata-server/src/test/org/apache/lucene/gdata/search/index/IndexEventListenerStub.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/search/index/IndexEventListenerStub.java (revision 0) +++ gdata-server/src/test/org/apache/lucene/gdata/search/index/IndexEventListenerStub.java (revision 0) @@ -0,0 +1,46 @@ +/** + * 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.concurrent.atomic.AtomicInteger; + +/** + * @author Simon Willnauer + * + */ +public class IndexEventListenerStub implements IndexEventListener { + AtomicInteger count; + /** + * + */ + public IndexEventListenerStub() { + super(); + this.count = new AtomicInteger(0); + } + + /** + * @see org.apache.lucene.gdata.search.index.IndexEventListener#commitCallBack(java.lang.String) + */ + public void commitCallBack(String service) { + this.count.incrementAndGet(); + } + + public int getCalledCount(){ + return this.count.get(); + } + +} Index: gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataRequest.java =================================================================== --- gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataRequest.java (revision 426779) +++ gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataRequest.java (working copy) @@ -64,6 +64,7 @@ protected void tearDown() throws Exception { super.tearDown(); this.control.reset(); + GDataServerRegistry.getRegistry().destroy(); } public void testConstructor() { Index: gdata-server/src/java/org/apache/lucene/gdata/utils/ReflectionUtils.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/utils/ReflectionUtils.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/utils/ReflectionUtils.java (revision 0) @@ -0,0 +1,179 @@ +/** + * 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.utils; + +import java.lang.reflect.Constructor; + +/** + * A collection of static helper methods solve common reflection problems + * + * @author Simon Willnauer + * + */ +public class ReflectionUtils { + + /** + * Check if the given type implements a given super type + * @param typeToCheck - type supposed to implement an interface + * @param superType - the interface to be implemented by the type to check + * @return true if and only if the super type is above in the type hierarchy of the given type, otherwise false + */ + public static boolean implementsType(Class typeToCheck, Class superType) { + if(!superType.isInterface()) + return false; + if (typeToCheck == null) + return false; + if (typeToCheck.equals(Object.class)) + return false; + if (typeToCheck.equals(superType)) + return true; + Class[] interfaces = typeToCheck.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + if (implementsType(interfaces[i], superType)) + return true; + } + return implementsType(typeToCheck.getSuperclass(),superType); + + } + /** + * Check if the given type extends a given super type + * @param typeToCheck - type supposed to extend an specific type + * @param superType - the type to be extended by the type to check + * @return true if and only if the super type is above in the type hierarchy of the given type, otherwise false + */ + public static boolean extendsType(Class typeToCheck, Class superType) { + if (typeToCheck == null) + return false; + if (typeToCheck.equals(Object.class)) + return false; + if (typeToCheck.equals(superType)) + return true; + + return extendsType(typeToCheck.getSuperclass(),superType); + } + /** + * This method combines the extendsType and implementsType and checks interfaces and classes + * @param typeToCheck - type supposed to extend / implement an specific type + * @param superType - the type to be extended / implemented by the type to check + * @return true if and only if the super type is above in the type hierarchy of the given type, otherwise false + */ + public static boolean isTypeOf(Class typeToCheck, Class superType){ + return extendsType(typeToCheck,superType)||implementsType(typeToCheck,superType); + } + + + +/** + * @param the type of the class to instantiate + * @param clazz - class object of the type + * @return a new instance of T + + */ +@SuppressWarnings("unchecked") +public static T getDefaultInstance(Class clazz) { + if(clazz == null) + throw new ReflectionException("class must not be null"); + if(clazz.isPrimitive()) + clazz = (Class)getPrimitiveWrapper(clazz); + try{ + Constructor constructor = clazz.getConstructor(new Class[]{}); + if(constructor == null) + throw new ReflectionException("no default constructor"); + return (T) constructor.newInstance(new Object[]{}); + }catch (Exception e) { + throw new ReflectionException("can not instantiate type of class "+clazz.getName(),e); + } +} + + +/** + * This method calls {@link Class#newInstance()} to get a new instance. Use with care! + * @param clazz - the class to instantiate + * @return true if an instance could be created, otherwise false; + */ +public static boolean canCreateInstance(Class clazz){ + if(clazz == null) + return false; + try{ + Object o = clazz.newInstance(); + return o != null; + }catch (Throwable e) { + return false; + } +} +/** + * Returns the wrapper type for the given primitive type. Wrappers can be + * easily instantiated via reflection and will be boxed by the VM + * @param primitive - the primitive type + * @return - the corresponding wrapper type + */ +public static final Class getPrimitiveWrapper(Class primitive) { + if(primitive == null ) + throw new ReflectionException("primitive must not be null"); + if(!primitive.isPrimitive()) + throw new ReflectionException("given class is not a primitive"); + + if (primitive == Integer.TYPE) + return Integer.class; + if (primitive == Float.TYPE) + return Float.class; + if (primitive == Long.TYPE) + return Long.class; + if (primitive == Short.TYPE) + return Short.class; + if (primitive == Byte.TYPE) + return Byte.class; + if (primitive == Double.TYPE) + return Double.class; + if (primitive == Boolean.TYPE) + return Boolean.class; + + return primitive; +} + +/** + * Exception wrapper for all thrown exception in the ReflectionUtils methods + * @author Simon Willnauer + * + */ +public static class ReflectionException extends RuntimeException{ + + /** + * + */ + private static final long serialVersionUID = -4855060602565614280L; + + /** + * @param message - the exception message + * @param cause - the exception root cause + */ + public ReflectionException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + /** + * @param message - the exception message + */ + public ReflectionException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + +} + +} Index: gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/UpdateFeedHandler.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/UpdateFeedHandler.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/UpdateFeedHandler.java (working copy) @@ -26,6 +26,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.lucene.gdata.data.GDataAccount; import org.apache.lucene.gdata.data.ServerBaseFeed; +import org.apache.lucene.gdata.server.GDataResponse; import org.apache.lucene.gdata.server.ServiceException; import org.apache.lucene.gdata.server.ServiceFactory; import org.apache.lucene.gdata.server.administration.AdminService; @@ -59,7 +60,7 @@ ServiceFactory serviceFactory = registry.lookup( ServiceFactory.class, ComponentType.SERVICEFACTORY); if (serviceFactory == null) { - setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + setError(GDataResponse.SERVER_ERROR, "required component is not available"); throw new FeedHandlerException( "Can't update feed - ServiceFactory is null"); @@ -67,7 +68,7 @@ service = serviceFactory.getAdminService(); service.updateFeed(feed, account); } catch (ServiceException e) { - setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + setError(e.getErrorCode(), "can not update feed"); LOG.error("Can not update feed -- " + e.getMessage(), e); } catch (Exception e) { Index: gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultDeleteHandler.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultDeleteHandler.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultDeleteHandler.java (working copy) @@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.lucene.gdata.data.GDataAccount.AccountRole; import org.apache.lucene.gdata.server.GDataRequestException; +import org.apache.lucene.gdata.server.GDataResponse; import org.apache.lucene.gdata.server.ServiceException; import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; @@ -37,7 +38,7 @@ *

*
    *
  1. if the entry could be deleted - HTTP status code 200 OK
  2. - *
  3. if an error occures - HTTP status code 500 INTERNAL SERVER ERROR
  4. + *
  5. if an error occurs - HTTP status code 500 INTERNAL SERVER ERROR
  6. *
  7. if the resource could not found - HTTP status code 404 NOT FOUND
  8. *
* @@ -63,7 +64,7 @@ return; } if(!authenticateAccount(request,AccountRole.ENTRYAMINISTRATOR)){ - setError(HttpServletResponse.SC_UNAUTHORIZED); + setError(GDataResponse.UNAUTHORIZED); sendError(); return; } @@ -74,6 +75,7 @@ } catch (ServiceException e) { LOG.error("Could not process DeleteFeed request - " + e.getMessage(), e); + setError(e.getErrorCode()); sendError(); }finally{ closeService(); Index: gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultInsertHandler.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultInsertHandler.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultInsertHandler.java (working copy) @@ -26,6 +26,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.lucene.gdata.data.GDataAccount.AccountRole; import org.apache.lucene.gdata.server.GDataRequestException; +import org.apache.lucene.gdata.server.GDataResponse; import org.apache.lucene.gdata.server.ServiceException; import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; @@ -40,7 +41,7 @@ *

*
    *
  1. if the entry was added - HTTP status code 200 OK
  2. - *
  3. if an error occures - HTTP status code 500 INTERNAL SERVER ERROR
  4. + *
  5. if an error occurs - HTTP status code 500 INTERNAL SERVER ERROR
  6. *
  7. if the resource could not found - HTTP status code 404 NOT FOUND
  8. *
*

The added entry will be send back to the client if the insert request was successful.

@@ -64,7 +65,7 @@ return; } if(!authenticateAccount(this.feedRequest,AccountRole.ENTRYAMINISTRATOR)){ - setError(HttpServletResponse.SC_UNAUTHORIZED); + setError(GDataResponse.UNAUTHORIZED); sendError(); return; } @@ -72,12 +73,13 @@ try{ BaseEntry entry = this.service.createEntry(this.feedRequest,this.feedResponse); setFeedResponseFormat(); - setFeedResponseStatus(HttpServletResponse.SC_CREATED); + setFeedResponseStatus(GDataResponse.CREATED); this.feedResponse.sendResponse(entry, this.feedRequest.getConfigurator().getExtensionProfile()); }catch (ServiceException e) { LOG.error("Could not process GetFeed request - "+e.getMessage(),e); - this.feedResponse.sendError(); + setError(e.getErrorCode()); + sendError(); }finally{ closeService(); } Index: gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractGdataRequestHandler.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractGdataRequestHandler.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractGdataRequestHandler.java (working copy) @@ -65,7 +65,7 @@ try { this.feedRequest.initializeRequest(); } catch (GDataRequestException e) { - this.feedResponse.setError(HttpServletResponse.SC_NOT_FOUND); + setError(GDataResponse.NOT_FOUND); LOG.warn("Couldn't initialize FeedRequest - " + e.getMessage(), e); throw e; } Index: gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AuthenticationHandler.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AuthenticationHandler.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AuthenticationHandler.java (working copy) @@ -27,6 +27,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.lucene.gdata.data.GDataAccount; +import org.apache.lucene.gdata.server.GDataResponse; import org.apache.lucene.gdata.server.ServiceException; import org.apache.lucene.gdata.server.ServiceFactory; import org.apache.lucene.gdata.server.administration.AdminService; @@ -91,10 +92,10 @@ } } catch (AuthenticationException e){ LOG.error("BadAuthentication -- "+e.getMessage(),e); - sendError(response, HttpServletResponse.SC_FORBIDDEN,"BadAuthentication"); + sendError(response, GDataResponse.FORBIDDEN,"BadAuthentication"); }catch (Exception e) { LOG.error("Unexpected Exception -- SERVERERROR -- "+e.getMessage(),e); - sendError(response,HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Service not available"); + sendError(response,GDataResponse.SERVER_ERROR, "Service not available"); } } Index: gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractAccountHandler.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractAccountHandler.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractAccountHandler.java (working copy) @@ -26,6 +26,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.lucene.gdata.data.GDataAccount; import org.apache.lucene.gdata.data.GDataAccount.AccountRole; +import org.apache.lucene.gdata.server.GDataResponse; import org.apache.lucene.gdata.server.ServiceException; import org.apache.lucene.gdata.server.ServiceFactory; import org.apache.lucene.gdata.server.administration.AccountBuilder; @@ -72,10 +73,10 @@ GDataAccount account = getAccountFromRequest(request); if (!account.requiredValuesSet()) { - setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "requiered server component not available"); + setError(GDataResponse.SERVER_ERROR, + "Required server component not available"); throw new AccountHandlerException( - "requiered values are not set -- account can not be saved -- " + "Required values are not set -- account can not be saved -- " + account); } this.service = factory.getAdminService(); @@ -83,13 +84,14 @@ } catch (ServiceException e) { LOG.error("Can't process account action -- " + e.getMessage(), e); - setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ""); - } catch (Exception e) { + setError(e.getErrorCode(), ""); + } + catch (AccountHandlerException e) { LOG.error("Can't process account action -- " + e.getMessage(), e); } }else{ - setError(HttpServletResponse.SC_UNAUTHORIZED,"Authorization failed"); + setError(GDataResponse.UNAUTHORIZED,"Authorization failed"); } sendResponse(response); }finally{ Index: gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultGetHandler.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultGetHandler.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultGetHandler.java (working copy) @@ -37,10 +37,10 @@ /** * Default Handler implementation. This handler processes the incoming * {@link org.apache.lucene.gdata.server.GDataRequest} and retrieves the - * requested feed from the underlaying storage. + * requested feed from the underlying storage. *

- * This hander also processes search queries and retrives the search hits from - * the underlaying search component. The user query will be accessed via the + * This hander also processes search queries and retrieves the search hits from + * the underlying search component. The user query will be accessed via the * {@link org.apache.lucene.gdata.server.GDataRequest} instance passed to the * {@link Service} class. *

@@ -101,6 +101,7 @@ } catch (ServiceException e) { LOG.error("Could not process GetFeed request - " + e.getMessage(), e); + setError(e.getErrorCode()); sendError(); }finally{ closeService(); @@ -110,7 +111,7 @@ /** * * returns true if the resource has been modified since the specified - * reqeust header value + * request header value */ private boolean checkIsModified(String lastModified) throws ServiceException { @@ -126,7 +127,7 @@ entityDate = this.service.getEntryLastModified(this.feedRequest .getEntryId(),this.feedRequest.getFeedId()); if(LOG.isInfoEnabled()) - LOG.info("comparing date clientDate: "+clientDate+"; lastmodified: "+entityDate); + LOG.info("comparing date clientDate: "+clientDate+"; last modified: "+entityDate); return (entityDate.getTime()-clientDate.getTime() > 1000); } catch (java.text.ParseException e) { LOG.info("Couldn't parse Last-Modified header -- "+lastModified,e); Index: gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DeleteFeedHandler.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DeleteFeedHandler.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DeleteFeedHandler.java (working copy) @@ -25,6 +25,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.lucene.gdata.data.ServerBaseFeed; +import org.apache.lucene.gdata.server.GDataResponse; +import org.apache.lucene.gdata.server.ServiceException; import org.apache.lucene.gdata.server.ServiceFactory; import org.apache.lucene.gdata.server.administration.AdminService; import org.apache.lucene.gdata.server.registry.ComponentType; @@ -52,16 +54,16 @@ GDataServerRegistry registry = GDataServerRegistry.getRegistry(); ServiceFactory serviceFactory = registry.lookup(ServiceFactory.class,ComponentType.SERVICEFACTORY); if(serviceFactory == null){ - setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,"required component is not available"); + setError(GDataResponse.SERVER_ERROR,"required component is not available"); throw new FeedHandlerException("Can't save feed - ServiceFactory is null"); } service = serviceFactory.getAdminService(); service.deleteFeed(feed); } catch (FeedHandlerException e) { LOG.error("Can not delete feed -- "+e.getMessage(),e); - }catch (Exception e) { + }catch (ServiceException e) { LOG.error("Can not delete feed -- "+e.getMessage(),e); - setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,"can not create feed"); + setError(e.getErrorCode(),"can not create feed"); }finally{ if(service != null) service.close(); @@ -76,7 +78,7 @@ private ServerBaseFeed createDeleteFeed(final HttpServletRequest request) throws FeedHandlerException { String feedId = request.getParameter("feedid"); if(feedId == null){ - setError(HttpServletResponse.SC_BAD_REQUEST,"No feed id specified"); + setError(GDataResponse.BAD_REQUEST,"No feed id specified"); throw new FeedHandlerException("no feed Id specified"); } ServerBaseFeed retVal = new ServerBaseFeed(); Index: gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultUpdateHandler.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultUpdateHandler.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultUpdateHandler.java (working copy) @@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.lucene.gdata.data.GDataAccount.AccountRole; import org.apache.lucene.gdata.server.GDataRequestException; +import org.apache.lucene.gdata.server.GDataResponse; import org.apache.lucene.gdata.server.ServiceException; import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; @@ -39,7 +40,7 @@ *

*
    *
  1. if the entry was successfully updated - HTTP status code 200 OK
  2. - *
  3. if an error occures - HTTP status code 500 INTERNAL SERVER ERROR
  4. + *
  5. if an error occurs - HTTP status code 500 INTERNAL SERVER ERROR
  6. *
  7. if the resource could not found - HTTP status code 404 NOT FOUND
  8. *
* @@ -61,7 +62,7 @@ try { initializeRequestHandler(request, response,GDataRequestType.UPDATE); } catch (GDataRequestException e) { - setError(HttpServletResponse.SC_UNAUTHORIZED); + setError(GDataResponse.UNAUTHORIZED); sendError(); return; } @@ -74,13 +75,13 @@ BaseEntry entry = this.service.updateEntry(this.feedRequest, this.feedResponse); setFeedResponseFormat(); - setFeedResponseStatus(HttpServletResponse.SC_OK); this.feedResponse.sendResponse(entry, this.feedRequest.getConfigurator().getExtensionProfile()); } catch (ServiceException e) { LOG.error("Could not process UpdateFeed request - " + e.getMessage(), e); + setError(e.getErrorCode()); sendError(); }finally{ closeService(); Index: gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractFeedHandler.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractFeedHandler.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractFeedHandler.java (working copy) @@ -28,6 +28,7 @@ import org.apache.lucene.gdata.data.ServerBaseFeed; import org.apache.lucene.gdata.data.GDataAccount.AccountRole; import org.apache.lucene.gdata.server.GDataEntityBuilder; +import org.apache.lucene.gdata.server.GDataResponse; import org.apache.lucene.gdata.server.ServiceException; import org.apache.lucene.gdata.server.ServiceFactory; import org.apache.lucene.gdata.server.administration.AdminService; @@ -62,7 +63,7 @@ HttpServletResponse response) throws ServletException, IOException { this.authenticated = authenticateAccount(request,AccountRole.FEEDAMINISTRATOR); if(!this.authenticated) - setError(HttpServletResponse.SC_UNAUTHORIZED,"Authorization failed"); + setError(GDataResponse.UNAUTHORIZED,"Authorization failed"); } @@ -70,12 +71,12 @@ GDataServerRegistry registry = GDataServerRegistry.getRegistry(); String providedService = request.getParameter(PARAMETER_SERVICE); if(!registry.isServiceRegistered(providedService)){ - setError(HttpServletResponse.SC_NOT_FOUND,"no such service"); + setError(GDataResponse.NOT_FOUND,"no such service"); throw new FeedHandlerException("ProvicdedService is not registered -- Name: "+providedService); } ProvidedService provServiceInstance = registry.getProvidedService(providedService); if(providedService == null){ - setError(HttpServletResponse.SC_BAD_REQUEST,"no such service"); + setError(GDataResponse.BAD_REQUEST,"no such service"); throw new FeedHandlerException("no such service registered -- "+providedService); } try{ @@ -85,12 +86,12 @@ }catch (IOException e) { if(LOG.isInfoEnabled()) LOG.info("Can not read from input stream - ",e); - setError(HttpServletResponse.SC_BAD_REQUEST,"Can not read from input stream"); + setError(GDataResponse.BAD_REQUEST,"Can not read from input stream"); throw e; }catch (ParseException e) { if(LOG.isInfoEnabled()) LOG.info("feed can not be parsed - ",e); - setError(HttpServletResponse.SC_BAD_REQUEST,"incoming feed can not be parsed"); + setError(GDataResponse.BAD_REQUEST,"incoming feed can not be parsed"); throw e; } @@ -102,7 +103,7 @@ ServiceFactory serviceFactory = registry.lookup(ServiceFactory.class,ComponentType.SERVICEFACTORY); if(serviceFactory == null){ - setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Required server component not available"); + setError(GDataResponse.SERVER_ERROR, "Required server component not available"); throw new FeedHandlerException("Required server component not available -- "+ServiceFactory.class.getName()); } AdminService service = serviceFactory.getAdminService(); Index: gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/InsertFeedHandler.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/InsertFeedHandler.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/InsertFeedHandler.java (working copy) @@ -26,12 +26,15 @@ import org.apache.commons.logging.LogFactory; import org.apache.lucene.gdata.data.GDataAccount; import org.apache.lucene.gdata.data.ServerBaseFeed; +import org.apache.lucene.gdata.server.GDataResponse; import org.apache.lucene.gdata.server.ServiceException; import org.apache.lucene.gdata.server.ServiceFactory; import org.apache.lucene.gdata.server.administration.AdminService; import org.apache.lucene.gdata.server.registry.ComponentType; import org.apache.lucene.gdata.server.registry.GDataServerRegistry; +import com.google.gdata.util.ParseException; + /** * @author Simon Willnauer * @@ -66,12 +69,14 @@ service = serviceFactory.getAdminService(); service.createFeed(feed, account); } catch (ServiceException e) { - setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + setError(GDataResponse.SERVER_ERROR, "can not create feed"); LOG.error("Can not create feed -- " + e.getMessage(), e); - } catch (Exception e) { + } catch (FeedHandlerException e) { LOG.error("Can not create feed -- " + e.getMessage(), e); + }catch (ParseException e) { + LOG.error("Can not create feed -- " + e.getMessage(), e); }finally{ if(service != null) service.close(); Index: gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java (working copy) @@ -1,3 +1,18 @@ +/** + * 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.storage.lucenestorage; import java.io.File; @@ -212,7 +227,7 @@ *

* if the reference counter has no remaining references the resource e.g. * the StorageQuery will be closed. This ensures that a - * StorageQuery instance will be arround as long as needed and + * StorageQuery instance will be around as long as needed and * the resources will be released. The reference counter should be * decremented by clients after finished using the query instance. *

@@ -232,7 +247,7 @@ this.storageQuery = getNewStorageQueryHolder(new StorageQuery( this.currentBuffer, this.searcher)); if (LOG.isInfoEnabled()) - LOG.info("Relese new StorageQuery"); + LOG.info("Release new StorageQuery"); } this.storageQuery.increamentReference(); return this.storageQuery; @@ -271,7 +286,7 @@ * changes available for searching. * * @throws IOException - - * if an IO exception occures + * if an IO exception occurs */ protected void registerNewStorageQuery() throws IOException { if(this.isClosed.get()) @@ -324,7 +339,7 @@ * * @return - a new modifier * @throws IOException - - * if an IO exception occures + * if an IO exception occurs */ protected IndexModifier createIndexModifier() throws IOException { if(this.isClosed.get()) @@ -380,7 +395,7 @@ * Forces the StorageModifier to write all buffered changes. * * @throws IOException - - * if an IO exception occures + * if an IO exception occurs * */ public void forceWrite() throws IOException { @@ -492,7 +507,7 @@ /** * An integer value after how many changes to the StorageModifier the - * buffered changes will be persisted / wirtten to the index + * buffered changes will be persisted / written to the index * * @return - the persist factor */ Index: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/XHtmlStrategy.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/analysis/XHtmlStrategy.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/analysis/XHtmlStrategy.java (revision 0) @@ -0,0 +1,36 @@ +/** + * 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.analysis; + +import org.apache.lucene.gdata.search.config.IndexSchemaField; + + +/** + * @author Simon Willnauer + * @see org.apache.lucene.gdata.search.analysis.TestHTMLStrategy + */ +public class XHtmlStrategy extends HTMLStrategy { + + + + /** + * @param fieldConfig + */ + public XHtmlStrategy(IndexSchemaField fieldConfig) { + super(fieldConfig); + } + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/XHtmlStrategy.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/GdataCategoryStrategy.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/analysis/GdataCategoryStrategy.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/analysis/GdataCategoryStrategy.java (revision 0) @@ -0,0 +1,122 @@ +/** + * 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.analysis; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.xpath.XPathExpressionException; + +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.apache.lucene.gdata.search.index.GdataIndexerException; +import org.w3c.dom.Node; + +/** + * This strategy retrieves the category term and and the scheme from a category + * element. The content is represented by the term which can be configured via + * the configuration file. + *

+ * The category element has at least one attribute with the name "scheme" which + * is not mandatory. The term can be the default attribute "term" or the text + * content of the element, this is configured via the path of the field. + *

+ *

+ * <category scheme="http://www.example.com/type" term="blog.post"/> + *

+ * TODO extend javadoc for search info + * @author Simon Willnauer + * + */ +public class GdataCategoryStrategy extends ContentStrategy { + protected String categoryScheme; + + protected String categorySchemeField; + + /** + * Schema field suffix + */ + public static final String CATEGORY_SCHEMA_FIELD_SUFFIX = "-urn"; + + protected GdataCategoryStrategy(IndexSchemaField fieldConfiguration) { + super(fieldConfiguration); + this.categorySchemeField = new StringBuilder(this.fieldName).append( + CATEGORY_SCHEMA_FIELD_SUFFIX).toString(); + + } + + /** + * @throws NotIndexableException + * @see org.apache.lucene.gdata.search.analysis.ContentStrategy#processIndexable(org.apache.lucene.gdata.search.analysis.Indexable) + */ + @Override + public void processIndexable( + Indexable indexable) + throws NotIndexableException { + String contentPath = this.config.getPath(); + Node node = null; + try { + node = indexable.applyPath(contentPath); + } catch (XPathExpressionException e) { + + throw new NotIndexableException("Can not apply path"); + } + if (node == null) + throw new NotIndexableException( + "Could not retrieve content for schema field: " + + this.config); + this.content = node.getTextContent(); + Node schemdeNode = node.getAttributes().getNamedItem("scheme"); + + if (schemdeNode != null) + this.categoryScheme = schemdeNode.getTextContent(); + + } + + /** + * @see org.apache.lucene.gdata.search.analysis.ContentStrategy#createLuceneField() + */ + @Override + public Field[] createLuceneField() { + List retValue = new ArrayList(2); + if(this.fieldName == null) + throw new GdataIndexerException( + "Required field 'name' is null -- " +this.config); + if(this.content == null) + throw new GdataIndexerException( + "Required field 'content' is null -- " +this.config); + + Field categoryTerm = new Field(this.fieldName, this.content, + Field.Store.YES, Field.Index.UN_TOKENIZED); + float boost = this.config.getBoost(); + if (boost != 1.0f) + categoryTerm.setBoost(boost); + retValue.add(categoryTerm); + /* + * omit category schema if not set + */ + if (this.categoryScheme != null && this.categoryScheme.length() > 0) { + Field categoryURN = new Field(this.categorySchemeField, + this.categoryScheme, Field.Store.YES, + Field.Index.UN_TOKENIZED); + retValue.add(categoryURN); + } + return retValue.toArray(new Field[0]); + + } + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/GdataCategoryStrategy.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/GdataDateStrategy.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/analysis/GdataDateStrategy.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/analysis/GdataDateStrategy.java (revision 0) @@ -0,0 +1,96 @@ +/** + * 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.analysis; + +import javax.xml.xpath.XPathExpressionException; + +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.apache.lucene.gdata.search.index.GdataIndexerException; +import org.w3c.dom.Node; + +import com.google.gdata.data.DateTime; + +/** + * This content strategy retrieves a so called GData Date from a RFC 3339 + * timestamp format. The format will be parsed and indexed as a timestamp value. + * + * @author Simon Willnauer + * + */ +public class GdataDateStrategy extends ContentStrategy { + + protected GdataDateStrategy(IndexSchemaField fieldConfiguration) { + super(fieldConfiguration); + + } + + /** + * @throws NotIndexableException + * @see org.apache.lucene.gdata.search.analysis.ContentStrategy#processIndexable(org.apache.lucene.gdata.search.analysis.Indexable) + */ + @Override + public void processIndexable( + Indexable indexable) + throws NotIndexableException { + String path = this.config.getPath(); + Node node; + try { + node = indexable.applyPath(path); + } catch (XPathExpressionException e1) { + throw new NotIndexableException("Can not apply path -- " + path + + " FieldConfig: " + this.config); + } + if (node == null) + throw new NotIndexableException( + "Could not retrieve content for schema field: " + + this.config); + String textContent = node.getTextContent(); + try { + this.content = getTimeStamp(textContent); + } catch (NumberFormatException e) { + throw new NotIndexableException("Can not parse GData date -- " + + textContent); + } + + } + + /** + * @see org.apache.lucene.gdata.search.analysis.ContentStrategy#createLuceneField() + */ + @Override + public Field[] createLuceneField() { + if(this.fieldName == null) + throw new GdataIndexerException( + "Required field 'name' is null -- " +this.config); + if(this.content == null) + throw new GdataIndexerException( + "Required field 'content' is null -- " +this.config); + Field retValue = new Field(this.fieldName, this.content, + Field.Store.YES, Field.Index.UN_TOKENIZED); + float boost = this.config.getBoost(); + if (boost != 1.0f) + retValue.setBoost(boost); + return new Field[] { retValue }; + + } + + private static String getTimeStamp(String dateString) { + return Long.toString(DateTime.parseDateTimeChoice(dateString).getValue()); + } + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/GdataDateStrategy.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/MixedContentStrategy.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/analysis/MixedContentStrategy.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/analysis/MixedContentStrategy.java (revision 0) @@ -0,0 +1,96 @@ +/** + * 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.analysis; + +import javax.xml.xpath.XPathExpressionException; + +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.apache.lucene.gdata.search.config.IndexSchemaField.ContentType; +import org.w3c.dom.Node; + +/** + * @author Simon Willnauer + * + */ +public class MixedContentStrategy extends ContentStrategy { + protected ContentStrategy strategy; + + protected MixedContentStrategy(IndexSchemaField fieldConfiguration) { + super(fieldConfiguration); + + } + + /** + * @throws NotIndexableException + * @see org.apache.lucene.gdata.search.analysis.ContentStrategy#processIndexable(org.apache.lucene.gdata.search.analysis.Indexable) + */ + @Override + public void processIndexable( + Indexable indexable) + throws NotIndexableException { + String path = this.config.getTypePath(); + + try { + Node node = indexable.applyPath(path); + if (node == null) + this.strategy = new PlainTextStrategy(this.config); + else { + String contentType = node.getTextContent(); + + this.strategy = chooseStrategy(contentType, this.config); + } + this.strategy.processIndexable(indexable); + } catch (XPathExpressionException e) { + throw new NotIndexableException("Can not apply path -- " + path); + + } + } + + /** + * @see org.apache.lucene.gdata.search.analysis.ContentStrategy#createLuceneField() + */ + @Override + public Field[] createLuceneField() { + + return this.strategy.createLuceneField(); + } + + private static ContentStrategy chooseStrategy(final String contentType, + final IndexSchemaField config) { + ContentType type = null; + try { + type = ContentType.valueOf(contentType==null?"TEXT":contentType.toUpperCase()); + } catch (Throwable e) { + type = ContentType.TEXT; + } + + switch (type) { + case HTML: + return new HTMLStrategy(config); + + case XHTML: + return new XHtmlStrategy(config); + + default: + return new PlainTextStrategy(config); + + } + } + +} Index: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/HTMLStrategy.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/analysis/HTMLStrategy.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/analysis/HTMLStrategy.java (revision 0) @@ -0,0 +1,98 @@ +/** + * 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.analysis; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; + +import javax.xml.xpath.XPathExpressionException; + +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.parser.XMLDocumentFilter; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLParserConfiguration; +import org.cyberneko.html.HTMLConfiguration; +import org.cyberneko.html.filters.ElementRemover; +import org.cyberneko.html.filters.Writer; +import org.w3c.dom.Node; + +/** + * This ContentStrategy applies the path to the Indexable and retrieves the + * plain string content from the returning node. All of the nodes text content + * will cleaned from any html tags. + * + * @author Simon Willnauer + * + */ +public class HTMLStrategy extends + org.apache.lucene.gdata.search.analysis.ContentStrategy { + private static final String REMOVE_SCRIPT = "script"; + + private static final String CHAR_ENCODING = "UTF-8"; + + protected HTMLStrategy(IndexSchemaField fieldConfiguration) { + super(fieldConfiguration); + + } + + /** + * @see org.apache.lucene.gdata.search.analysis.ContentStrategy#processIndexable(org.apache.lucene.gdata.search.analysis.Indexable) + */ + @Override + public void processIndexable(Indexable indexable) + throws NotIndexableException { + String path = this.config.getPath(); + Node node = null; + try { + node = indexable.applyPath(path); + } catch (XPathExpressionException e1) { + throw new NotIndexableException("Can not apply path -- " + path); + + } + if(node == null) + throw new NotIndexableException("Could not retrieve content for schema field: "+this.config); + StringReader contentReader = new StringReader(node.getTextContent()); + /* + * remove all elements and script parts + */ + ElementRemover remover = new ElementRemover(); + remover.removeElement(REMOVE_SCRIPT); + StringWriter contentWriter = new StringWriter(); + Writer writer = new Writer(contentWriter, CHAR_ENCODING); + XMLDocumentFilter[] filters = { remover, writer, }; + XMLParserConfiguration parser = new HTMLConfiguration(); + parser.setProperty("http://cyberneko.org/html/properties/filters", + filters); + XMLInputSource source = new XMLInputSource(null, null, null, + contentReader, CHAR_ENCODING); + try { + parser.parse(source); + } catch (XNIException e) { + throw new NotIndexableException("Can not parse html -- ", e); + + } catch (IOException e) { + throw new NotIndexableException("Can not parse html -- ", e); + + } + this.content = contentWriter.toString(); + } + + + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/HTMLStrategy.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/KeywordStrategy.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/analysis/KeywordStrategy.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/analysis/KeywordStrategy.java (revision 0) @@ -0,0 +1,57 @@ +/** + * 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.analysis; + +import javax.xml.xpath.XPathExpressionException; + +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.w3c.dom.Node; + +/** + * @author Simon Willnauer + * + */ +public class KeywordStrategy extends ContentStrategy { + + /** + * @param fieldConfig + */ + public KeywordStrategy(IndexSchemaField fieldConfig) { + super(Field.Index.UN_TOKENIZED,Field.Store.YES,fieldConfig); + } + + /** + * @see org.apache.lucene.gdata.search.analysis.ContentStrategy#processIndexable(org.apache.lucene.gdata.search.analysis.Indexable) + */ + @Override + public void processIndexable(Indexable indexable) throws NotIndexableException { + String path = this.config.getPath(); + try { + Node node = indexable.applyPath(path); + if(node == null) + throw new NotIndexableException("Could not retrieve content for schema field: "+this.config); + this.content = node.getTextContent(); + } catch (XPathExpressionException e) { + throw new NotIndexableException("Can not apply Path", e); + } + + } + + + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/KeywordStrategy.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/DomIndexable.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/analysis/DomIndexable.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/analysis/DomIndexable.java (revision 0) @@ -0,0 +1,109 @@ +/** + * 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.analysis; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import com.google.gdata.data.ExtensionProfile; +import com.google.gdata.util.common.xml.XmlWriter; + +/** + * Indexable implementation using the W3C Dom API and JAXP XPath + * engine + * + * @author Simon Willnauer + * @param - + * a subtype of {@link org.w3c.dom.Node} returned by the applyPath + * method + * @param - + * a subtype of {@link org.apache.lucene.gdata.data.ServerBaseEntry} + */ +public class DomIndexable extends + Indexable { + private final Document document; + + private final XPath xPath; + + /** + * @param applyAble + * @throws NotIndexableException + */ + public DomIndexable(I applyAble) throws NotIndexableException { + super(applyAble); + if (this.applyAble.getServiceConfig() == null) + throw new NotIndexableException("ServiceConfig is not set"); + try { + this.document = buildDomDocument(); + } catch (ParserConfigurationException e) { + throw new NotIndexableException("Can not create document builder", + e); + + } catch (IOException e) { + throw new NotIndexableException( + "IO Exception occurred while building indexable", e); + + } catch (SAXException e) { + throw new NotIndexableException("Can not parse entry", e); + + } + this.xPath = XPathFactory.newInstance().newXPath(); + + } + + private Document buildDomDocument() throws ParserConfigurationException, + IOException, SAXException { + StringWriter stringWriter = new StringWriter(); + ExtensionProfile profile = this.applyAble.getServiceConfig() + .getExtensionProfile(); + if (profile == null) + throw new IllegalStateException("ExtensionProfile is not set"); + XmlWriter writer = new XmlWriter(stringWriter); + this.applyAble.generateAtom(writer, profile); + DocumentBuilder builder = DocumentBuilderFactory.newInstance() + .newDocumentBuilder(); + return builder.parse(new InputSource(new StringReader(stringWriter + .toString()))); + + } + + /** + * @see org.apache.lucene.gdata.search.analysis.Indexable#applyPath(java.lang.String) + */ + @SuppressWarnings("unchecked") + @Override + public R applyPath(String expression) throws XPathExpressionException { + + return (R) this.xPath.evaluate(expression, this.document, + XPathConstants.NODE); + } + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/DomIndexable.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/Indexable.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/analysis/Indexable.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/analysis/Indexable.java (revision 0) @@ -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.analysis; + +import javax.xml.xpath.XPathExpressionException; + +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.w3c.dom.Node; + +/** + * This class wraps the access to the GData entities to access them via xpath + * expressions. An arbitrary valid Xpath expression can be passed to the + * applyPath method to access an element, attribute etc. in the gdata + * entity. + * + * @author Simon Willnauer + * @param - + * a subtype of {@link org.w3c.dom.Node} returned by the applyPath + * method + * @param - + * a subtype of {@link org.apache.lucene.gdata.data.ServerBaseEntry} + */ +public abstract class Indexable { + protected ServerBaseEntry applyAble; + + /** + * @param applyAble + */ + Indexable(I applyAble) { + this.applyAble = applyAble; + } + + /** + * @param xPath - + * a valid xpath expression + * @return - the requested element R + * @throws XPathExpressionException + */ + public abstract R applyPath(String xPath) throws XPathExpressionException; + + /** + * Factory method to create new Indexable instances. + * + * @param - + * a subtype of {@link org.w3c.dom.Node} returned by the + * applyPath method + * @param - + * a subtype of + * {@link org.apache.lucene.gdata.data.ServerBaseEntry} + * @param entry - + * the entry to wrap in a Indexable + * @return - a new instance of Indexable to access the entry via + * Xpath + * @throws NotIndexableException - if I can not be parsed. + */ + public static Indexable getIndexable( + I entry) throws NotIndexableException { + return new DomIndexable(entry); + } + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/Indexable.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/NotIndexableException.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/analysis/NotIndexableException.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/analysis/NotIndexableException.java (revision 0) @@ -0,0 +1,78 @@ +/** + * 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.analysis; + +/** + * This exception will be thrown by ContentStrategy instances if an exception + * occurs while retrieving content from entries + * + * @author Simon Willnauer + * + */ +public class NotIndexableException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1538388864181786380L; + + /** + * Constructs a new NotIndexableException + */ + public NotIndexableException() { + super(); + + } + + /** + * Constructs a new NotIndexableException with the specified detail message. + * + * @param arg0 - + * detail message + */ + public NotIndexableException(String arg0) { + super(arg0); + + } + + /** + * Constructs a new NotIndexableException with the specified detail message + * and nested exception. + * + * @param arg0 - + * detail message + * @param arg1 - + * nested exception + */ + public NotIndexableException(String arg0, Throwable arg1) { + super(arg0, arg1); + + } + + /** + * Constructs a new NotIndexableException with a nested exception caused + * this exception. + * + * @param arg0 - + * nested exception + */ + public NotIndexableException(Throwable arg0) { + super(arg0); + + } + +} Index: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/PlainTextStrategy.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/analysis/PlainTextStrategy.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/analysis/PlainTextStrategy.java (revision 0) @@ -0,0 +1,54 @@ +/** + * 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.analysis; + +import javax.xml.xpath.XPathExpressionException; + +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.w3c.dom.Node; + +/** + * @author Simon Willnauer + * + */ +public class PlainTextStrategy extends ContentStrategy { + + protected PlainTextStrategy(IndexSchemaField fieldConfiguration) { + super(fieldConfiguration); + + } + + /** + * @see org.apache.lucene.gdata.search.analysis.ContentStrategy#processIndexable(org.apache.lucene.gdata.search.analysis.Indexable) + */ + @Override + public void processIndexable(Indexable indexable) + throws NotIndexableException { + String path = this.config.getPath(); + try { + Node node = indexable.applyPath(path); + if(node == null) + throw new NotIndexableException("Could not retrieve content for schema field: "+this.config); + this.content = node.getTextContent(); + + } catch (XPathExpressionException e) { + throw new NotIndexableException("Can not apply Path", e); + } + } + +} Index: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/ContentStrategy.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/analysis/ContentStrategy.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/analysis/ContentStrategy.java (revision 0) @@ -0,0 +1,176 @@ +/** + * 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.analysis; + +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.data.ServerBaseEntry; +import org.apache.lucene.gdata.search.config.IndexSchemaField; +import org.apache.lucene.gdata.search.config.IndexSchemaField.ContentType; +import org.apache.lucene.gdata.search.index.GdataIndexerException; +import org.apache.lucene.gdata.utils.ReflectionUtils; +import org.w3c.dom.Node; + +/** + * Creating Indexable document requires processing of incoming entities as + * GData Entries. Entries in the GData protocol might have very different + * structures and content. They all have on thing in common as they are atom xml + * format. To retrieve the configured elements of the atom format and process the + * actual content might differ from element to element. + *

+ * Each predefined ContentStrategy can be used to retrieve certain content from + * the defined element. Which element to process is defined using a XPath + * expression in the gdata-config.xml file. + *

+ *

+ * ContentStrategy implementation should not be accessed directly. To + * get a ContentStrategy for a specific + * {@link org.apache.lucene.gdata.search.config.IndexSchemaField.ContentType} + * use the {@link ContentStrategy#getFieldStrategy} factory method. This method + * expects a IndexSchemaField instance with a set ContentType. The + * return value is a new ContentStrategy instance for the defined + * ContentType. + *

+ * + * @see org.apache.lucene.gdata.search.config.IndexSchemaField.ContentType + * @see org.apache.lucene.gdata.search.index.IndexDocumentBuilder + * + * @author Simon Willnauer + */ +public abstract class ContentStrategy { + protected final Store store; + + protected final Index index; + + protected final IndexSchemaField config; + + protected String content; + + protected String fieldName; + + protected ContentStrategy(IndexSchemaField fieldConfiguration) { + this(null, null, fieldConfiguration); + } + + protected ContentStrategy(Index index, Store store, + IndexSchemaField fieldConfig) { + if(fieldConfig == null) + throw new IllegalArgumentException("IndexSchemaField must not be null"); + this.config = fieldConfig; + this.fieldName = fieldConfig.getName(); + if (index != null) { + this.index = index; + } else { + this.index = fieldConfig.getIndex() == null ? IndexSchemaField.DEFAULT_INDEX_STRATEGY + : fieldConfig.getIndex(); + } + if (store != null) { + this.store = store; + } else { + this.store = fieldConfig.getStore() == null ? IndexSchemaField.DEFAULT_STORE_STRATEGY + : fieldConfig.getStore(); + } + + } + + /** + * @param indexable + * @throws NotIndexableException + */ + public abstract void processIndexable( + Indexable indexable) + throws NotIndexableException; + + /** + * This method creates a lucene field from the retrieved content of the + * entity. Values for Field.Index, Field.Store, the field name and the boost + * factor are configured in the IndexSchemaField passed by the + * constructor e.g the factory method. This method might be overwritten by + * subclasses. + * + * @return the Lucene {@link Field} + */ + public Field[] createLuceneField() { + /* + * should I test the content for being empty?! + * does that make any difference if empty fields are indexed?! + */ + if(this.fieldName==null|| this.content == null) + throw new GdataIndexerException("Required field not set fieldName: "+this.fieldName+" content: "+this.content); + + Field retValue = new Field(this.fieldName, this.content, this.store, + this.index); + float boost = this.config.getBoost(); + if (boost != 1.0f) + retValue.setBoost(boost); + return new Field[]{retValue}; + + } + + /** + * This factory method creates the ContentStrategy corresponding + * to the set ContentType value in the IndexSchemaField + * passed to the method as the single parameter. + *

+ * The ContentType must not be null + *

+ * + * @param fieldConfig - + * the field config to use to identify the corresponding + * ContentStrategy + * @return - a new ContentStrategy instance + */ + public static ContentStrategy getFieldStrategy(IndexSchemaField fieldConfig) { + if (fieldConfig == null) + throw new IllegalArgumentException( + "field configuration must not be null"); + ContentType type = fieldConfig.getContentType(); + if (type == null) + throw new IllegalArgumentException( + "ContentType in IndexSchemaField must not be null"); + fieldConfig.getAnalyzerClass(); + + switch (type) { + case CATEGORY: + return new GdataCategoryStrategy(fieldConfig); + case HTML: + return new HTMLStrategy(fieldConfig); + case XHTML: + return new XHtmlStrategy(fieldConfig); + case GDATADATE: + return new GdataDateStrategy(fieldConfig); + case TEXT: + return new PlainTextStrategy(fieldConfig); + case KEYWORD: + return new KeywordStrategy(fieldConfig); + case CUSTOM: + /* + * check if this class can be created with default const. is checked + * in IndexSchemaField#setFieldClass and throws RuntimeEx if not. So + * server can not start up. + */ + return ReflectionUtils.getDefaultInstance(fieldConfig + .getFieldClass()); + case MIXED: + return new MixedContentStrategy(fieldConfig); + default: + throw new RuntimeException("No content strategy found for " + type); + } + + } + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/ContentStrategy.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/analysis/package.html =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/analysis/package.html (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/analysis/package.html (revision 0) @@ -0,0 +1,10 @@ + + + + + + + +Classes used for extracting content from entries and building lucene documents. + + \ No newline at end of file Index: gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchema.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchema.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchema.java (revision 0) @@ -0,0 +1,451 @@ +/** + * 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 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. + *

+ * 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. + *

+ *

+ * 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. + *

+ * + * + * @see org.apache.lucene.gdata.search.config.IndexSchemaField + * + * + * @author Simon Willnauer + */ +public class IndexSchema { + 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 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 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 boolean useCompoundFile = false; + + /** + * Creates a new IndexSchema and initialize the standard service analyzer to + * {@link StandardAnalyzer} + * + */ + public IndexSchema() { + this.schemaFields = new ArrayList(); + /* + * 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"); + + } + + /** + * @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 + * null 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; + if (field.getName().equals(IndexDocument.FIELD_ENTRY_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); + + } + + /** + * @return Returns the fieldConfiguration. + */ + public Collection 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 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) { + + 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 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(); + + + } +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchema.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchemaField.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchemaField.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchemaField.java (revision 0) @@ -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}. + *

+ * 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. + *

+ *

+ * 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. + *

+ * @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 analyzerClass; + + private Class fieldClass; + + /** + * Constructs a new SchemaField
+ * Default values: + *
    + *
  1. boost: 1.0
  2. + *
  3. index: TOKENIZED
  4. + *
  5. store: NO
  6. + *
+ */ + 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 getAnalyzerClass() { + return this.analyzerClass; + } + + /** + * @param alanyzerClass + * The alanyzerClass to set. + */ + public void setAnalyzerClass(Class alanyzerClass) { + this.analyzerClass = alanyzerClass; + } + + /** + * @return Returns the fieldClass. + */ + public Class 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 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.canCreateInstance(fieldClass)) + 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 + * IndexSchemaField 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 (this.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); + } + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/config/IndexSchemaField.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/config/package.html =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/config/package.html (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/config/package.html (revision 0) @@ -0,0 +1,10 @@ + + + + + + + +All classes used for index and search configuration + + \ No newline at end of file Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexer.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexer.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexer.java (revision 0) @@ -0,0 +1,487 @@ +/** + * 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. + *

+ * 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.
+ * Although this class provides methods to add, remove and update document in + * the index all IndexDocument 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. + *

+ * + * + * + * @author Simon Willnauer + */ +public class GDataIndexer { + private static final Log LOG = LogFactory.getLog(GDataIndexer.class); + + protected IndexWriter writer; + + protected IndexSearcher searcher; + + 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 listeners = new ArrayList(); + + protected final BlockingQueue> futurQueue = new LinkedBlockingQueue>( + 100); + + private final IndexSchema serviceConfiguration; + + private final ExecutorService indexTaskExecutor; + + private IndexTask indexTask; + + private static final Integer ZERO = new Integer(0); + + private static final Integer ONE = new Integer(1); + + private final Map 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(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 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 { + Integer docCountToKeep = this.action.get(indexable); + + /* + * 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 + */ + if (docCountToKeep == null || docCountToKeep == 0) + this.action.put(indexable, ONE); + doWrite(indexable); + this.docsAdded.incrementAndGet(); + + } + + protected synchronized void updateDocument(IndexDocument indexable) + throws IOException { + Integer docCountToKeep = this.action.get(indexable); + + /* + * 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 + */ + if (docCountToKeep == null || docCountToKeep == 0) + this.action.put(indexable, ONE); + doWrite(indexable); + this.docsUpdated.incrementAndGet(); + } + + protected synchronized void deleteDocument(IndexDocument indexable) { + Integer docCountToKeep = this.action.get(indexable); + /* + * add a zero for zero documents to keep for this IndexDocument when + * doDelete + */ + if (docCountToKeep == null || docCountToKeep > 0) + this.action.put(indexable, ZERO); + 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 - + * true 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(); + if (changes == 0) + return; + 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) { + 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 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 docs are processed + */ + this.action.clear(); + + } + + 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 - + * true to create a new index, false + * 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 - + * true to create a new index, false + * 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") + private static final class FinishingFuture implements Future { + + /** + * @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 false; + } + + /** + * @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; + } + + } + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexer.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexEventListener.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexEventListener.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexEventListener.java (revision 0) @@ -0,0 +1,36 @@ +/** + * 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 interface should be implemented by classes need to be notified when an + * index is commited + * + * @author Simon Willnauer + * + */ +public interface IndexEventListener { + + /** + * This method will be invoked by an instance of {@link GDataIndexer} if the + * index is commited + * + * @param service - + * the name of the service the invoking indexer runs for + */ + public abstract void commitCallBack(String service); + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexEventListener.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocumentBuilderTask.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocumentBuilderTask.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocumentBuilderTask.java (revision 0) @@ -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 java.util.Collection; + +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.analysis.ContentStrategy; +import org.apache.lucene.gdata.search.analysis.Indexable; +import org.apache.lucene.gdata.search.analysis.NotIndexableException; +import org.apache.lucene.gdata.search.config.IndexSchema; +import org.apache.lucene.gdata.search.config.IndexSchemaField; + +/** + * This callable does all of the entiti processing concurrently while added to + * the {@link org.apache.lucene.gdata.search.index.GDataIndexer} task queue; + * + * @see org.apache.lucene.gdata.search.analysis.Indexable + * @see org.apache.lucene.gdata.search.analysis.ContentStrategy + * @author Simon Willnauer + * + */ +class IndexDocumentBuilderTask implements IndexDocumentBuilder { + private static final Log LOG = LogFactory + .getLog(IndexDocumentBuilderTask.class); + + private final ServerBaseEntry entry; + + private final IndexSchema schema; + + private final IndexAction action; + + private final boolean commitAfter; + + protected IndexDocumentBuilderTask(final ServerBaseEntry entry, + final IndexSchema schema, IndexAction action, boolean commitAfter) { + /* + * omit check for null parameter this happens in the controller. + */ + this.schema = schema; + this.entry = entry; + this.action = action; + this.commitAfter = commitAfter; + } + + /** + * @see java.util.concurrent.Callable#call() + */ + @SuppressWarnings("unchecked") + public T call() throws GdataIndexerException { + Collection fields = this.schema.getFields(); + GDataIndexDocument document = new GDataIndexDocument(this.action, + this.entry.getId(), this.commitAfter); + int addedFields = 0; + for (IndexSchemaField field : fields) { + /* + * get the strategy to process the field + */ + ContentStrategy strategy = ContentStrategy.getFieldStrategy(field); + if (LOG.isInfoEnabled()) + LOG.info("Process indexable for " + field); + try { + /* + * get the indexable via the factory method to enable new / + * different implementation of the interface (this could be a + * faster dom impl e.g. dom4j) + */ + strategy.processIndexable(Indexable.getIndexable(this.entry)); + addedFields++; + } catch (NotIndexableException e) { + LOG.warn("Can not create field for " + field+" field will be skipped -- reason: ", e); + continue; + } + + document.addField(strategy); + + } + if(addedFields == 0) + throw new GdataIndexerException("No field added to document for Schema: "+this.schema); + return (T)document; + } + + +} Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexWriter.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexWriter.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexWriter.java (revision 0) @@ -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 create is false + */ + 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); + } + +} Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexAction.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexAction.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexAction.java (revision 0) @@ -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 +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexAction.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocument.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocument.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocument.java (revision 0) @@ -0,0 +1,79 @@ +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. + *

+ * 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. + *

+ * + * @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"; + + /** + * @return true if and only if this document is an update, + * otherwise false + */ + public abstract boolean isUpdate(); + + /** + * @return true if and only if this document is a delete, + * otherwise false + */ + public abstract boolean isDelete(); + + /** + * @return true if and only if this document is an insert, + * otherwise false + */ + public abstract boolean isInsert(); + + /** + * + * @return - the lucene document to write to the index if the action is + * insert or updated, otherwise it will return null; + */ + 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 true if the index should be commited after this + * document, otherwise false + */ + public abstract boolean commitAfter(); + + /** + * Indicates that the index should be optimized after this document has been + * processed + * + * + * @return true if the index should be optimized after this + * document, otherwise false + */ + public abstract boolean optimizeAfter(); + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocument.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexDocument.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexDocument.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexDocument.java (revision 0) @@ -0,0 +1,132 @@ +/** + * 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; + + private Collection fields; + + GDataIndexDocument(IndexAction action, String entryId, boolean commitAfter) { + this.action = action; + this.id = entryId; + this.fields = new ArrayList(10); + this.commitAfter = commitAfter; + // TODO implement this + this.optimizeAfter = false; + } + + /** + * Adds a new field e.g. ContentStrategy 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)); + 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; + } + +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/index/GDataIndexDocument.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexTask.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexTask.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexTask.java (revision 0) @@ -0,0 +1,167 @@ +/** + * 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.concurrent.BlockingQueue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * Class to be used inside a + * {@link org.apache.lucene.gdata.search.index.GDataIndexer} to process the task + * queue. This class calls the commit method of the indexer if commit is + * scheduled. + * + * @author Simon Willnauer + * + */ +class IndexTask implements Runnable { + private static final Log INNERLOG = LogFactory.getLog(IndexTask.class); + + private AtomicBoolean stopped = new AtomicBoolean(false); + + private final GDataIndexer indexer; + + protected AtomicBoolean commit = new AtomicBoolean(false); + + /* + * keep protected for subclassing + */ + protected final BlockingQueue> taskQueue; + + IndexTask(final GDataIndexer indexer, + final BlockingQueue> taskQueue) { + this.indexer = indexer; + this.taskQueue = taskQueue; + } + + /** + * @see java.lang.Runnable#run() + */ + public void run() { + + while (!this.stopped.get() || this.taskQueue.size() != 0) { + + try { + /* + * get the future from the queue and wait until processing has + * been done + */ + Future future = getTask(); + if (future != null) { + IndexDocument document = future.get(); + processDocument(document); + /* + * the document contains the info for commit or optimize --> + * this comes from the controller + */ + if (document == null || document.commitAfter()) + this.indexer.commit(document == null ? false : document + .optimizeAfter()); + } + if (this.commit.getAndSet(false)) + this.indexer.commit(false); + + } catch (InterruptedException e) { + INNERLOG.warn("Queue is interrupted exiting IndexTask -- ", e); + + } catch (GdataIndexerException e) { + /* + * + * TODO fire callback here as well + */ + INNERLOG.error("can not retrieve Field from IndexDocument ", e); + } catch (ExecutionException e) { + /* + * TODO callback for fail this exception is caused by an + * exception while processing the document. call back for failed + * docs should be placed here + */ + INNERLOG.error("Future throws execution exception ", e); + + } catch (IOException e) { + INNERLOG.error("IOException thrown while processing document ", + e); + + } catch (Throwable e) { + /* + * catch all to prevent the thread from dieing + */ + INNERLOG.error( + "Unexpected exception while processing document -- " + + e.getMessage(), e); + } + } + try { + this.indexer.commit(false); + } catch (IOException e) { + + e.printStackTrace(); + } + this.stop(); + } + + /* + * keep this protected for subclassing see TimedIndexTask! + */ + protected Future getTask() throws InterruptedException { + return this.taskQueue.take(); + } + + private void processDocument(IndexDocument document) throws IOException { + /* + * a null document is used for waking up the task if the indexer has + * been destroyed to finish up and commit. should I change this?! --> + * see TimedIndexTask#getTask() also!! + */ + if (document == null) { + INNERLOG.warn("Can not process document -- is null -- run commit"); + return; + } + if (document.isDelete()) { + this.indexer.deleteDocument(document); + return; + } else if (document.isInsert()) { + this.indexer.addDocument(document); + return; + } else if (document.isUpdate()) { + this.indexer.updateDocument(document); + return; + } + /* + * that should not happen -- anyway skip the document and write it to + * the log + */ + INNERLOG.warn("IndexDocument has no Action " + document); + + } + + protected boolean isStopped() { + return this.stopped.get(); + } + + protected void stop() { + this.stopped.set(true); + } + +} \ No newline at end of file Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexController.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexController.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexController.java (revision 0) @@ -0,0 +1,371 @@ +/** + * 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.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.index.IndexFileNameFilter; +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 { + private static final Log LOG = LogFactory.getLog(IndexController.class); + + private static final int COMMIT_COUNT = 15; + + private final AtomicBoolean isInitialized = new AtomicBoolean(false); + + private final AtomicBoolean destroyed = new AtomicBoolean(false); + + protected Map 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 void initialize() { + /* + * if this fails the server must not startup --> throw runtime xeception + */ + GDataServerRegistry.getRegistry().registerEntryEventListener(this); + + this.indexerMap = new ConcurrentHashMap(6); + GDataServerRegistry.getRegistry().registerEntryEventListener(this); + Collection services = GDataServerRegistry + .getRegistry().getServices(); + 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 indexcontroller and create the indexer. create + * directories and check out exising 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); + 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 commited indexer?! keep the possibilty 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); + return new ServiceIndex(schema, indexer); + } + + /* + * 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 direcoty + */ + 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 void commitCallBack(String service) { + // TODO for searchers + } + + /** + * @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"); + + 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 { + boolean commitAfter = bean.incrementActionAndReset(COMMIT_COUNT); + IndexDocumentBuilder callable = new IndexDocumentBuilderTask( + entry, bean.getSchema(), action, commitAfter); + Future 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 getServiceSearcher(ProvidedService service) { + if (this.destroyed.get()) + throw new IllegalStateException( + "IndexController has been destroyed"); + return null; + } + + /** + * @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; + LOG.info("Shutting down IndexController -- destroy has been called"); + Set> entrySet = this.indexerMap.entrySet(); + for (Entry entry : entrySet) { + ServiceIndex bean = entry.getValue(); + GDataIndexer indexer = bean.getIndexer(); + try { + indexer.destroy(); + } catch (IOException e) { + LOG.warn("Can not destory indexer for service: " + + bean.getSchema().getName(), e); + } + } + this.taskExecutor.shutdown(); + this.indexerMap.clear(); + } + + static class ServiceIndex { + private AtomicInteger actionCount = new AtomicInteger(0); + + private final Lock lock; + + private final IndexSchema schema; + + private final GDataIndexer indexer; + + // private final Map actionMap; + + ServiceIndex(final IndexSchema schema, GDataIndexer indexer) { + this.schema = schema; + this.indexer = indexer; + this.lock = new ReentrantLock(true); + // this.actionMap = new HashMap(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 - + * if this value is greater or equals the count, the count + * will be reset to 0 + * @return true if the count has been set to 0, otherwise + * false; + */ + boolean incrementActionAndReset(int reset) { + if (this.actionCount.get() >= reset) { + this.actionCount.getAndSet(0); + return true; + } + this.actionCount.incrementAndGet(); + return false; + } + + } +} Property changes on: gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexController.java ___________________________________________________________________ Name: svn:executable + * Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocumentBuilder.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocumentBuilder.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/IndexDocumentBuilder.java (revision 0) @@ -0,0 +1,32 @@ +/** + * 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.concurrent.Callable; + +/** + * Interface for DocumentBuilders + * @author Simon Willnauer + * @param IndexDocument implementation + * + */ +public interface IndexDocumentBuilder extends Callable{ + /** + * @see java.util.concurrent.Callable#call() + */ + public T call() throws GdataIndexerException; + +} Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/TimedIndexTask.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/TimedIndexTask.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/TimedIndexTask.java (revision 0) @@ -0,0 +1,63 @@ +/** + * 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.concurrent.BlockingQueue; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +/** + * This {@link IndexTask} will idle the given time if no task is on the queue. + * If the idle time exceeds the task will force a commit on the index. The timer + * will be reset if a task is on the queue. + * + * @author Simon Willnauer + * + */ +class TimedIndexTask extends IndexTask { + protected final static TimeUnit TIME_UNIT = TimeUnit.SECONDS; + + protected final static long DEFAULT_IDLE_TIME = 30; + + private final long idleTime; + + TimedIndexTask(final GDataIndexer indexer, + final BlockingQueue> taskQueue, + final long idleTime) { + super(indexer, taskQueue); + this.idleTime = idleTime < DEFAULT_IDLE_TIME ? DEFAULT_IDLE_TIME + : idleTime; + + } + + /** + * @see org.apache.lucene.gdata.search.index.IndexTask#getTask() + */ + @Override + protected Future getTask() throws InterruptedException { + /* + * wait for a certain time and return null if no task is on the queue. + * If return null --> commit will be called + */ + Future retVal = this.taskQueue.poll(this.idleTime, TIME_UNIT); + if(retVal== null) + this.commit.set(true); + return retVal; + + } + +} Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/GdataIndexerException.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/GdataIndexerException.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/GdataIndexerException.java (revision 0) @@ -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); + + } + +} Index: gdata-server/src/java/org/apache/lucene/gdata/search/index/package.html =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/index/package.html (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/index/package.html (revision 0) @@ -0,0 +1,10 @@ + + + + + + + +Contains classes processing of documents and accessing the search index of the server + + \ No newline at end of file Index: gdata-server/src/java/org/apache/lucene/gdata/search/SearchComponent.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/SearchComponent.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/SearchComponent.java (revision 0) @@ -0,0 +1,36 @@ +/** + * 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; + +import org.apache.lucene.gdata.server.registry.ProvidedService; +import org.apache.lucene.gdata.server.registry.ServerComponent; + +/** + * TODO document this when Search comes into play + * @author Simon Willnauer + * + */ +public interface SearchComponent extends ServerComponent { + /** + * TODO document this when Search comes into play + * @param service + * @return a GDataSearcher + */ + public abstract GDataSearcher getServiceSearcher(ProvidedService service); + + +} Index: gdata-server/src/java/org/apache/lucene/gdata/search/GDataSearcher.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/search/GDataSearcher.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/search/GDataSearcher.java (revision 0) @@ -0,0 +1,24 @@ +/** + * 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; + +/** + * @author Simon Willnauer + * + */ +public interface GDataSearcher { + +} Index: gdata-server/src/java/org/apache/lucene/gdata/server/FeedNotFoundException.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/FeedNotFoundException.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/FeedNotFoundException.java (working copy) @@ -12,41 +12,46 @@ private static final long serialVersionUID = 1L; - /** - * Constructs a FeedNotFoundException - */ - public FeedNotFoundException() { - super(); + /** + * Constructs a new FeedNotFoundException + * @param errorCode - gdata request errorcode + */ + public FeedNotFoundException(int errorCode) { + super(errorCode); + + + } + + /** + * Constructs a new FeedNotFoundException + * @param arg0 - the exception message + * @param errorCode - gdata request errorcode + */ + public FeedNotFoundException(String arg0,int errorCode) { + super(arg0, errorCode); + + } + + /** + * Constructs a new FeedNotFoundException + * @param arg0 - the exceptin message + * @param arg1 - the exception cause + * @param errorCode - gdata request errorcode + */ + public FeedNotFoundException(String arg0, Throwable arg1,int errorCode) { + super(arg0, arg1, errorCode); + + + } + + /** + * Constructs a new FeedNotFoundException + * @param arg0 - the exception cause + * @param errorCode - gdata request errorcode + */ + public FeedNotFoundException(Throwable arg0,int errorCode) { + super(arg0, errorCode); + + } - } - - /** - * @param arg0 - - * message - * @param arg1 - - * cause - */ - public FeedNotFoundException(String arg0, Throwable arg1) { - super(arg0, arg1); - - } - - /** - * @param arg0 - - * message - */ - public FeedNotFoundException(String arg0) { - super(arg0); - - } - - /** - * @param arg0 - - * cause - */ - public FeedNotFoundException(Throwable arg0) { - super(arg0); - - } - } \ No newline at end of file Index: gdata-server/src/java/org/apache/lucene/gdata/server/GDataResponse.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/GDataResponse.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/GDataResponse.java (working copy) @@ -35,18 +35,18 @@ import com.google.gdata.util.common.xml.XmlWriter.Namespace; /** - * The FeedRequest Class wraps the curren HttpServletResponse. Any action on the + * The FeedRequest Class wraps the current HttpServletResponse. Any action on the * HttpServletRequest will be executed via this class. This represents an * abstraction on the plain {@link HttpServletResponse}. Any action which has - * to be performed on the underlaying {@link HttpServletResponse} will be + * to be performed on the underlying {@link HttpServletResponse} will be * executed within this class. *

- * The GData basicly writes two different kinds ouf reponse to the output + * The GData basically writes two different kinds of response to the output * stream. *

    - *
  1. update, delete or insert requests will respond with a statuscode and if + *
  2. update, delete or insert requests will respond with a status code and if * successful the feed entry modified or created
  3. - *
  4. get requests will respond with a statuscode and if successful the + *
  5. get requests will respond with a status code and if successful the * requested feed
  6. *
* @@ -70,6 +70,40 @@ * */ public class GDataResponse { + /** + * Response code bad request + */ + public static final int BAD_REQUEST = HttpServletResponse.SC_BAD_REQUEST; + /** + * Response code version conflict + */ + public static final int CONFLICT = HttpServletResponse.SC_CONFLICT; + /** + * Response code forbidden access + */ + public static final int FORBIDDEN = HttpServletResponse.SC_FORBIDDEN; + /** + * Response code internal server error + */ + public static final int SERVER_ERROR = HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + /** + * Response code not found + */ + public static final int NOT_FOUND = HttpServletResponse.SC_NOT_FOUND; + /** + * Response code not modified since + */ + public static final int NOT_MODIFIED = HttpServletResponse.SC_NOT_MODIFIED; + /** + * Response code created + */ + public static final int CREATED = HttpServletResponse.SC_CREATED; + /** + * Response code unauthorized access + */ + public static final int UNAUTHORIZED = HttpServletResponse.SC_UNAUTHORIZED; + + private static final Log LOG = LogFactory.getLog(GDataResponse.class); private int error; @@ -96,7 +130,7 @@ * Creates a new GDataResponse * * @param response - - * The underlaying {@link HttpServletResponse} + * The underlying {@link HttpServletResponse} */ public GDataResponse(HttpServletResponse response) { if (response == null) @@ -117,7 +151,7 @@ } /** - * Sets the status of the underlaying response + * Sets the status of the underlying response * * @see HttpServletResponse * @param responseCode - @@ -131,7 +165,7 @@ * This method sends the specified error to the user if set * * @throws IOException - - * if an I/O Exception occures + * if an I/O Exception occurs */ public void sendError() throws IOException { if (this.isError) @@ -142,7 +176,7 @@ /** * @return - the {@link HttpServletResponse} writer * @throws IOException - - * If an I/O exception occures + * If an I/O exception occurs */ public Writer getWriter() throws IOException { return this.response.getWriter(); @@ -150,14 +184,14 @@ /** * Sends a response for a get e.g. query request. This method must not - * invoked in a case of an error performing the requeste action. + * invoked in a case of an error performing the requested action. * * @param feed - * the feed to respond to the client * @param profile - - * the extension profil for the feed to write + * the extension profile for the feed to write * @throws IOException - - * if an I/O exception accures, often caused by an already + * if an I/O exception occurs, often caused by an already * closed Writer or OutputStream * */ @@ -167,7 +201,7 @@ throw new IllegalArgumentException("feed must not be null"); if (profile == null) throw new IllegalArgumentException( - "extension profil must not be null"); + "extension profile must not be null"); DateTime time = feed.getUpdated(); if (time != null) setLastModifiedHeader(time.getValue()); @@ -186,7 +220,7 @@ /** * * Sends a response for an update, insert or delete request. This method - * must not invoked in a case of an error performing the requeste action. If + * must not invoked in a case of an error performing the requested action. If * the specified response format is ATOM the default namespace will be set * to ATOM. * @@ -195,7 +229,7 @@ * @param profile - * the entries extension profile * @throws IOException - - * if an I/O exception accures, often caused by an already + * if an I/O exception occurs, often caused by an already * closed Writer or OutputStream */ public void sendResponse(BaseEntry entry, ExtensionProfile profile) @@ -204,7 +238,7 @@ throw new IllegalArgumentException("entry must not be null"); if (profile == null) throw new IllegalArgumentException( - "extension profil must not be null"); + "extension profile must not be null"); DateTime time = entry.getUpdated(); if (time != null) setLastModifiedHeader(time.getValue()); Index: gdata-server/src/java/org/apache/lucene/gdata/server/ServiceException.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/ServiceException.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/ServiceException.java (working copy) @@ -16,16 +16,18 @@ package org.apache.lucene.gdata.server; + /** * The ServiceException is used to encapsulate all {@link java.lang.Exception} - * throw by underlaying layers of the + * throw by underlying layers of the * {@link org.apache.lucene.gdata.server.Service} layer. * * @author Simon Willnauer * */ public class ServiceException extends Exception { - + + private int errorCode; /** * */ @@ -33,38 +35,51 @@ /** * Constructs a new ServiceException + * @param errorCode - gdata request error code */ - public ServiceException() { + public ServiceException(int errorCode) { super(); + this.errorCode = errorCode; } /** * Constructs a new ServiceException * @param arg0 - the exception message + * @param errorCode - gdata request error code */ - public ServiceException(String arg0) { + public ServiceException(String arg0,int errorCode) { super(arg0); - + this.errorCode = errorCode; } /** * Constructs a new ServiceException - * @param arg0 - the exceptin message + * @param arg0 - the exception message * @param arg1 - the exception cause + * @param errorCode - gdata request error code */ - public ServiceException(String arg0, Throwable arg1) { + public ServiceException(String arg0, Throwable arg1,int errorCode) { super(arg0, arg1); - + this.errorCode = errorCode; + } /** * Constructs a new ServiceException * @param arg0 - the exception cause + * @param errorCode - gdata request error code */ - public ServiceException(Throwable arg0) { + public ServiceException(Throwable arg0,int errorCode) { super(arg0); + this.errorCode = errorCode; + } + /** + * @return Returns the errorCode. + */ + public int getErrorCode() { + return this.errorCode; } } Index: gdata-server/src/java/org/apache/lucene/gdata/server/GDataService.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/GDataService.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/GDataService.java (working copy) @@ -19,13 +19,12 @@ import java.util.Date; import java.util.List; -import javax.servlet.http.HttpServletResponse; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.lucene.gdata.data.ServerBaseEntry; import org.apache.lucene.gdata.data.ServerBaseFeed; import org.apache.lucene.gdata.server.registry.ComponentType; +import org.apache.lucene.gdata.server.registry.EntryEventMediator; import org.apache.lucene.gdata.server.registry.GDataServerRegistry; import org.apache.lucene.gdata.storage.ModificationConflictException; import org.apache.lucene.gdata.storage.ResourceNotFoundException; @@ -48,7 +47,7 @@ * */ public class GDataService implements Service { - private static final Log LOGGER = LogFactory.getLog(GDataService.class); + private static final Log LOG = LogFactory.getLog(GDataService.class); protected Storage storage; @@ -61,6 +60,8 @@ private static final String generatorURI = "http://lucene.apache.org"; private static final String XMLMIME = "application/atom+xml"; + + private final EntryEventMediator entryEventMediator; static { generator = new Generator(); generator.setName(generatorName); @@ -77,14 +78,14 @@ throw new StorageException( "StorageController is not registered"); this.storage = controller.getStorage(); - + this.entryEventMediator = GDataServerRegistry.getRegistry().getEntryEventMediator(); } catch (StorageException e) { - LOGGER + LOG .fatal( "Can't get Storage Instance -- can't serve any requests", e); ServiceException ex = new ServiceException( - "Can't get Storage instance" + e.getMessage(), e); + "Can't get Storage instance" + e.getMessage(), e,GDataResponse.SERVER_ERROR); ex.setStackTrace(e.getStackTrace()); throw ex; } @@ -98,8 +99,8 @@ public BaseEntry createEntry(GDataRequest request, GDataResponse response) throws ServiceException { - if (LOGGER.isInfoEnabled()) - LOGGER.info("create Entry for feedId: " + request.getFeedId()); + if (LOG.isInfoEnabled()) + LOG.info("create Entry for feedId: " + request.getFeedId()); ServerBaseEntry entry = buildEntry(request, response); entry.setFeedId(request.getFeedId()); @@ -111,12 +112,13 @@ try { retVal = this.storage.storeEntry(entry); } catch (Exception e) { - response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + ServiceException ex = new ServiceException("Could not store entry", - e); + e,GDataResponse.SERVER_ERROR); ex.setStackTrace(e.getStackTrace()); throw ex; } + this.entryEventMediator.entryAdded(entry); return retVal; } @@ -135,28 +137,31 @@ setVersionId(entry,request,response); if (entry.getId() == null) throw new ServiceException( - "entry id is null -- can not delete null entry"); + "entry id is null -- can not delete null entry",GDataResponse.SERVER_ERROR); try { this.storage.deleteEntry(entry); + } catch (ResourceNotFoundException e) { - response.setError(HttpServletResponse.SC_BAD_REQUEST); + ServiceException ex = new ServiceException( - "Could not delete entry", e); + "Could not delete entry", e,GDataResponse.BAD_REQUEST); ex.setStackTrace(e.getStackTrace()); throw ex; }catch (ModificationConflictException e) { - response.setError(HttpServletResponse.SC_CONFLICT); + ServiceException ex = new ServiceException( - "Could not delete entry - version confilict", e); + "Could not delete entry - version conflict",e, GDataResponse.CONFLICT); ex.setStackTrace(e.getStackTrace()); throw ex; }catch (StorageException e) { - response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + ServiceException ex = new ServiceException( - "Could not delete entry", e); + "Could not delete entry", e,GDataResponse.SERVER_ERROR); ex.setStackTrace(e.getStackTrace()); throw ex; } + this.entryEventMediator.entryDeleted(entry); + //TODO change ret value return null; } @@ -172,23 +177,22 @@ entry.setFeedId(request.getFeedId()); setVersionId(entry,request,response); entry.setServiceConfig(request.getConfigurator()); - if (LOGGER.isInfoEnabled()) - LOGGER.info("update Entry" + entry.getId() + " for feedId: " + if (LOG.isInfoEnabled()) + LOG.info("update Entry" + entry.getId() + " for feedId: " + request.getFeedId()); if (entry.getId() == null) { - response.setError(HttpServletResponse.SC_BAD_REQUEST); - throw new ServiceException("Entry id is null can not update entry"); + throw new ServiceException("Entry id is null can not update entry",GDataResponse.BAD_REQUEST); } if (!entry.getId().equals(request.getEntryId())) { - if (LOGGER.isInfoEnabled()) - LOGGER + if (LOG.isInfoEnabled()) + LOG .info("Entry id in the entry xml does not match the requested resource -- XML-ID:" + entry.getId() + "; Requested resource: " + request.getEntryId()); - response.setError(HttpServletResponse.SC_BAD_REQUEST); + throw new ServiceException( - "Entry id in the entry xml does not match the requested resource"); + "Entry id in the entry xml does not match the requested resource",GDataResponse.BAD_REQUEST); } BaseEntry tempEntry = entry.getEntry(); tempEntry.setUpdated(getCurrentDateTime()); @@ -199,24 +203,24 @@ try { retVal = this.storage.updateEntry(entry); } catch (ResourceNotFoundException e) { - response.setError(HttpServletResponse.SC_BAD_REQUEST); + ServiceException ex = new ServiceException( - "Could not update entry", e); + "Could not update entry", e,GDataResponse.BAD_REQUEST); ex.setStackTrace(e.getStackTrace()); throw ex; }catch (ModificationConflictException e) { - response.setError(HttpServletResponse.SC_CONFLICT); ServiceException ex = new ServiceException( - "Could not update entry - version confilict", e); + "Could not update entry - version conflict", e,GDataResponse.CONFLICT); ex.setStackTrace(e.getStackTrace()); throw ex; }catch (StorageException e) { - response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + ServiceException ex = new ServiceException( - "Could not update entry", e); + "Could not update entry", e,GDataResponse.SERVER_ERROR); ex.setStackTrace(e.getStackTrace()); throw ex; } + this.entryEventMediator.entryUpdated(entry); return retVal; } @@ -239,12 +243,11 @@ return retVal; /* - * resouce not found will be detected in Gdata request. - * the request queries the storage for the feed to get the serivce for the feed + * Resource not found will be detected in Gdata request. + * the request queries the storage for the feed to get the service for the feed */ } catch (StorageException e) { - response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - ServiceException ex = new ServiceException("Could not get feed", e); + ServiceException ex = new ServiceException("Could not get feed", e,GDataResponse.SERVER_ERROR); ex.setStackTrace(e.getStackTrace()); throw ex; } @@ -267,15 +270,13 @@ return entry; } catch (ParseException e) { - response.setError(HttpServletResponse.SC_BAD_REQUEST); ServiceException ex = new ServiceException( - "Could not parse entry from incoming request", e); + "Could not parse entry from incoming request", e, GDataResponse.BAD_REQUEST); ex.setStackTrace(e.getStackTrace()); throw ex; } catch (IOException e) { - response.setError(HttpServletResponse.SC_BAD_REQUEST); ServiceException ex = new ServiceException( - "Could not read or open input stream", e); + "Could not read or open input stream", e, GDataResponse.BAD_REQUEST); ex.setStackTrace(e.getStackTrace()); throw ex; } @@ -298,8 +299,7 @@ if(entry.getId() == null){ - response.setError(HttpServletResponse.SC_BAD_REQUEST); - throw new ServiceException("entry is null can't get entry"); + throw new ServiceException("entry is null can't get entry", GDataResponse.BAD_REQUEST); } BaseEntry retVal = null; @@ -307,13 +307,12 @@ dynamicElementEntryStragey(retVal, request); return retVal; } catch (ResourceNotFoundException e) { - response.setError(HttpServletResponse.SC_BAD_REQUEST); ServiceException ex = new ServiceException( - "Could not get entry", e); + "Could not get entry", e, GDataResponse.BAD_REQUEST); ex.setStackTrace(e.getStackTrace()); throw ex; } catch (StorageException e) { - ServiceException ex = new ServiceException("Could not get feed", e); + ServiceException ex = new ServiceException("Could not get feed", e, GDataResponse.SERVER_ERROR); ex.setStackTrace(e.getStackTrace()); throw ex; } @@ -392,7 +391,7 @@ } catch (StorageException e) { ServiceException ex = new ServiceException( - "Could not get Last update for feed -- "+feedId, e); + "Could not get Last update for feed -- "+feedId, e, GDataResponse.SERVER_ERROR); ex.setStackTrace(e.getStackTrace()); throw ex; } @@ -405,12 +404,9 @@ public Date getEntryLastModified(final String entryId,final String feedId) throws ServiceException { try { return new Date(this.storage.getEntryLastModified(entryId, feedId)); - - - } catch (StorageException e) { ServiceException ex = new ServiceException( - "Could not get Last update for entry -- "+entryId, e); + "Could not get Last update for entry -- "+entryId, e, GDataResponse.SERVER_ERROR); ex.setStackTrace(e.getStackTrace()); throw ex; } @@ -421,9 +417,8 @@ entry.setVersion(Integer.parseInt(request.getEntryVersion())); return entry; }catch (Exception e) { - LOGGER.error("Can not parse entry version -- version is not an integer -- versionid: "+request.getEntryVersion(),e); - response.setError(HttpServletResponse.SC_BAD_REQUEST); - throw new ServiceException("Can not parse entry version -- version is not an integer -- versionid: "+request.getEntryVersion(),e); + LOG.error("Can not parse entry version -- version is not an integer -- versionid: "+request.getEntryVersion(),e); + throw new ServiceException("Can not parse entry version -- version is not an integer -- versionid: "+request.getEntryVersion(),e, GDataResponse.BAD_REQUEST); } } Index: gdata-server/src/java/org/apache/lucene/gdata/server/administration/AccountBuilder.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/administration/AccountBuilder.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/administration/AccountBuilder.java (working copy) @@ -17,14 +17,18 @@ import java.io.IOException; import java.io.Reader; +import java.net.URL; + + import org.apache.commons.digester.Digester; import org.apache.lucene.gdata.data.GDataAccount; import org.apache.lucene.gdata.utils.SimpleSaxErrorHandler; +import org.apache.xerces.parsers.SAXParser; import org.xml.sax.SAXException; /** - * Helperclass to create {@link org.apache.lucene.gdata.data.GDataAccount} + * Helper class to create {@link org.apache.lucene.gdata.data.GDataAccount} * instances from a xml stream provided via a {@link Reader} instance. * * @author Simon Willnauer @@ -36,16 +40,27 @@ * Reads the xml from the provided reader and binds the values to the * @param reader - the reader to read the xml from * @return - the GDataAccount - * @throws IOException - if an IOException occures + * @throws IOException - if an IOException occurs * @throws SAXException - if the xml can not be parsed by the sax reader */ public static GDataAccount buildAccount(final Reader reader) throws IOException, SAXException { if (reader == null) throw new IllegalArgumentException("Reader must not be null"); - String schemaFile = AccountBuilder.class.getResource("/gdata-account.xsd").getFile(); + URL resource = AccountBuilder.class.getResource("/gdata-account.xsd"); + if(resource == null) + throw new RuntimeException("can not find xml schema file 'gdata-account.xsd' -- file must be present on the classpath"); + String schemaFile = resource.getFile(); GDataAccount account = null; - Digester digester = new Digester(); + /* + * Force using apache xerces parser for digester + */ + SAXParser parser = new SAXParser(); + parser.setFeature("http://apache.org/xml/features/validation/schema-full-checking",true); + parser.setFeature("http://apache.org/xml/features/validation/schema",true); + parser.setFeature("http://xml.org/sax/features/validation",true); + parser.setProperty("http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",schemaFile); + Digester digester = new Digester(parser); digester.setValidating(true); digester.setErrorHandler(new SimpleSaxErrorHandler()); digester.setSchema(schemaFile); @@ -61,7 +76,6 @@ "authorLink"); account = (GDataAccount) digester.parse(reader); - return account; } Index: gdata-server/src/java/org/apache/lucene/gdata/server/administration/GDataAdminService.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/administration/GDataAdminService.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/administration/GDataAdminService.java (working copy) @@ -19,6 +19,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.lucene.gdata.data.GDataAccount; import org.apache.lucene.gdata.data.ServerBaseFeed; +import org.apache.lucene.gdata.server.GDataResponse; import org.apache.lucene.gdata.server.GDataService; import org.apache.lucene.gdata.server.ServiceException; import org.apache.lucene.gdata.storage.StorageException; @@ -47,13 +48,13 @@ */ public void createFeed(final ServerBaseFeed feed,final GDataAccount account) throws ServiceException { if(feed == null) - throw new ServiceException("Can not create feed -- feed is null"); + throw new ServiceException("Can not create feed -- feed is null", GDataResponse.BAD_REQUEST); if(account == null) - throw new ServiceException("Can not create feed -- account is null"); + throw new ServiceException("Can not create feed -- account is null", GDataResponse.UNAUTHORIZED); if(feed.getId() == null) - throw new ServiceException("Feed ID is null can not create feed"); + throw new ServiceException("Feed ID is null can not create feed", GDataResponse.BAD_REQUEST); if(account.getName() == null) - throw new ServiceException("Account name is null -- can't create feed"); + throw new ServiceException("Account name is null -- can't create feed", GDataResponse.UNAUTHORIZED); try { feed.setUpdated(getCurrentDateTime()); feed.setAccount(account); @@ -61,7 +62,7 @@ } catch (StorageException e) { if(LOG.isInfoEnabled()) LOG.info("Can not save feed -- "+e.getMessage(),e); - throw new ServiceException("Can not save feed",e); + throw new ServiceException("Can not save feed",e, GDataResponse.SERVER_ERROR); } } @@ -73,13 +74,13 @@ */ public void updateFeed(ServerBaseFeed feed, GDataAccount account) throws ServiceException { if(feed == null) - throw new ServiceException("Can not update null feed"); + throw new ServiceException("Can not update null feed", GDataResponse.BAD_REQUEST); if(account == null) - throw new ServiceException("Can not update feed -- account is null"); + throw new ServiceException("Can not update feed -- account is null", GDataResponse.UNAUTHORIZED); if(feed.getId() == null) - throw new ServiceException("Feed ID is null can not update feed"); + throw new ServiceException("Feed ID is null can not update feed", GDataResponse.BAD_REQUEST); if(account.getName() == null) - throw new ServiceException("Account name is null -- can't update feed"); + throw new ServiceException("Account name is null -- can't update feed", GDataResponse.UNAUTHORIZED); try { feed.setAccount(account); feed.setUpdated(getCurrentDateTime()); @@ -87,7 +88,7 @@ } catch (StorageException e) { if(LOG.isInfoEnabled()) LOG.info("Can not update feed -- "+e.getMessage(),e); - throw new ServiceException("Can not update feed",e); + throw new ServiceException("Can not update feed",e, GDataResponse.SERVER_ERROR); } } @@ -99,15 +100,15 @@ */ public void deleteFeed(ServerBaseFeed feed) throws ServiceException { if(feed == null) - throw new ServiceException("Can not delete null feed"); + throw new ServiceException("Can not delete null feed", GDataResponse.BAD_REQUEST); if(feed.getId() == null) - throw new ServiceException("Feed ID is null can not delete feed"); + throw new ServiceException("Feed ID is null can not delete feed", GDataResponse.BAD_REQUEST); try { this.storage.deleteFeed(feed.getId()); } catch (StorageException e) { if(LOG.isInfoEnabled()) LOG.info("Can not delete feed -- "+e.getMessage(),e); - throw new ServiceException("Can not delete feed",e); + throw new ServiceException("Can not delete feed",e, GDataResponse.SERVER_ERROR); } } @@ -117,13 +118,13 @@ */ public void createAccount(GDataAccount account) throws ServiceException { if(account == null) - throw new ServiceException("Can not save null account"); + throw new ServiceException("Can not save null account", GDataResponse.BAD_REQUEST); try { this.storage.storeAccount(account); } catch (StorageException e) { if(LOG.isInfoEnabled()) LOG.info("Can not save account -- "+e.getMessage(),e); - throw new ServiceException("Can not save account",e); + throw new ServiceException("Can not save account",e, GDataResponse.SERVER_ERROR); } } @@ -132,13 +133,13 @@ */ public void deleteAccount(GDataAccount account) throws ServiceException { if(account == null) - throw new ServiceException("Can not delete null account"); + throw new ServiceException("Can not delete null account", GDataResponse.BAD_REQUEST); try { this.storage.deleteAccount(account.getName()); } catch (StorageException e) { if(LOG.isInfoEnabled()) LOG.info("Can not save account -- "+e.getMessage(),e); - throw new ServiceException("Can not save account",e); + throw new ServiceException("Can not save account",e, GDataResponse.SERVER_ERROR); } } @@ -147,13 +148,13 @@ */ public void updateAccount(GDataAccount account) throws ServiceException { if(account == null) - throw new ServiceException("Can not update null account"); + throw new ServiceException("Can not update null account", GDataResponse.BAD_REQUEST); try { this.storage.updateAccount(account); } catch (StorageException e) { if(LOG.isInfoEnabled()) LOG.info("Can not save account -- "+e.getMessage(),e); - throw new ServiceException("Can not save account",e); + throw new ServiceException("Can not save account",e, GDataResponse.SERVER_ERROR); } } @@ -162,13 +163,13 @@ */ public GDataAccount getAccount(String accountName)throws ServiceException{ if(accountName == null) - throw new ServiceException("Can not get null account"); + throw new ServiceException("Can not get null account", GDataResponse.BAD_REQUEST); try { return this.storage.getAccount(accountName); } catch (StorageException e) { if(LOG.isInfoEnabled()) LOG.info("Can not get account -- "+e.getMessage(),e); - throw new ServiceException("Can not get account",e); + throw new ServiceException("Can not get account",e, GDataResponse.SERVER_ERROR); } } @@ -180,7 +181,7 @@ */ public GDataAccount getFeedOwningAccount(String feedId) throws ServiceException { if(feedId == null) - throw new ServiceException("Can not get account - feed id must not be null"); + throw new ServiceException("Can not get account - feed id must not be null", GDataResponse.BAD_REQUEST); try { String accountName = this.storage.getAccountNameForFeedId(feedId); return this.storage.getAccount(accountName); @@ -188,7 +189,7 @@ } catch (StorageException e) { if(LOG.isInfoEnabled()) LOG.info("Can not get account for feed Id -- "+e.getMessage(),e); - throw new ServiceException("Can not get account for the given feed id",e); + throw new ServiceException("Can not get account for the given feed id",e, GDataResponse.SERVER_ERROR); } } Index: gdata-server/src/java/org/apache/lucene/gdata/server/registry/GDataServerRegistry.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/registry/GDataServerRegistry.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/registry/GDataServerRegistry.java (working copy) @@ -25,12 +25,13 @@ import org.apache.commons.logging.LogFactory; import org.apache.lucene.gdata.server.registry.configuration.ComponentConfiguration; import org.apache.lucene.gdata.server.registry.configuration.PropertyInjector; +import org.apache.lucene.gdata.utils.ReflectionUtils; /** * * The GDataServerRegistry represents the registry component of the GData * Server. All provided services and server components will be registered here. - * The Gdata Server serves RSS / ATOM feeds for defined services. Each service + * The GData Server serves RSS / ATOM feeds for defined services. Each service * provides n feeds of a defined subclass of * {@link com.google.gdata.data.BaseFeed}. Each feed contains m entries * of a defined subclass of {@link com.google.gdata.data.BaseEntry}. To @@ -42,9 +43,9 @@ *

*

* The components defined in the gdata-config.xml will also be loaded and - * instanciated at startup. If a component can not be loaded or an Exception - * occures the server will not start up. To cause of the exception or error will - * be logged to the standart server output. + * instantiated at startup. If a component can not be loaded or an Exception + * occurs the server will not start up. To cause of the exception or error will + * be logged to the standard server output. *

*

* The GDataServerRegistry is a Singleton @@ -54,16 +55,17 @@ * @author Simon Willnauer * */ -public class GDataServerRegistry { +public class GDataServerRegistry extends EntryEventMediator{ private static GDataServerRegistry INSTANCE; - private static final Log LOGGER = LogFactory + private static final Log LOG = LogFactory .getLog(GDataServerRegistry.class); private ScopeVisitable requestVisitable; private ScopeVisitable sessionVisitable; - //not available yet + + // not available yet private ScopeVisitable contextVisitable; private List visitorBuffer = new ArrayList(5); @@ -78,7 +80,7 @@ } /** - * @return a Sinleton registry instance + * @return a Singleton registry instance */ public static synchronized GDataServerRegistry getRegistry() { if (INSTANCE == null) @@ -94,7 +96,7 @@ */ public void registerService(ProvidedService configurator) { if (configurator == null) { - LOGGER.warn("Feedconfigurator is null -- skip registration"); + LOG.warn("Feed configurator is null -- skip registration"); return; } this.serviceTypeMap.put(configurator.getName(), configurator); @@ -112,8 +114,8 @@ Scope scope = visitor.getClass().getAnnotation(Scope.class); if (scope == null) throw new RegistryException("Visitor has not Scope"); - if (LOGGER.isInfoEnabled()) - LOGGER.info("Register scope visitor -- " + visitor.getClass()); + if (LOG.isInfoEnabled()) + LOG.info("Register scope visitor -- " + visitor.getClass()); if (scope.scope().equals(Scope.ScopeType.REQUEST) && this.requestVisitable != null) this.requestVisitable.accept(visitor); @@ -141,8 +143,8 @@ Scope scope = visitable.getClass().getAnnotation(Scope.class); if (scope == null) throw new RegistryException("Visitable has not Scope"); - if (LOGGER.isInfoEnabled()) - LOGGER.info("Register scope visitable -- " + visitable.getClass()); + if (LOG.isInfoEnabled()) + LOG.info("Register scope visitable -- " + visitable.getClass()); if (scope.scope() == Scope.ScopeType.REQUEST && this.requestVisitable == null) this.requestVisitable = visitable; @@ -176,7 +178,7 @@ public ProvidedService getProvidedService(String service) { if (service == null) throw new IllegalArgumentException( - "Service is null - must not be null to get registered feedtype"); + "Service is null - must not be null to get registered feed type"); return this.serviceTypeMap.get(service); } @@ -267,7 +269,7 @@ * annotations not visible at runtime or not set, if the super * type provided by the {@link ComponentType} for the class to * register is not a super type of the class or if the - * invokation of the {@link ServerComponent#initialize()} method + * invocation of the {@link ServerComponent#initialize()} method * throws an exception. */ @SuppressWarnings("unchecked") @@ -280,7 +282,8 @@ throw new IllegalArgumentException( "component class must not be null"); - if (!checkSuperType(componentClass, ServerComponent.class)) + if (!ReflectionUtils.implementsType(componentClass, + ServerComponent.class)) throw new RegistryException( "can not register component. the given class does not implement ServerComponent interface -- " + componentClass.getName()); @@ -298,14 +301,14 @@ + type.name()); Class superType = type.getClass().getField(type.name()) .getAnnotation(SuperType.class).superType(); - if (!checkSuperType(componentClass, superType)) - throw new RegistryException("Considered Supertype <" + if (!ReflectionUtils.isTypeOf(componentClass, superType)) + throw new RegistryException("Considered super type <" + superType.getName() + "> is not a super type of <" + componentClass + ">"); ServerComponent comp = componentClass.newInstance(); if (configuration == null) { - if (LOGGER.isInfoEnabled()) - LOGGER.info("no configuration for ComponentType: " + if (LOG.isInfoEnabled()) + LOG.info("no configuration for ComponentType: " + type.name()); } else configureComponent(comp, type, configuration); @@ -313,7 +316,8 @@ ComponentBean bean = new ComponentBean(comp, superType); this.componentMap.put(type, bean); - if (checkSuperType(componentClass, ScopeVisitor.class)) + if (ReflectionUtils.implementsType(componentClass, + ScopeVisitor.class)) this.registerScopeVisitor((ScopeVisitor) comp); } catch (Exception e) { e.printStackTrace(); @@ -334,21 +338,6 @@ injector.injectProperties(configuration); } - private static boolean checkSuperType(Class type, Class consideredSuperType) { - if (type == null) - return false; - if (type.equals(Object.class)) - return false; - if (type.equals(consideredSuperType)) - return true; - Class[] interfaces = type.getInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - if (checkSuperType(interfaces[i], consideredSuperType)) - return true; - } - return checkSuperType(type.getSuperclass(), consideredSuperType); - } - private static class ComponentBean { private final Class superType; @@ -369,4 +358,21 @@ } + /** + * @see org.apache.lucene.gdata.server.registry.EntryEventMediator#getEntryEventMediator() + */ + @Override + public EntryEventMediator getEntryEventMediator() { + + return this; + } + + /** + * @return - all registered services + */ + public Collection getServices() { + + return this.serviceTypeMap.values(); + } + } Index: gdata-server/src/java/org/apache/lucene/gdata/server/registry/ComponentType.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/registry/ComponentType.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/registry/ComponentType.java (working copy) @@ -1,12 +1,13 @@ package org.apache.lucene.gdata.server.registry; +import org.apache.lucene.gdata.search.SearchComponent; import org.apache.lucene.gdata.server.ServiceFactory; import org.apache.lucene.gdata.server.authentication.AuthenticationController; import org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory; import org.apache.lucene.gdata.storage.StorageController; /** - * The enmueration {@link ComponentType} defines the GDATA-Server Components + * The enumeration {@link ComponentType} defines the GDATA-Server Components * available via {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry#lookup(Class, ComponentType)} * method. * @see org.apache.lucene.gdata.server.registry.Component @@ -30,12 +31,11 @@ @SuperType(superType = RequestHandlerFactory.class) REQUESTHANDLERFACTORY, /** - * INDEXER TYPE - * + * SearchComponent Type + * @see SearchComponent */ - // TODO not available yet - @SuperType(superType = Object.class) - INDEXER, + @SuperType(superType = SearchComponent.class) + SEARCHCONTROLLER, /** * ServiceFactory Type * @@ -44,7 +44,7 @@ @SuperType(superType = ServiceFactory.class) SERVICEFACTORY, /** - * Supertype for AuthenticationController implementations + * Super type for AuthenticationController implementations * @see AuthenticationController */ @SuperType(superType = AuthenticationController.class) Index: gdata-server/src/java/org/apache/lucene/gdata/server/registry/EntryEventListener.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/registry/EntryEventListener.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/server/registry/EntryEventListener.java (revision 0) @@ -0,0 +1,48 @@ +/** + * 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.server.registry; + +import org.apache.lucene.gdata.data.ServerBaseEntry; + +/** + * The EntryEventListener interface should be implemented by any class needs to be informed about any changes on entries. + * To register a class as a EntryEventListener use: + *

+ * + * GdataServerRegistry.registerEntryEventListener(EntryEventListener); + * + *

+ * @author Simon Willnauer + * + */ +public interface EntryEventListener { + /** + * will be invoked on every successful update on every entry + * @param entry the updated entry + */ + public abstract void fireUpdateEvent(ServerBaseEntry entry); + /** + * will be invoked on every successful entry insert + * @param entry + */ + public abstract void fireInsertEvent(ServerBaseEntry entry); + /** + * will be invoked on every successful entry delete + * @param entry + */ + public abstract void fireDeleteEvent(ServerBaseEntry entry); +} Index: gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryBuilder.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryBuilder.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryBuilder.java (working copy) @@ -18,14 +18,17 @@ import java.io.IOException; import org.apache.commons.digester.Digester; +import org.apache.lucene.gdata.search.config.IndexSchema; +import org.apache.lucene.gdata.search.config.IndexSchemaField; import org.apache.lucene.gdata.server.registry.configuration.ComponentConfiguration; import org.apache.lucene.gdata.utils.SimpleSaxErrorHandler; +import org.apache.xerces.parsers.SAXParser; import org.xml.sax.SAXException; /** * Reads the configuration file and creates the * {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry} singleton - * instance. All services and components will be instanciated and registered in + * instance. All services and components will be instantiated and registered in * the registry. * * @author Simon Willnauer @@ -38,22 +41,30 @@ * {@link GDataServerRegistry#getRegistry()} method * * @throws IOException - - * if an IOException occures while reading the config file + * if an IOException occurs while reading the config file * @throws SAXException - * if the config file can not be parsed */ static void buildRegistry() throws IOException, SAXException { + String schemaFile = RegistryBuilder.class.getResource("/gdata-config.xsd").getFile(); + /* + * Force using apache xerces parser for digester + */ + SAXParser parser = new SAXParser(); + parser.setFeature("http://apache.org/xml/features/validation/schema-full-checking",true); + parser.setFeature("http://apache.org/xml/features/validation/schema",true); + parser.setFeature("http://xml.org/sax/features/validation",true); + parser.setProperty("http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",schemaFile); + Digester digester = new Digester(parser); + buildFromConfiguration(digester, GDataServerRegistry + .getRegistry(),schemaFile); - buildFromConfiguration(new Digester(), GDataServerRegistry - .getRegistry()); - } private static void buildFromConfiguration(Digester digester, - GDataServerRegistry registry) throws IOException, SAXException { - String schemaFile = RegistryBuilder.class.getResource("/gdata-config.xsd").getFile(); + GDataServerRegistry registry, String schemaURL) throws IOException, SAXException { digester.setValidating(true); - digester.setSchema(schemaFile); + digester.setSchema(schemaURL); digester.setErrorHandler(new SimpleSaxErrorHandler()); digester.push(registry); /* @@ -66,7 +77,7 @@ digester.addBeanPropertySetter("gdata/service/entry-class", "entryType"); digester.addBeanPropertySetter("gdata/service/extension-profile", "extensionProfileClass"); - + addIndexRule(digester); /* * load components and configurations */ @@ -77,11 +88,66 @@ digester.addCallMethod("gdata/server-components/component/configuration/property","set",2,new Class[]{String.class,String.class}); digester.addCallParam("gdata/server-components/component/configuration/property",0,"name"); digester.addCallParam("gdata/server-components/component/configuration/property",1); + //second parameter on registerComponent -- top of the stack (Component configuration) digester.addCallParam("gdata/server-components/component/configuration",1,0); digester.parse(RegistryBuilder.class .getResourceAsStream("/gdata-config.xml")); } + + + private static void addIndexRule(Digester digester){ + digester.addObjectCreate("gdata/service/index-schema", IndexSchema.class); + digester.addSetNext("gdata/service/index-schema", "setIndexSchema"); + digester.addSetProperties("gdata/service/index-schema"); + digester.addSetProperties("gdata/service/index-schema/index"); + digester.addBeanPropertySetter("gdata/service/index-schema/index/maxMergeDocs"); + digester.addBeanPropertySetter("gdata/service/index-schema/index/maxBufferedDocs"); + digester.addBeanPropertySetter("gdata/service/index-schema/index/maxFieldLength"); + digester.addBeanPropertySetter("gdata/service/index-schema/index/mergeFactor"); + digester.addBeanPropertySetter("gdata/service/index-schema/index/indexLocation"); + digester.addBeanPropertySetter("gdata/service/index-schema/index/useCompoundFile"); + digester.addCallMethod("gdata/service/index-schema/index/defaultAnalyzer", "serviceAnalyzer",1,new Class[]{Class.class}); + + //call method on top of the stack addSchemaField + digester.addCallMethod("gdata/service/index-schema/field","addSchemaField",1,new Class[]{IndexSchemaField.class}); + digester.addObjectCreate("gdata/service/index-schema/field",IndexSchemaField.class); + //set parameter for method call -- parameter is IndexSchemaField + digester.addCallParam("gdata/service/index-schema/field",0,0); + digester.addSetProperties("gdata/service/index-schema/field"); + digester.addBeanPropertySetter("gdata/service/index-schema/field/path"); + digester.addBeanPropertySetter("gdata/service/index-schema/field/store","storeByName"); + digester.addBeanPropertySetter("gdata/service/index-schema/field/index","indexByName"); + digester.addBeanPropertySetter("gdata/service/index-schema/field/analyzer","analyzerClass"); + +// call method on top of the stack addSchemaField + digester.addCallMethod("gdata/service/index-schema/custom","addSchemaField",1,new Class[]{IndexSchemaField.class}); + digester.addObjectCreate("gdata/service/index-schema/custom",IndexSchemaField.class); + //set parameter for method call -- parameter is IndexSchemaField + digester.addCallParam("gdata/service/index-schema/custom",0,0); + digester.addSetProperties("gdata/service/index-schema/custom"); + digester.addBeanPropertySetter("gdata/service/index-schema/custom/path"); + digester.addBeanPropertySetter("gdata/service/index-schema/custom/store","storeByName"); + digester.addBeanPropertySetter("gdata/service/index-schema/custom/index","indexByName"); + digester.addBeanPropertySetter("gdata/service/index-schema/custom/analyzer","analyzerClass"); + digester.addBeanPropertySetter("gdata/service/index-schema/custom/field-class","fieldClass"); +// digester.addCallMethod("gdata/service/index-schema/custom/field-class","fieldClass",1,new Class[]{Class.class}); + + +// call method on top of the stack addSchemaField + digester.addCallMethod("gdata/service/index-schema/mixed","addSchemaField",1,new Class[]{IndexSchemaField.class}); + digester.addObjectCreate("gdata/service/index-schema/mixed",IndexSchemaField.class); + //set parameter for method call -- parameter is IndexSchemaField + digester.addCallParam("gdata/service/index-schema/mixed",0,0); + digester.addSetProperties("gdata/service/index-schema/mixed"); + digester.addBeanPropertySetter("gdata/service/index-schema/mixed","type"); + digester.addBeanPropertySetter("gdata/service/index-schema/mixed/path"); + digester.addBeanPropertySetter("gdata/service/index-schema/mixed/store","storeByName"); + digester.addBeanPropertySetter("gdata/service/index-schema/mixed/index","indexByName"); + digester.addBeanPropertySetter("gdata/service/index-schema/mixed/contenttype","typePath"); + digester.addBeanPropertySetter("gdata/service/index-schema/mixed/analyzer","analyzerClass"); + + } } Index: gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryContextListener.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryContextListener.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryContextListener.java (working copy) @@ -27,7 +27,7 @@ * {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry} when the * context is loaded. The registry will be loaded before the * {@link org.apache.lucene.gdata.servlet.RequestControllerServlet} is loaded. - * The Registry will be loaded and set up befor the REST interface is available. + * The Registry will be loaded and set up before the REST interface is available. *

* This ContextListener has to be configured in the web.xml * deployment descriptor. @@ -58,9 +58,13 @@ try { RegistryBuilder.buildRegistry(); this.serverRegistry = GDataServerRegistry.getRegistry(); - } catch (Exception e) { - this.serverRegistry.destroy(); - LOG.error("can not register requiered components", e); + /* + * catch all exceptions and destroy the registry to release all resources. + * some components start lots of threads, the will remain running if the registry is not destroyed + */ + } catch (Throwable e) { + GDataServerRegistry.getRegistry().destroy(); + LOG.error("can not register required components", e); throw new RuntimeException("Can not register required components", e); } @@ -73,7 +77,12 @@ */ public void contextDestroyed(ServletContextEvent arg0) { LOG.info("Destroying context"); - this.serverRegistry.destroy(); + /* + * this might be null if startup fails + * --> prevent null pointer exception + */ + if(this.serverRegistry != null) + this.serverRegistry.destroy(); } Index: gdata-server/src/java/org/apache/lucene/gdata/server/registry/ProvidedServiceConfig.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/registry/ProvidedServiceConfig.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/registry/ProvidedServiceConfig.java (working copy) @@ -19,6 +19,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.lucene.gdata.search.config.IndexSchema; import org.apache.lucene.gdata.utils.Pool; import org.apache.lucene.gdata.utils.PoolObjectFactory; import org.apache.lucene.gdata.utils.SimpleObjectPool; @@ -26,13 +27,13 @@ import com.google.gdata.data.ExtensionProfile; /** - * Standart implementation of + * Standard implementation of * {@link org.apache.lucene.gdata.server.registry.ProvidedService} to be used * inside the * {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry} *

* ExtensionProfiles are used to generate and parse xml by the gdata api. For - * that case all methodes are synchronized. This will slow down the application + * that case all methods are synchronized. This will slow down the application * when performing lots of xml generation concurrently. For that case the * extensionProfile for a specific service will be pooled and reused. *

@@ -47,9 +48,9 @@ .getLog(ProvidedServiceConfig.class); private static final int DEFAULT_POOL_SIZE = 5; - + private IndexSchema indexSchema; /* - * To ensure a extensionprofile instance will not be shared within multiple + * To ensure a extension profile instance will not be shared within multiple * threads each thread requesting a config will have one instance for the * entire request. */ @@ -92,7 +93,7 @@ } /** - * Default constructor to instanciate via reflection + * Default constructor to instantiate via reflection */ public ProvidedServiceConfig() { try { @@ -126,6 +127,8 @@ if (ext != null) { return ext; } + if(this.extensionProfile == null) + return null; if (this.profilPool == null) createProfilePool(); ext = this.profilPool.aquire(); @@ -135,7 +138,7 @@ /** * @param extensionProfil - - * the extensionprofile for this feed configuration + * the extension profile for this feed configuration */ @SuppressWarnings("unchecked") public void setExtensionProfile(ExtensionProfile extensionProfil) { @@ -150,7 +153,7 @@ private void createProfilePool() { if (LOG.isInfoEnabled()) - LOG.info("Create ExtensionProfile pool with poolsize:" + LOG.info("Create ExtensionProfile pool with pool size:" + this.poolSize + " for service " + this.serviceName); this.profilPool = new SimpleObjectPool(this.poolSize, new ExtensionProfileFactory( @@ -232,7 +235,7 @@ this.constructor = clazz.getConstructor(new Class[0]); } catch (Exception e) { throw new IllegalArgumentException( - "The given class has no defaul constructor -- can not use as a ExtensionProfile -- " + "The given class has no default constructor -- can not use as a ExtensionProfile -- " + this.clazz.getName(), e); } } @@ -247,7 +250,7 @@ return (Type) this.constructor.newInstance(constArray); } catch (Exception e) { throw new RuntimeException( - "Can not instanciate new ExtensionProfile -- ", e); + "Can not instantiate new ExtensionProfile -- ", e); } } @@ -271,7 +274,7 @@ createProfilePool(); /* * don't set a extension profile for each thread. The current thread - * might use another service and does not need the extensionprofile of + * might use another service and does not need the extension profile of * this service */ } @@ -295,4 +298,20 @@ this.profilPool.release(ext); } + /** + * @return Returns the indexSchema. + */ + public IndexSchema getIndexSchema() { + return this.indexSchema; + } + + /** + * @param indexSchema The indexSchema to set. + */ + public void setIndexSchema(IndexSchema indexSchema) { + this.indexSchema = indexSchema; + if(this.indexSchema != null) + this.indexSchema.setName(this.serviceName); + } + } Index: gdata-server/src/java/org/apache/lucene/gdata/server/registry/configuration/PropertyInjector.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/registry/configuration/PropertyInjector.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/registry/configuration/PropertyInjector.java (working copy) @@ -19,14 +19,15 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; -import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.Map.Entry; +import org.apache.lucene.gdata.utils.ReflectionUtils; + /** * PropertyInjector is used to set member variables / properties of classes via - * setter methodes using the + * setter methods using the * {@link org.apache.lucene.gdata.server.registry.configuration.ComponentConfiguration} * class. *

@@ -34,8 +35,8 @@ * the class or a superclass of the object to populate has to provide at least * one setter method with a single parameter. The object to populate is set via * the {@link PropertyInjector#setTargetObject} method. The class of the object - * will be analyzed for setter methodes having a "set" prefix in their method - * name. If one of the found setter methodes is annotated with + * will be analyzed for setter methods having a "set" prefix in their method + * name. If one of the found setter methods is annotated with * {@link org.apache.lucene.gdata.server.registry.configuration.Requiered} this * property is interpreted as a mandatory property. Mandatory properties must be * available in the provided ComponentConfiguration, if not the injection will @@ -46,14 +47,14 @@ * setter method without the 'set' prefix and must begin with a lower case * character. KeybufferSize does match a method signature * of setBufferSize The type of the parameter will be - * reflected via the Reflection API and instanciated with the given value if + * reflected via the Reflection API and instantiated with the given value if * possible. *

*

- * Setter methodes without a Requiered anntoation will be set if + * Setter methods without a Required annotation will be set if * the property is present in the ComponentConfiguration *

- *

This class does not support overloaded setter methodes.

+ *

This class does not support overloaded setter methods.

* @author Simon Willnauer * @see org.apache.lucene.gdata.server.registry.configuration.Requiered * @see org.apache.lucene.gdata.server.registry.configuration.ComponentConfiguration @@ -88,7 +89,7 @@ if (this.requieredProperties.isEmpty() && this.optionalProperties.isEmpty()) throw new InjectionException( - "Given type has no public setter methodes -- " + "Given type has no public setter methods -- " + o.getClass().getName()); } @@ -132,7 +133,7 @@ /** * Injects the properties stored in the ComponentConfiguration - * to the corresponding methodes of the target object + * to the corresponding methods of the target object * @param bean - configuration bean containing all properties to set. * */ @@ -143,11 +144,11 @@ throw new IllegalStateException("target is not set -- null"); Set> requiered = this.requieredProperties .entrySet(); - // set requiered properties + // set required properties for (Entry entry : requiered) { if (!bean.contains(entry.getKey())) throw new InjectionException( - "requiered property can not be set -- value not in configuration bean; Property: " + "Required property can not be set -- value not in configuration bean; Property: " + entry.getKey() + "for class " + this.targetClass.getName()); @@ -196,12 +197,12 @@ private Object createObject(String s, Class clazz) { try { - // if class is requested use s as fully qualified classname + // if class is requested use s as fully qualified class name if (clazz == Class.class) return Class.forName(s); // check for primitive type if (clazz.isPrimitive()) - clazz = getPrimitiveWrapper(clazz); + clazz = ReflectionUtils.getPrimitiveWrapper(clazz); boolean defaultConst = false; boolean stringConst = false; Constructor[] constructors = clazz.getConstructors(); @@ -226,8 +227,8 @@ return constructor.newInstance(new Object[] { s }); } /* - * if no string const. but a default const -- use the string as a - * classname + * if no string const. but a default const. -- use the string as a + * class name */ if (defaultConst) return Class.forName(s).newInstance(); @@ -255,28 +256,6 @@ this.requieredProperties.clear(); } - /* - * return the wrappertype for the given primitive type. Wrappers can be - * easily instanciated via reflection and will be boxed by the vm - */ - private static final Class getPrimitiveWrapper(Class primitive) { + - if (primitive == Integer.TYPE) - return Integer.class; - if (primitive == Float.TYPE) - return Float.class; - if (primitive == Long.TYPE) - return Long.class; - if (primitive == Short.TYPE) - return Short.class; - if (primitive == Byte.TYPE) - return Byte.class; - if (primitive == Double.TYPE) - return Double.class; - if (primitive == Boolean.TYPE) - return Boolean.class; - - return primitive; - } - } Index: gdata-server/src/java/org/apache/lucene/gdata/server/registry/configuration/ComponentConfiguration.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/registry/configuration/ComponentConfiguration.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/registry/configuration/ComponentConfiguration.java (working copy) @@ -21,7 +21,7 @@ /** * Simple configuration class storing properties as key with defined property - * values as values in a Map. As amap cannot + * values as values in a Map. As a map cannot * contain duplicate keys the first use of a key can not be replaced. If a key * is used twice a {@link java.lang.IllegalArgumentException} will be thrown. * @see Map Index: gdata-server/src/java/org/apache/lucene/gdata/server/registry/EntryEventMediator.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/registry/EntryEventMediator.java (revision 0) +++ gdata-server/src/java/org/apache/lucene/gdata/server/registry/EntryEventMediator.java (revision 0) @@ -0,0 +1,89 @@ +/** + * 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.server.registry; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.lucene.gdata.data.ServerBaseEntry; + +/** + * This class will be informed about every successful entry event and + * distributes all event to all registered + * {@link org.apache.lucene.gdata.server.registry.EntryEventListener} + * + * @author Simon Willnauer + * + */ +public abstract class EntryEventMediator { + + private final List entryEventListener = new ArrayList( + 5); + + /** + * @return - a entry event mediator instance + */ + public abstract EntryEventMediator getEntryEventMediator(); + + /** + * Registers a {@link EntryEventListener}. This listner will be fired if an + * entry update, insert or delete occures + * + * @param listener - + * listener to register + */ + public void registerEntryEventListener(final EntryEventListener listener) { + if (listener == null || this.entryEventListener.contains(listener)) + return; + this.entryEventListener.add(listener); + } + + /** + * @param entry - + * the updated entry + */ + public void entryUpdated(final ServerBaseEntry entry) { + for (EntryEventListener listener : this.entryEventListener) { + listener.fireUpdateEvent(entry); + } + } + + /** + * @param entry - + * the added entry + */ + public void entryAdded(final ServerBaseEntry entry) { + for (EntryEventListener listener : this.entryEventListener) { + listener.fireInsertEvent(entry); + } + } + + /** + * @param entry - + * the deleted entry + */ + public void entryDeleted(final ServerBaseEntry entry) { + for (EntryEventListener listener : this.entryEventListener) { + listener.fireDeleteEvent(entry); + } + } + + public boolean isListenerRegistered(final EntryEventListener listner){ + return listner!=null&&this.entryEventListener.contains(listner); + } + +} Index: gdata-server/src/java/org/apache/lucene/gdata/server/registry/ServerComponent.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/registry/ServerComponent.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/registry/ServerComponent.java (working copy) @@ -32,6 +32,7 @@ public interface ServerComponent { /** * will be call when the component is registered. + * if this fails the server must not startup. */ public abstract void initialize(); Index: gdata-server/src/java/org/apache/lucene/gdata/server/registry/ProvidedService.java =================================================================== --- gdata-server/src/java/org/apache/lucene/gdata/server/registry/ProvidedService.java (revision 426779) +++ gdata-server/src/java/org/apache/lucene/gdata/server/registry/ProvidedService.java (working copy) @@ -15,6 +15,8 @@ */ package org.apache.lucene.gdata.server.registry; +import org.apache.lucene.gdata.search.config.IndexSchema; + import com.google.gdata.data.ExtensionProfile; /** @@ -41,7 +43,7 @@ public abstract Class getEntryType(); /** - * @return - the servicename + * @return - the service name */ public abstract String getName(); @@ -49,5 +51,8 @@ * releases all dependencies and resources */ public abstract void destroy(); - + /** + * @return the index schema configuration for this service + */ + public abstract IndexSchema getIndexSchema(); } \ No newline at end of file Index: gdata-server/build.xml =================================================================== --- gdata-server/build.xml (revision 426779) +++ gdata-server/build.xml (working copy) @@ -25,6 +25,8 @@ + + @@ -74,6 +76,8 @@ + +