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 @@
";
+ 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 extends Node, ? extends ServerBaseEntry>)'
+ */
+ 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 extends Node, ? extends ServerBaseEntry> 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(Futuretrue 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 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 @@
*
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 @@ * ** 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 extends Node, ? extends ServerBaseEntry> 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+ * 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 extends Node, ? extends ServerBaseEntry> 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
+ * 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.
+ *
+ * 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.
+ * 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.
+ *
- * 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.
* 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
+ * Default values:
+ *
+ *
+ */
+ public IndexSchemaField() {
+ super();
+ }
+ boolean checkRequieredValues(){
+ /*
+ * This class will be inst. by the reg builder.
+ * Check all values to be set. otherwise return false.
+ * false will cause a runtime exception in IndexSchema
+ */
+ boolean returnValue = (this.name != null&&this.path!=null&&this.contentType!=null&&this.index!=null&&this.store!=null&&this.boost>=MINIMAL_BOOST);
+ if(this.contentType == ContentType.CUSTOM)
+ returnValue &=this.fieldClass!=null;
+ else if(this.contentType == ContentType.MIXED)
+ returnValue &=this.typePath!=null;
+
+ return returnValue;
+ }
+ /**
+ * @return Returns the alanyzerClass.
+ */
+ public Class extends Analyzer> getAnalyzerClass() {
+ return this.analyzerClass;
+ }
+
+ /**
+ * @param alanyzerClass
+ * The alanyzerClass to set.
+ */
+ public void setAnalyzerClass(Class extends Analyzer> alanyzerClass) {
+ this.analyzerClass = alanyzerClass;
+ }
+
+ /**
+ * @return Returns the fieldClass.
+ */
+ public Class
+ * 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.
+ * 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.Entrytrue 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 Futurecreate 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.
+ * 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 Collectiontrue 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
- *
*
@@ -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
+ *
+ * GdataServerRegistry.registerEntryEventListener(EntryEventListener);
+ *
+ *
* This ContextListener has to be configured in the
* 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.
*
@@ -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. Key
- * Setter methodes without a This class does not support overloaded setter methodes. This class does not support overloaded setter methods.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}
* bufferSize 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.
* Requiered anntoation will be set if
+ * Setter methods without a Required annotation will be set if
* the property is present in the ComponentConfiguration
* 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");
SetMap. 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