Index: trunk/build.xml
===================================================================
--- trunk/build.xml (revision 412202)
+++ trunk/build.xml (working copy)
@@ -379,6 +379,7 @@
+
@@ -386,7 +387,7 @@
-
+
Index: trunk/contrib/gdata-server/webroot/WEB-INF/web.xml
===================================================================
--- trunk/contrib/gdata-server/webroot/WEB-INF/web.xml (revision 0)
+++ trunk/contrib/gdata-server/webroot/WEB-INF/web.xml (revision 0)
@@ -0,0 +1,24 @@
+
+
+ Lucene GData - Server
+
+ Server-side implementation of the GData protocol based on Apache
+ - Lucene
+
+
+ org.apache.lucene.gdata.server.registry.RegistryContextListener
+
+
+ ControllerServlet
+
+ org.apache.lucene.gdata.servlet.RequestControllerServlet
+
+
+
+ ControllerServlet
+ /*
+
+
\ No newline at end of file
Index: trunk/contrib/gdata-server/webroot/WEB-INF/classes/lucenestorage.properties.xml
===================================================================
--- trunk/contrib/gdata-server/webroot/WEB-INF/classes/lucenestorage.properties.xml (revision 0)
+++ trunk/contrib/gdata-server/webroot/WEB-INF/classes/lucenestorage.properties.xml (revision 0)
@@ -0,0 +1,11 @@
+
+
+
+Lucene Storage Properties
+20
+20
+20
+/tmp/storage/
+true
+false
+
\ No newline at end of file
Index: trunk/contrib/gdata-server/lib/gdata-client-1.0.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/contrib/gdata-server/lib/gdata-client-1.0.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Index: trunk/contrib/gdata-server/lib/easymock.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/contrib/gdata-server/lib/easymock.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Index: trunk/contrib/gdata-server/lib/servlet-api.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/contrib/gdata-server/lib/servlet-api.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Index: trunk/contrib/gdata-server/lib/commons-logging-1.1.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/contrib/gdata-server/lib/commons-logging-1.1.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Index: trunk/contrib/gdata-server/lib/log4j-1.2.13.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/contrib/gdata-server/lib/log4j-1.2.13.jar
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Index: trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/servlet/TestAbstractGdataServlet.java
===================================================================
--- trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/servlet/TestAbstractGdataServlet.java (revision 0)
+++ trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/servlet/TestAbstractGdataServlet.java (revision 0)
@@ -0,0 +1,282 @@
+package org.apache.lucene.gdata.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.easymock.MockControl;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public class TestAbstractGdataServlet extends TestCase {
+ private static final String METHOD_DELETE = "DELETE";
+
+ private static final String METHOD_GET = "GET";
+
+ private static final String METHOD_POST = "POST";
+
+ private static final String METHOD_PUT = "PUT";
+
+ private static final String METHOD_HEADER_NAME = "x-http-method-override";
+
+ private HttpServletRequest mockRequest = null;
+
+ private HttpServletResponse mockResponse = null;
+
+ private AbstractGdataServlet servletInstance = null;
+
+ private MockControl requestMockControl;
+
+ private MockControl responseMockControl;
+
+ protected void setUp() throws Exception {
+ this.requestMockControl = MockControl
+ .createControl(HttpServletRequest.class);
+ this.responseMockControl = MockControl
+ .createControl(HttpServletResponse.class);
+ this.mockRequest = (HttpServletRequest) this.requestMockControl
+ .getMock();
+ this.mockResponse = (HttpServletResponse) this.responseMockControl
+ .getMock();
+ this.servletInstance = new StubGDataServlet();
+ }
+
+ /**
+ * Test method for
+ * 'org.apache.lucene.gdata.servlet.AbstractGdataServlet.service(HttpServletRequest,
+ * HttpServletResponse)'
+ */
+ public void testServiceHttpServletRequestHttpServletResponseDelete() {
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getMethod(), METHOD_DELETE);
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getHeader(METHOD_HEADER_NAME), METHOD_DELETE);
+ this.requestMockControl.replay();
+
+ try {
+ this.servletInstance.service(this.mockRequest, this.mockResponse);
+ } catch (ServletException e) {
+ fail("ServeltExpception not expected");
+ } catch (IOException e) {
+ fail("IOExpception not expected");
+ }
+
+ this.requestMockControl.verify();
+ this.requestMockControl.reset();
+
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getMethod(), METHOD_POST);
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getHeader(METHOD_HEADER_NAME), METHOD_DELETE);
+ this.requestMockControl.replay();
+
+ try {
+ this.servletInstance.service(this.mockRequest, this.mockResponse);
+ } catch (ServletException e) {
+ fail("ServeltExpception not expected");
+ } catch (IOException e) {
+ fail("IOExpception not expected");
+ }
+
+ this.requestMockControl.verify();
+ }
+
+ /**
+ *
+ */
+ public void testServiceNullOverrideHeader() {
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getMethod(), METHOD_POST);
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getHeader(METHOD_HEADER_NAME), null);
+ this.requestMockControl.replay();
+
+ try {
+ this.servletInstance.service(this.mockRequest, this.mockResponse);
+ } catch (ServletException e) {
+ fail("ServeltExpception not expected");
+ } catch (IOException e) {
+ fail("IOExpception not expected");
+ }
+
+ this.requestMockControl.verify();
+ this.requestMockControl.reset();
+ }
+
+ /**
+ * Test method for
+ * 'org.apache.lucene.gdata.servlet.AbstractGdataServlet.service(HttpServletRequest,
+ * HttpServletResponse)'
+ */
+ public void testServiceHttpServletRequestHttpServletResponsePOST() {
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getMethod(), METHOD_POST);
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getHeader(METHOD_HEADER_NAME), METHOD_POST);
+ this.requestMockControl.replay();
+
+ try {
+ this.servletInstance.service(this.mockRequest, this.mockResponse);
+ } catch (ServletException e) {
+ fail("ServeltExpception not expected");
+ } catch (IOException e) {
+ fail("IOExpception not expected");
+ }
+
+ this.requestMockControl.verify();
+ this.requestMockControl.reset();
+
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getMethod(), METHOD_PUT);
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getHeader(METHOD_HEADER_NAME), METHOD_POST);
+ this.requestMockControl.replay();
+
+ try {
+ this.servletInstance.service(this.mockRequest, this.mockResponse);
+ } catch (ServletException e) {
+ fail("ServeltExpception not expected");
+ } catch (IOException e) {
+ fail("IOExpception not expected");
+ }
+
+ this.requestMockControl.verify();
+ }
+
+ /**
+ * Test method for
+ * 'org.apache.lucene.gdata.servlet.AbstractGdataServlet.service(HttpServletRequest,
+ * HttpServletResponse)'
+ */
+ public void testServiceHttpServletRequestHttpServletResponsePUT() {
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getMethod(), METHOD_PUT);
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getHeader(METHOD_HEADER_NAME), METHOD_PUT);
+ this.requestMockControl.replay();
+
+ try {
+ this.servletInstance.service(this.mockRequest, this.mockResponse);
+ } catch (ServletException e) {
+ fail("ServeltExpception not expected");
+ } catch (IOException e) {
+ fail("IOExpception not expected");
+ }
+
+ this.requestMockControl.verify();
+ this.requestMockControl.reset();
+
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getMethod(), METHOD_POST);
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getHeader(METHOD_HEADER_NAME), METHOD_PUT);
+ this.requestMockControl.replay();
+
+ try {
+ this.servletInstance.service(this.mockRequest, this.mockResponse);
+ } catch (ServletException e) {
+ fail("ServeltExpception not expected");
+ } catch (IOException e) {
+ fail("IOExpception not expected");
+ }
+
+ this.requestMockControl.verify();
+ }
+
+ /**
+ * Test method for
+ * 'org.apache.lucene.gdata.servlet.AbstractGdataServlet.service(HttpServletRequest,
+ * HttpServletResponse)'
+ */
+ public void testServiceHttpServletRequestHttpServletResponseGET() {
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getMethod(), METHOD_GET);
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getHeader(METHOD_HEADER_NAME), METHOD_GET);
+ this.requestMockControl.replay();
+
+ try {
+ this.servletInstance.service(this.mockRequest, this.mockResponse);
+ } catch (ServletException e) {
+ fail("ServeltExpception not expected");
+ } catch (IOException e) {
+ fail("IOExpception not expected");
+ }
+
+ this.requestMockControl.verify();
+ this.requestMockControl.reset();
+
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getMethod(), METHOD_POST);
+ this.requestMockControl.expectAndDefaultReturn(this.mockRequest
+ .getHeader(METHOD_HEADER_NAME), METHOD_GET);
+ this.requestMockControl.replay();
+
+ try {
+ this.servletInstance.service(this.mockRequest, this.mockResponse);
+ } catch (ServletException e) {
+ fail("ServeltExpception not expected");
+ } catch (IOException e) {
+ fail("IOExpception not expected");
+ }
+
+ this.requestMockControl.verify();
+
+ }
+ /**
+ * Stub Implementation for AbstractGdataServlet
+ * @author Simon Willnauer
+ *
+ */
+ static class StubGDataServlet extends AbstractGdataServlet {
+
+ private static final long serialVersionUID = -6271464588547620925L;
+
+ protected void doDelete(HttpServletRequest arg0,
+ HttpServletResponse arg1) {
+ if (arg0.getHeader(METHOD_HEADER_NAME) == null)
+ assertEquals("Http-Method --DELETE--", METHOD_DELETE, arg0
+ .getMethod());
+ else
+ assertEquals("Http-Method override --DELETE--", METHOD_DELETE,
+ arg0.getHeader(METHOD_HEADER_NAME));
+
+ }
+
+ protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1) {
+ if (arg0.getHeader(METHOD_HEADER_NAME) == null)
+ assertEquals("Http-Method --GET--", arg0.getMethod(),
+ METHOD_GET);
+ else
+ assertEquals("Http-Method override --GET--", arg0
+ .getHeader(METHOD_HEADER_NAME), METHOD_GET);
+ }
+
+ protected void doPost(HttpServletRequest arg0, HttpServletResponse arg1) {
+ if (arg0.getHeader(METHOD_HEADER_NAME) == null)
+ assertEquals("Http-Method --POST--", arg0.getMethod(),
+ METHOD_POST);
+ else
+ assertEquals("Http-Method override --POST--", METHOD_POST, arg0
+ .getHeader(METHOD_HEADER_NAME));
+
+ }
+
+ protected void doPut(HttpServletRequest arg0, HttpServletResponse arg1) {
+ if (arg0.getHeader(METHOD_HEADER_NAME) == null)
+ assertEquals("Http-Method --PUT--", arg0.getMethod(),
+ METHOD_PUT);
+ else
+ assertEquals("Http-Method override --PUT--", arg0
+ .getHeader(METHOD_HEADER_NAME), METHOD_PUT);
+ }
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageModifier.java
===================================================================
--- trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageModifier.java (revision 0)
+++ trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageModifier.java (revision 0)
@@ -0,0 +1,247 @@
+package org.apache.lucene.gdata.storage.lucenestorage;
+
+import java.io.IOException;
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.gdata.server.FeedNotFoundException;
+import org.apache.lucene.gdata.server.registry.FeedInstanceConfigurator;
+import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
+import org.apache.lucene.gdata.server.registry.RegistryBuilder;
+import org.apache.lucene.gdata.storage.StorageException;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageModifier;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageQuery;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
+import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Hits;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.RAMDirectory;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.DateTime;
+import com.google.gdata.data.Entry;
+import com.google.gdata.data.ExtensionProfile;
+import com.google.gdata.data.Feed;
+import com.google.gdata.data.PlainTextConstruct;
+import com.google.gdata.data.TextConstruct;
+import com.google.gdata.data.TextContent;
+import com.google.gdata.util.ParseException;
+
+public class TestStorageModifier extends TestCase {
+ private StorageModifier modifier;
+ private int count = 1;
+
+ private ExtensionProfile profile;
+ private Directory dir;
+
+
+ private static String feedId = "myFeed";
+
+ protected void setUp() throws Exception {
+ FeedInstanceConfigurator configurator = new FeedInstanceConfigurator();
+ configurator.setFeedType(Feed.class);
+ configurator.setFeedId(feedId);
+ configurator.setExtensionProfileClass(ExtensionProfile.class);
+ GDataServerRegistry.getRegistry().registerFeed(configurator);
+ dir = new RAMDirectory();
+ this.profile = new ExtensionProfile();
+ IndexWriter writer;
+
+ writer = new IndexWriter(dir,new StandardAnalyzer(),true);
+ writer.close();
+ modifier = StorageCoreController.getStorageCoreController(dir).getStorageModifier();
+
+
+ }
+
+ protected void tearDown() throws Exception {
+ this.count = 1;
+ // destroy all resources
+ GDataServerRegistry.getRegistry().destroy();//TODO remove dependency here
+
+ }
+
+ /*
+ * Test method for
+ * 'org.apache.lucene.storage.lucenestorage.StorageModifier.StorageModifier(Directory,
+ * int)'
+ */
+ public void testStorageModifier() {
+
+ }
+
+ /*
+ * Test method for
+ * 'org.apache.lucene.storage.lucenestorage.StorageModifier.updateEntry(StroageEntryWrapper)'
+ */
+ public void testUpdateEntry() throws IOException, InterruptedException, FeedNotFoundException, ParseException, StorageException {
+ testInsertEntry();
+ for(int i = 1; i < this.count; i++){
+ Entry e = new Entry();
+ e.setId(""+i);
+ String insertString = "Hello world"+i;
+ e.setTitle(new PlainTextConstruct(insertString));
+ StorageEntryWrapper wrapper = new StorageEntryWrapper(e,feedId,StorageOperation.UPDATE,this.profile);
+ this.modifier.updateEntry(wrapper);
+ ReferenceCounter innerQuery = StorageCoreController.getStorageCoreController().getStorageQuery();
+ BaseEntry fetchedEntry = innerQuery.get().singleEntryQuery(""+i,feedId,this.profile);
+ assertEquals("updated Title:",insertString,fetchedEntry.getTitle().getPlainText());
+ }
+ // double updates
+ for(int i = 1; i < this.count; i++){
+ Entry e = new Entry();
+ e.setId(""+i);
+ String insertString = "Hello world"+i;
+ e.setTitle(new PlainTextConstruct(insertString));
+ StorageEntryWrapper wrapper = new StorageEntryWrapper(e,feedId,StorageOperation.UPDATE,this.profile);
+ this.modifier.updateEntry(wrapper);
+
+ e = new Entry();
+ e.setId(""+i);
+ insertString = "Foo Bar"+i;
+ e.setTitle(new PlainTextConstruct(insertString));
+ wrapper = new StorageEntryWrapper(e,feedId,StorageOperation.UPDATE,this.profile);
+ this.modifier.updateEntry(wrapper);
+
+ ReferenceCounter innerQuery = StorageCoreController.getStorageCoreController().getStorageQuery();
+
+ BaseEntry fetchedEntry = innerQuery.get().singleEntryQuery(""+i,feedId,this.profile);
+ assertEquals("updated Title:",insertString,fetchedEntry.getTitle().getPlainText());
+ }
+
+
+
+ }
+
+ /*
+ * Test method for
+ * 'org.apache.lucene.storage.lucenestorage.StorageModifier.insertEntry(StroageEntryWrapper)'
+ */
+ public void testInsertEntry() throws IOException, InterruptedException, FeedNotFoundException, ParseException, StorageException {
+
+ Thread a = getRunnerThread(this.count);
+ a.start();
+
+ Thread b = getRunnerThread((this.count+=10));
+ b.start();
+ a.join();
+ for (int i = 1; i < this.count ; i++) {
+ ReferenceCounter innerQuery = StorageCoreController.getStorageCoreController().getStorageQuery();
+ BaseEntry e = innerQuery.get().singleEntryQuery(""+i,feedId,this.profile);
+ assertEquals("get entry for id"+i,""+i,e.getId());
+
+
+ }
+ b.join();
+ ReferenceCounter query = StorageCoreController.getStorageCoreController().getStorageQuery();
+
+ this.count+=10;
+ for (int i = 1; i < this.count ; i++) {
+ BaseEntry e = query.get().singleEntryQuery(""+i,feedId,this.profile);
+ assertEquals("get entry for id"+i,""+i,e.getId());
+ }
+
+ BaseEntry e = query.get().singleEntryQuery(""+this.count,feedId,this.profile);
+ assertNull("not entry for ID",e);
+ query.decrementRef();
+
+ }
+
+ /*
+ * Test method for
+ * 'org.apache.lucene.storage.lucenestorage.StorageModifier.deleteEntry(String)'
+ */
+ public void testDeleteEntry() throws IOException, InterruptedException, FeedNotFoundException, ParseException, StorageException {
+ testInsertEntry();
+ for (int i = 1; i < this.count ; i++) {
+ if(i%2 == 0 || i< 10){
+ this.modifier.deleteEntry(""+i,feedId);
+ }
+ ReferenceCounter query = StorageCoreController.getStorageCoreController().getStorageQuery();
+ if(i%2 == 0 || i< 10){
+ assertNull(query.get().singleEntryQuery(""+i,feedId,this.profile));
+ }
+ else
+ assertEquals(""+i,query.get().singleEntryQuery(""+i,feedId,this.profile).getId());
+ query.decrementRef();
+ }
+
+ StorageCoreController.getStorageCoreController().forceWrite();
+ IndexSearcher searcher = new IndexSearcher(this.dir);
+
+ for (int i = 1; i < this.count ; i++) {
+ Query luceneQuery = new TermQuery(new Term(StorageEntryWrapper.FIELD_ENTRY_ID,""+i));
+ Hits hits = searcher.search(luceneQuery);
+ if(i%2 == 0 || i< 10){
+
+ assertEquals(0,hits.length());
+ }
+ else
+ assertEquals(1,hits.length());
+ }
+ searcher.close();
+
+ }
+
+
+ private Thread getRunnerThread(int idIndex){
+ Thread t = new Thread(new Runner(idIndex));
+ return t;
+ }
+
+ private class Runner implements Runnable{
+ private int idIndex;
+ public Runner(int idIndex){
+ this.idIndex = idIndex;
+ }
+ public void run() {
+ for (int i = idIndex; i < idIndex+10; i++) {
+
+ BaseEntry e = buildEntry(""+i);
+ try {
+ StorageEntryWrapper wrapper = new StorageEntryWrapper(e,feedId,StorageOperation.INSERT,new ExtensionProfile());
+ modifier.insertEntry(wrapper);
+ } catch (Exception e1) {
+
+ e1.printStackTrace();
+ }
+
+
+
+
+ }
+
+
+ }//end run
+
+ private BaseEntry buildEntry(String id){
+ Entry e = new Entry();
+ e.setId(id);
+ e.setTitle(new PlainTextConstruct("Monty Python"));
+
+ e.setPublished(DateTime.now());
+
+ e.setUpdated(DateTime.now());
+ String content = "1st soldier with a keen interest in birds: Who goes there?" +
+ "King Arthur: It is I, Arthur, son of Uther Pendragon, from the castle of Camelot. King of the Britons, defeater of the Saxons, Sovereign of all England!" +
+ "1st soldier with a keen interest in birds: Pull the other one!" +
+ "King Arthur: I am, and this is my trusty servant Patsy. We have ridden the length and breadth of the land in search of knights who will join me in my court at Camelot. I must speak with your lord and master." +
+ "1st soldier with a keen interest in birds: What? Ridden on a horse?" +
+ "King Arthur: Yes!";
+ e.setContent(new TextContent(new PlainTextConstruct(content)));
+ e.setSummary(new PlainTextConstruct("The Holy Grail"));
+ return e;
+ }
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestModifiedEntryFilter.java
===================================================================
--- trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestModifiedEntryFilter.java (revision 0)
+++ trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestModifiedEntryFilter.java (revision 0)
@@ -0,0 +1,66 @@
+package org.apache.lucene.gdata.storage.lucenestorage;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+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.storage.lucenestorage.ModifiedEntryFilter;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Hits;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.store.RAMDirectory;
+
+public class TestModifiedEntryFilter extends TestCase {
+ IndexWriter writer;
+ IndexReader reader;
+ List excludeList;
+ String feedID = "feed";
+ String fieldFeedId = "feedID";
+ protected void setUp() throws Exception {
+ RAMDirectory dir = new RAMDirectory();
+ this.writer = new IndexWriter(dir,new StandardAnalyzer(),true);
+ Document doc = new Document();
+ doc.add(new Field(StorageEntryWrapper.FIELD_ENTRY_ID,"1",Field.Store.YES,Field.Index.UN_TOKENIZED));
+ doc.add(new Field(fieldFeedId,feedID,Field.Store.YES,Field.Index.UN_TOKENIZED));
+ Document doc1 = new Document();
+ doc1.add(new Field(StorageEntryWrapper.FIELD_ENTRY_ID,"2",Field.Store.YES,Field.Index.UN_TOKENIZED));
+ doc1.add(new Field(fieldFeedId,feedID,Field.Store.YES,Field.Index.UN_TOKENIZED));
+ this.writer.addDocument(doc);
+ this.writer.addDocument(doc1);
+ this.writer.close();
+ this.reader = IndexReader.open(dir);
+ this.excludeList = new ArrayList();
+ this.excludeList.add("1");
+
+
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+ public void testFilter() throws IOException{
+ Searcher s = new IndexSearcher(this.reader);
+ Query q = new TermQuery(new Term(fieldFeedId,feedID));
+ Hits hits = s.search(q);
+ assertEquals(2,hits.length());
+
+ hits = s.search(q,new ModifiedEntryFilter(this.excludeList));
+ assertEquals(1,hits.length());
+ this.excludeList.add("2");
+
+ hits = s.search(q,new ModifiedEntryFilter(this.excludeList));
+ assertEquals(0,hits.length());
+
+ }
+}
Index: trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageQuery.java
===================================================================
--- trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageQuery.java (revision 0)
+++ trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageQuery.java (revision 0)
@@ -0,0 +1,175 @@
+package org.apache.lucene.gdata.storage.lucenestorage;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.gdata.server.FeedNotFoundException;
+import org.apache.lucene.gdata.server.registry.FeedInstanceConfigurator;
+import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
+import org.apache.lucene.gdata.server.registry.RegistryBuilder;
+import org.apache.lucene.gdata.storage.StorageException;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageModifier;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageQuery;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
+import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.RAMDirectory;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.DateTime;
+import com.google.gdata.data.Entry;
+import com.google.gdata.data.ExtensionProfile;
+import com.google.gdata.data.Feed;
+import com.google.gdata.util.ParseException;
+
+public class TestStorageQuery extends TestCase {
+ private StorageModifier modifier;
+ private int count = 30;
+ private ReferenceCounter query;
+ private ExtensionProfile profile;
+
+ private Directory dir;
+ private static String feedId = "myFeed";
+ protected void setUp() throws Exception {
+ FeedInstanceConfigurator configurator = new FeedInstanceConfigurator();
+ configurator.setFeedType(Feed.class);
+ configurator.setFeedId(feedId);
+ configurator.setExtensionProfileClass(ExtensionProfile.class);
+ GDataServerRegistry.getRegistry().registerFeed(configurator);
+ this.profile = new ExtensionProfile();
+ this.dir = new RAMDirectory();
+ IndexWriter writer;
+ writer = new IndexWriter(this.dir,new StandardAnalyzer(),true);
+ writer.close();
+ this.modifier = StorageCoreController.getStorageCoreController(this.dir).getStorageModifier();
+ insertEntries(this.count);
+ this.query = StorageCoreController.getStorageCoreController().getStorageQuery();
+
+
+
+ }
+
+
+ public void insertEntries(int count) throws IOException,InterruptedException, StorageException{
+ List tempList = new ArrayList();
+ for (int i = 0; i <= count ; i++) {
+ Entry entry = new Entry();
+ entry.setId(""+i);
+
+ entry.setUpdated(new DateTime(System.currentTimeMillis(),0));
+ StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,feedId,StorageOperation.INSERT,this.profile);
+ tempList.add(i,wrapper);
+
+ // force different timestamps --> DateTime 2006-06-05T13:37:55.724Z
+ Thread.sleep(50);
+
+ }
+ for (StorageEntryWrapper entry : tempList) {
+ this.modifier.insertEntry(entry);
+ }
+
+
+
+
+ }
+
+ protected void tearDown() throws Exception {
+ this.query.decrementRef();
+ GDataServerRegistry.getRegistry().destroy();//TODO remove dependency here
+ }
+
+ /*
+ * Test method for 'org.apache.lucene.storage.lucenestorage.StorageQuery.feedQuery(String, int, int)'
+ */
+ public void testFeedQuery() throws IOException, FeedNotFoundException, ParseException, StorageException {
+ FeedQueryHelper(this.query);
+ StorageCoreController.getStorageCoreController().forceWrite();
+ ReferenceCounter queryAssureWritten = StorageCoreController.getStorageCoreController().getStorageQuery();
+
+ assertNotSame(queryAssureWritten,this.query);
+ FeedQueryHelper(queryAssureWritten);
+ queryAssureWritten.decrementRef();
+ }
+ private void FeedQueryHelper(ReferenceCounter currentQuery) throws IOException, FeedNotFoundException, ParseException{
+ List entryList = currentQuery.get().getLatestFeedQuery(feedId,25,1,this.profile);
+
+ assertTrue("listSize: "+entryList.size(),entryList.size() == 25);
+
+ BaseEntry tempEntry = null;
+ for (BaseEntry entry : entryList) {
+
+ assertNotNull("entry",entry);
+ if(tempEntry != null){
+ assertTrue(tempEntry.getUpdated().compareTo(entry.getUpdated())>=0) ;
+ tempEntry = entry;
+ }else
+ tempEntry = entry;
+
+ }
+ // test sub retrieve sublist
+ int offset = 15;
+ int resultCount = 5;
+ List entrySubList = currentQuery.get().getLatestFeedQuery(feedId,resultCount,offset,this.profile);
+
+ assertTrue("listSize: "+entrySubList.size(),entrySubList.size() == resultCount);
+ offset--;
+ for (BaseEntry entry : entrySubList) {
+
+ assertEquals(entry.getId(),entryList.get(offset).getId());
+ offset++;
+
+ }
+
+
+
+ }
+
+ /*
+ * Test method for 'org.apache.lucene.storage.lucenestorage.StorageQuery.singleEntryQuery(String, String)'
+ */
+ public void testSingleEntryQuery() throws FeedNotFoundException, ParseException, IOException {
+ for (int i = 1; i <= this.count; i++) {
+ BaseEntry entry = this.query.get().singleEntryQuery(""+i,feedId,this.profile);
+ assertEquals(""+i,entry.getId());
+ }
+
+ }
+
+ /*
+ * Test method for 'org.apache.lucene.storage.lucenestorage.StorageQuery.entryQuery(List, String)'
+ */
+ public void testEntryQuery() throws FeedNotFoundException, ParseException, IOException, StorageException {
+ entryQueryHelper(this.query);
+ StorageCoreController.getStorageCoreController().forceWrite();
+ ReferenceCounter queryAssureWritten = StorageCoreController.getStorageCoreController().getStorageQuery();
+
+ assertNotSame(queryAssureWritten,query);
+ entryQueryHelper(queryAssureWritten);
+ queryAssureWritten.decrementRef();
+ }
+
+
+ private void entryQueryHelper(ReferenceCounter currentQuery) throws IOException, FeedNotFoundException, ParseException{
+
+ List entryIdList = new ArrayList();
+ for (int i = 1; i <= this.count; i++) {
+ entryIdList.add(""+i);
+ }
+ List entryList = currentQuery.get().entryQuery(entryIdList,feedId,this.profile);
+ assertEquals(entryIdList.size(),entryList.size());
+ List entryIdCompare = new ArrayList();
+ for (BaseEntry entry : entryList) {
+ entryIdCompare.add(entry.getId());
+ }
+ assertTrue(entryIdList.containsAll(entryIdCompare));
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/TestIDGenerator.java
===================================================================
--- trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/TestIDGenerator.java (revision 0)
+++ trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/TestIDGenerator.java (revision 0)
@@ -0,0 +1,52 @@
+package org.apache.lucene.gdata.storage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.lucene.gdata.storage.IDGenerator;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public class TestIDGenerator extends TestCase {
+ private IDGenerator idgen;
+
+ private int initialCap = 100;
+
+ @Override
+ protected void setUp() throws Exception {
+ this.idgen = new IDGenerator(this.initialCap);
+
+
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ this.idgen.stopIDGenerator();
+ }
+
+ /**
+ * Test method for 'org.apache.lucene.gdata.storage.IDGenerator.getUID()'
+ * @throws InterruptedException
+ */
+ public void testGetUID() throws InterruptedException {
+
+ List idlist = new ArrayList();
+ //TODO think about a better way to test this
+ for (int i = 0; i < 1000; i++) {
+ String id = this.idgen.getUID();
+ assertNotNull(id);
+ assertFalse(idlist.contains(id));
+ idlist.add(id);
+
+
+
+ }
+
+ }
+
+
+}
Property changes on: trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/TestIDGenerator.java
___________________________________________________________________
Name: svn:executable
+ *
Index: trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataResponse.java
===================================================================
--- trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataResponse.java (revision 0)
+++ trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataResponse.java (revision 0)
@@ -0,0 +1,161 @@
+package org.apache.lucene.gdata.server;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.TestCase;
+
+import org.apache.lucene.gdata.server.GDataRequest.OutputFormat;
+import org.easymock.MockControl;
+
+import com.google.gdata.data.Entry;
+import com.google.gdata.data.ExtensionProfile;
+import com.google.gdata.data.Feed;
+import com.google.gdata.data.PlainTextConstruct;
+/**
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class TestGDataResponse extends TestCase {
+ private GDataResponse response;
+ private HttpServletResponse httpResponse;
+ private MockControl control;
+ private static String generatedFeedAtom = "Test";
+ private static String generatedEntryAtom = "Test";
+ private static String generatedFeedRSS = "Test";
+ private static String generatedEntryRSS = "Test";
+ protected void setUp() throws Exception {
+ this.control = MockControl.createControl(HttpServletResponse.class);
+ this.httpResponse = (HttpServletResponse)this.control.getMock();
+ this.response = new GDataResponse(this.httpResponse);
+
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+
+ public void testConstructor(){
+ try{
+ new GDataResponse(null);
+ fail("IllegalArgumentExceptin expected");
+ }catch (IllegalArgumentException e) {
+ // TODO: handle exception
+ }
+ }
+ /*
+ * Test method for 'org.apache.lucene.gdata.server.GDataResponse.sendResponse(BaseFeed, ExtensionProfile)'
+ */
+ public void testSendResponseBaseFeedExtensionProfile() throws IOException {
+ try{
+ Feed f = null;
+ this.response.sendResponse(f,new ExtensionProfile());
+ fail("Exception expected");
+ }catch (IllegalArgumentException e) {
+ //
+ }
+
+ try{
+ Feed f = createFeed();
+ this.response.sendResponse(f,null);
+ fail("Exception expected");
+ }catch (IllegalArgumentException e) {
+ //
+ }
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter writer = new PrintWriter(stringWriter);
+
+ this.control.expectAndReturn(this.httpResponse.getWriter(),writer);
+ this.response.setOutputFormat(OutputFormat.ATOM);
+ this.control.replay();
+
+ this.response.sendResponse(createFeed(),new ExtensionProfile
+ ());
+ assertEquals("Simple XML representation",stringWriter.toString(),generatedFeedAtom);
+ this.control.reset();
+
+ stringWriter = new StringWriter();
+ writer = new PrintWriter(stringWriter);
+
+ this.control.expectAndReturn(this.httpResponse.getWriter(),writer);
+ this.response.setOutputFormat(OutputFormat.RSS);
+ this.control.replay();
+
+ this.response.sendResponse(createFeed(),new ExtensionProfile
+ ());
+ assertEquals("Simple XML representation",stringWriter.toString(),generatedFeedRSS);
+
+
+
+
+ }
+
+ /*
+ * Test method for 'org.apache.lucene.gdata.server.GDataResponse.sendResponse(BaseEntry, ExtensionProfile)'
+ */
+ public void testSendResponseBaseEntryExtensionProfile() throws IOException {
+ try{
+ Entry e = null;
+ this.response.sendResponse(e,new ExtensionProfile());
+ fail("Exception expected");
+ }catch (IllegalArgumentException e) {
+ //
+ }
+ try{
+ Entry e = createEntry();
+ this.response.sendResponse(e,null);
+ fail("Exception expected");
+ }catch (IllegalArgumentException e) {
+ //
+ }
+// // test Atom output
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter writer = new PrintWriter(stringWriter);
+
+ this.control.expectAndReturn(this.httpResponse.getWriter(),writer);
+ this.response.setOutputFormat(OutputFormat.ATOM);
+ this.control.replay();
+
+ this.response.sendResponse(createEntry(),new ExtensionProfile
+ ());
+ assertEquals("Simple XML representation ATOM",stringWriter.toString(),generatedEntryAtom);
+
+ // test rss output
+ this.control.reset();
+ stringWriter = new StringWriter();
+ writer = new PrintWriter(stringWriter);
+
+ this.control.expectAndReturn(this.httpResponse.getWriter(),writer);
+ this.response.setOutputFormat(OutputFormat.RSS);
+ this.control.replay();
+
+ this.response.sendResponse(createEntry(),new ExtensionProfile
+ ());
+
+ assertEquals("Simple XML representation RSS",stringWriter.toString(),generatedEntryRSS);
+
+
+
+ }
+
+ /* create a simple feed */
+ private Feed createFeed(){
+ Feed feed = new Feed();
+
+ feed.getEntries().add(createEntry());
+
+ return feed;
+ }
+ /* create a simple entry */
+ private Entry createEntry(){
+ Entry e = new Entry();
+ e.setTitle(new PlainTextConstruct("Test"));
+ return e;
+ }
+
+}
Index: trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestGDataEntityBuilder.java
===================================================================
--- trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestGDataEntityBuilder.java (revision 0)
+++ trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestGDataEntityBuilder.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.server.registry;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+
+import junit.framework.TestCase;
+
+import org.apache.lucene.gdata.server.FeedNotFoundException;
+import org.apache.lucene.gdata.server.GDataEntityBuilder;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.BaseFeed;
+import com.google.gdata.data.Entry;
+import com.google.gdata.data.ExtensionProfile;
+import com.google.gdata.data.Feed;
+import com.google.gdata.util.ParseException;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public class TestGDataEntityBuilder extends TestCase {
+ private static File incomingFeed = new File("src/test/org/apache/lucene/gdata/server/registry/TestEntityBuilderIncomingFeed.xml");
+ private static File incomingEntry = new File("src/test/org/apache/lucene/gdata/server/registry/TestEntityBuilderIncomingEntry.xml");
+ private static String feedTitleFromXML = "Simon Willnauer";
+ private static String entrySummaryFromXML = "When: 2006-12-23 to 2006-12-31 America/Los_Angeles";
+ private static GDataServerRegistry reg = GDataServerRegistry.getRegistry();
+ private Reader reader;
+ private static String feedID = "myFeed";
+ private ExtensionProfile profile;
+ private static Class feedType = Feed.class;
+
+
+ /**
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ FeedInstanceConfigurator config = new FeedInstanceConfigurator();
+ config.setFeedId(feedID);
+ config.setFeedType(feedType);
+ this.profile = new ExtensionProfile();
+ reg.registerFeed(config);
+ }
+
+ /**
+ * @see junit.framework.TestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ reg.flushRegistry();
+ this.reader = null;
+ }
+
+ /**
+ * Test method for 'org.apache.lucene.gdata.data.GDataEntityBuilder.buildFeed(String, Reader)'
+ */
+ public void testBuildFeedStringReader() throws FeedNotFoundException, ParseException, IOException {
+ this.reader = new FileReader(incomingFeed);
+ BaseFeed feed = GDataEntityBuilder.buildFeed(feedID,this.reader,this.profile);
+ assertNotNull(feed);
+ assertEquals("feed title",feed.getTitle().getPlainText(), feedTitleFromXML);
+ assertTrue( feed instanceof Feed);
+
+ }
+
+ /*
+ * Test method for 'org.apache.lucene.gdata.data.GDataEntityBuilder.buildEntry(String, Reader)'
+ */
+ public void testBuildEntryStringReader() throws FeedNotFoundException, ParseException, IOException {
+ this.reader = new FileReader(incomingEntry);
+ BaseEntry entry = GDataEntityBuilder.buildEntry(feedID,this.reader,this.profile);
+ assertNotNull(entry);
+ assertEquals("entry summary",entry.getSummary().getPlainText(),entrySummaryFromXML);
+ assertTrue(entry instanceof Entry);
+
+ }
+
+
+
+}
Index: trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestEntityBuilderIncomingEntry.xml
===================================================================
--- trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestEntityBuilderIncomingEntry.xml (revision 0)
+++ trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestEntityBuilderIncomingEntry.xml (revision 0)
@@ -0,0 +1,21 @@
+
+
+
+ http://www.google.com/calendar/feeds/simon.willnauer%40googlemail.com/public/basic/af4b5ca305c80f96f42c9af66c5b04a8473c949c
+
+ 2006-12-23T00:00:00.000Z
+ 2006-05-23T16:42:48.000Z
+
+
+
+ When: 2006-12-23 to 2006-12-31 America/Los_Angeles<br>
+
+
+
+
+
+
\ No newline at end of file
Index: trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestEntityBuilderIncomingFeed.xml
===================================================================
--- trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestEntityBuilderIncomingFeed.xml (revision 0)
+++ trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestEntityBuilderIncomingFeed.xml (revision 0)
@@ -0,0 +1,90 @@
+
+
+
+ http://www.google.com/calendar/feeds/simon.willnauer%40googlemail.com/public/basic
+
+ 2006-05-27T11:47:55.000Z
+ Simon Willnauer
+ Simon Willnauer
+
+
+
+
+
+
+
+ Simon Willnauer
+ simon.willnauer@googlemail.com
+
+
+ Google Calendar
+
+ 25
+
+
+ http://www.google.com/calendar/feeds/simon.willnauer%40googlemail.com/public/basic/af4b5ca305c80f96f42c9af66c5b04a8473c949c
+
+ 2006-12-23T00:00:00.000Z
+ 2006-05-23T16:42:48.000Z
+
+
+
+ When: 2006-12-23 to 2006-12-31 America/Los_Angeles<br>
+
+
+
+
+
+
+
+
+ http://www.google.com/calendar/feeds/simon.willnauer%40googlemail.com/public/basic/d5402951792ce690f6a45e51143deb78f4fffac4
+
+ 2006-05-26T00:00:00.000Z
+ 2006-05-20T22:17:44.000Z
+
+
+
+ When: 2006-05-26 to 2006-05-27 America/Los_Angeles<br>
+
+
+
+
+
+
+
+
+ http://www.google.com/calendar/feeds/simon.willnauer%40googlemail.com/public/basic/21630e853795ea81d5e792d0ab082ad1c44256e4
+
+ 2006-06-19T14:00:00.000Z
+ 2006-05-17T16:10:57.000Z
+
+
+
+ When: 2006-06-19 07:00:00 to 08:00:00
+ America/Los_Angeles<br>
+
+
+
+
+
+
+
\ No newline at end of file
Index: trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestFeedRegistry.java
===================================================================
--- trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestFeedRegistry.java (revision 0)
+++ trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestFeedRegistry.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.server.registry;
+
+import com.google.gdata.data.Feed;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public class TestFeedRegistry extends TestCase {
+ private GDataServerRegistry reg;
+ private FeedInstanceConfigurator configurator;
+ @Override
+ protected void setUp(){
+ this.reg = GDataServerRegistry.getRegistry();
+ this.configurator = new FeedInstanceConfigurator();
+ }
+ /**
+ * @see junit.framework.TestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ this.reg.flushRegistry();
+ }
+ /**
+ * Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getRegistry()'
+ */
+ public void testGetRegistry() {
+
+ GDataServerRegistry reg1 = GDataServerRegistry.getRegistry();
+ assertEquals("test singleton",this.reg,reg1);
+ }
+
+ /**
+ * Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.registerFeed(FeedInstanceConfigurator)'
+ */
+ public void testRegisterFeed() {
+ String feedURL = "myFeed";
+ registerFeed(feedURL);
+ assertEquals("Registered Configurator",this.configurator,this.reg.getFeedConfigurator(feedURL));
+ assertNull("not registered Configurator",this.reg.getFeedConfigurator("somethingElse"));
+ try{
+ this.reg.getFeedConfigurator(null);
+ fail("Exception expected");
+ }catch (IllegalArgumentException e) {
+ //
+ }
+ }
+
+ /**
+ * Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getFeedConfigurator(String)'
+ */
+ public void testFlushRegistry() {
+ String feedURL = "testFeed";
+ registerFeed(feedURL);
+ assertEquals("Registered Configurator",this.configurator,this.reg.getFeedConfigurator(feedURL));
+ this.reg.flushRegistry();
+ assertNull("Registry flushed",this.reg.getFeedConfigurator(feedURL));
+
+
+ }
+
+ /**
+ *
+ */
+ public void testIsFeedRegistered(){
+ String myFeed = "myFeed";
+ registerFeed(myFeed);
+ assertTrue("Feed is registerd",this.reg.isFeedRegistered(myFeed));
+ assertFalse("null Feed is not registerd",this.reg.isFeedRegistered(null));
+ assertFalse("Feed is not registerd",this.reg.isFeedRegistered("someOtherFeed"));
+
+ }
+
+ private void registerFeed(String feedURL){
+
+ this.configurator.setFeedType(Feed.class);
+ this.configurator.setFeedId(feedURL);
+ this.reg.registerFeed(this.configurator);
+ }
+
+}
Index: trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataRequest.java
===================================================================
--- trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataRequest.java (revision 0)
+++ trunk/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataRequest.java (revision 0)
@@ -0,0 +1,403 @@
+/**
+ * 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;
+
+import javax.servlet.http.HttpServletRequest;
+
+import junit.framework.TestCase;
+
+import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType;
+import org.apache.lucene.gdata.server.GDataRequest.OutputFormat;
+import org.apache.lucene.gdata.server.registry.FeedInstanceConfigurator;
+import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
+import org.easymock.MockControl;
+
+import com.google.gdata.data.ExtensionProfile;
+import com.google.gdata.data.Feed;
+
+/**
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class TestGDataRequest extends TestCase {
+ private HttpServletRequest request;
+
+ private MockControl control;
+
+ private GDataRequest feedRequest;
+
+ @Override
+ protected void setUp() throws Exception {
+ FeedInstanceConfigurator configurator = new FeedInstanceConfigurator();
+ configurator.setFeedType(Feed.class);
+ configurator.setFeedId("feed");
+ configurator.setExtensionProfileClass(ExtensionProfile.class);
+ GDataServerRegistry.getRegistry().registerFeed(configurator);
+ this.control = MockControl.createControl(HttpServletRequest.class);
+ this.request = (HttpServletRequest) this.control.getMock();
+ this.feedRequest = new GDataRequest(this.request,GDataRequestType.GET);
+
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ this.control.reset();
+ }
+
+ public void testConstructor() {
+ try {
+ new GDataRequest(null,GDataRequestType.GET);
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //
+ }
+ try {
+ new GDataRequest(null,null);
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //
+ }
+ try {
+ new GDataRequest(this.request,null);
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //
+ }
+ }
+
+ public void testGetFeedId() throws GDataRequestException {
+
+ this.control.expectAndDefaultReturn(this.request.getPathInfo(),
+ "/feed/1/1");
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ null);
+ this.control.replay();
+ this.feedRequest.initializeRequest();
+ assertEquals("feedID", this.feedRequest.getFeedId(), "feed");
+ this.control.reset();
+
+ }
+
+ public void testEmptyPathInfo() {
+ this.control.expectAndDefaultReturn(this.request.getPathInfo(), "/");
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ null);
+ this.control.replay();
+ try {
+ this.feedRequest.initializeRequest();
+
+ fail("FeedRequestException expected");
+ } catch (GDataRequestException e) {
+ // expected
+ } catch (Exception e) {
+ fail("FeedRequestException expected");
+ }
+
+ }
+
+ public void testGetFeedIdWithoutEntry() throws GDataRequestException {
+ this.control
+ .expectAndDefaultReturn(this.request.getPathInfo(), "/feed");
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ null);
+ this.control.replay();
+ this.feedRequest.initializeRequest();
+ assertEquals("feedID", this.feedRequest.getFeedId(), "feed");
+ }
+
+ public void testGetEntyId() throws GDataRequestException {
+
+ this.control.expectAndDefaultReturn(this.request.getPathInfo(),
+ "/feed/1/15");
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ null);
+ this.control.replay();
+ this.feedRequest.initializeRequest();
+ assertEquals("entryid", this.feedRequest.getEntryId(), "1");
+ assertEquals("feedId", this.feedRequest.getFeedId(), "feed");
+ assertEquals("entryid", this.feedRequest.getEntryVersion(), "15");
+ this.control.reset();
+
+ }
+
+ public void testSetResponseFormatAtom() throws GDataRequestException {
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ "atom");
+ this.control
+ .expectAndDefaultReturn(this.request.getPathInfo(), "/feed");
+ this.control.replay();
+ this.feedRequest.initializeRequest();
+ assertEquals("ResponseFromat Atom", this.feedRequest
+ .getRequestedResponseFormat(), OutputFormat.ATOM);
+ this.control.reset();
+ }
+
+ public void testSetResponseFormatRSS() throws GDataRequestException {
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ "rss");
+ this.control
+ .expectAndDefaultReturn(this.request.getPathInfo(), "/feed");
+ this.control.replay();
+ this.feedRequest.initializeRequest();
+ assertEquals("ResponseFromat RSS", this.feedRequest
+ .getRequestedResponseFormat(), OutputFormat.RSS);
+ this.control.reset();
+ }
+
+ public void testSetResponseFormatKeepAtom() throws GDataRequestException {
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ "fooBar");
+ this.control
+ .expectAndDefaultReturn(this.request.getPathInfo(), "/feed");
+ this.control.replay();
+ this.feedRequest.initializeRequest();
+ assertEquals("ResponseFromat Atom", this.feedRequest
+ .getRequestedResponseFormat(), OutputFormat.ATOM);
+ this.control.reset();
+ }
+
+ public void testSetResponseFormatNull() throws GDataRequestException {
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ null);
+
+ this.control
+ .expectAndDefaultReturn(this.request.getPathInfo(), "/feed");
+ this.control.replay();
+ this.feedRequest.initializeRequest();
+ assertEquals("ResponseFromat Atom", this.feedRequest
+ .getRequestedResponseFormat(), OutputFormat.ATOM);
+ this.control.reset();
+ }
+
+ public void testGetItemsPerPage() throws GDataRequestException {
+ this.control.expectAndReturn(this.request.getParameter("max-results"),
+ null);
+ this.control.replay();
+ assertEquals("default value 25", 25, this.feedRequest.getItemsPerPage());
+ this.control.verify();
+ this.control.reset();
+
+ this.control.expectAndReturn(this.request.getParameter("max-results"),
+ "24", 2);
+ this.control.replay();
+ assertEquals("24 results", 24, this.feedRequest.getItemsPerPage());
+ this.control.verify();
+ this.control.reset();
+
+ this.control.expectAndReturn(this.request.getParameter("max-results"),
+ "-1", 2);
+ this.control.replay();
+ assertEquals("25 results", 25, this.feedRequest.getItemsPerPage());
+ this.control.verify();
+ this.control.reset();
+
+ this.control.expectAndReturn(this.request.getParameter("max-results"),
+ "helloworld", 2);
+ this.control.replay();
+ assertEquals("25 results", 25, this.feedRequest.getItemsPerPage());
+ this.control.verify();
+ this.control.reset();
+ }
+
+ public void testGetSelfId() throws GDataRequestException{
+ String host = "www.apache.org";
+ String feedAndEntryID = "/feed/entryid";
+ String queryString = "?max-results=25";
+ this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
+ this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed/entryId/15");
+ this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15");
+ this.control.expectAndReturn(this.request.getParameter("max-results"),"25",2);
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ null);
+ this.control.expectAndDefaultReturn(this.request.getQueryString(),
+ queryString);
+ this.control.replay();
+ this.feedRequest.initializeRequest();
+ String selfID = "http://"+host+"/host/feed/entryId/15"+queryString;
+
+ assertEquals("Self ID",selfID,this.feedRequest.getSelfId());
+ this.control.reset();
+
+
+ queryString = "?alt=rss&max-results=25";
+ this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
+ this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed/entryId/15");
+ this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15");
+ this.control.expectAndReturn(this.request.getParameter("max-results"),"25",2);
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ null);
+ this.control.expectAndDefaultReturn(this.request.getQueryString(),
+ queryString);
+ this.control.replay();
+ this.feedRequest.initializeRequest();
+ selfID = "http://"+host+"/host/feed/entryId/15"+queryString;
+
+ assertEquals("Self ID",selfID,this.feedRequest.getSelfId());
+ this.control.reset();
+
+ queryString = "";
+ this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
+ this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed/entryId/15");
+ this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15");
+ this.control.expectAndDefaultReturn(this.request.getParameter("max-results"),null);
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ null);
+ this.control.expectAndDefaultReturn(this.request.getQueryString(),
+ null);
+ this.control.replay();
+ this.feedRequest.initializeRequest();
+ selfID = "http://"+host+"/host/feed/entryId/15"+"?max-results=25";
+
+ assertEquals("Self ID",selfID,this.feedRequest.getSelfId());
+ this.control.reset();
+ }
+
+ public void testGetQueryString(){
+ String maxResults = "max-results=25";
+ String queryString = "?"+maxResults;
+ this.control.expectAndReturn(this.request.getParameter("max-results"),"25",2);
+
+ this.control.expectAndDefaultReturn(this.request.getQueryString(),
+ queryString);
+ this.control.replay();
+
+ assertEquals(queryString,this.feedRequest.getQueryString());
+ this.control.reset();
+ // test no result defined
+ queryString = "?alt=rss";
+ this.control.expectAndDefaultReturn(this.request.getParameter("max-results"),null);
+
+ this.control.expectAndDefaultReturn(this.request.getQueryString(),
+ queryString);
+ this.control.replay();
+
+ assertEquals(queryString+"&"+maxResults,this.feedRequest.getQueryString());
+ this.control.reset();
+
+// test no result defined && query == null
+ queryString = null;
+ this.control.expectAndDefaultReturn(this.request.getParameter("max-results"),null);
+
+ this.control.expectAndDefaultReturn(this.request.getQueryString(),
+ queryString);
+ this.control.replay();
+
+ assertEquals("?"+maxResults,this.feedRequest.getQueryString());
+ this.control.reset();
+
+ }
+
+ public void testIsFeedRequest() throws GDataRequestException{
+ String host = "www.apache.org";
+ String feedAndEntryID = "/feed";
+
+ this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
+ this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed");
+ this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed");
+
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ null);
+ this.control.expectAndDefaultReturn(this.request.getQueryString(),
+ null);
+ this.control.replay();
+ this.feedRequest.initializeRequest();
+
+
+ assertTrue(this.feedRequest.isFeedRequested());
+ assertFalse(this.feedRequest.isEntryRequested());
+ this.control.reset();
+
+ host = "www.apache.org";
+ feedAndEntryID = "/feed/1";
+
+ this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
+ this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed/1");
+ this.control.expectAndDefaultReturn(this.request.getPathInfo(),feedAndEntryID);
+
+ this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+ null);
+ this.control.expectAndDefaultReturn(this.request.getQueryString(),
+ null);
+ this.control.replay();
+ this.feedRequest.initializeRequest();
+
+
+ assertFalse(this.feedRequest.isFeedRequested());
+ assertTrue(this.feedRequest.isEntryRequested());
+ this.control.reset();
+
+
+ }
+ public void testIsEntryRequest(){
+
+ }
+
+ public void testGetNextId() throws GDataRequestException{
+// String host = "www.apache.org";
+// String feedAndEntryID = "/feed/entryid";
+// String queryString = "?max-results=25";
+// String startIndex = "&start-index=26";
+// this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
+// this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15");
+// this.control.expectAndReturn(this.request.getParameter("max-results"),"25",2);
+// this.control.expectAndReturn(this.request.getParameter("start-index"),null);
+// this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+// null);
+// this.control.expectAndDefaultReturn(this.request.getQueryString(),
+// queryString);
+// this.control.replay();
+// this.feedRequest.initializeRequest();
+// String nextID = "http://"+host+"/feed"+queryString+startIndex;
+//
+// assertEquals("Next ID",nextID,this.feedRequest.getNextId());
+// this.control.reset();
+//
+//
+// queryString = "?alt=rss&max-results=25";
+//
+// this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
+// this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15");
+// this.control.expectAndReturn(this.request.getParameter("max-results"),"25",2);
+// this.control.expectAndReturn(this.request.getParameter("start-index"),"26",2);
+// this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+// null);
+// this.control.expectAndDefaultReturn(this.request.getQueryString(),
+// queryString+startIndex);
+// this.control.replay();
+// this.feedRequest.initializeRequest();
+// startIndex = "&start-index=51";
+// nextID = "http://"+host+"/feed"+queryString+startIndex;
+//
+// assertEquals("Next ID 51",nextID,this.feedRequest.getNextId());
+// this.control.reset();
+//
+// queryString = "";
+// this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
+// this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15");
+// this.control.expectAndDefaultReturn(this.request.getParameter("max-results"),null);
+// this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
+// null);
+// this.control.expectAndDefaultReturn(this.request.getQueryString(),
+// null);
+// this.control.replay();
+// this.feedRequest.initializeRequest();
+// selfID = "http://"+host+"/feed"+"?max-results=25";
+//
+// assertEquals("Self ID",selfID,this.feedRequest.getSelfId());
+// this.control.reset();
+ }
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/RequestControllerServlet.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/RequestControllerServlet.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/RequestControllerServlet.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.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.servlet.handler.DefaultRequestHandlerFactory;
+import org.apache.lucene.gdata.servlet.handler.GDataRequestHandler;
+import org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory;
+
+/**
+ * Provides a clean basic interface for GDATA Client API and requests to the
+ * GDATA Server. This Servlet dispatches the incoming requests to defined GDATA
+ * request handlers. Each of the handler processes the incoming request and
+ * responds according to the requested action.
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class RequestControllerServlet extends AbstractGdataServlet {
+ private static RequestHandlerFactory HANDLER_FACTORY = null;
+ private static final Log LOGGER = LogFactory.getLog(RequestControllerServlet.class);
+
+ /**
+ * Version ID since this class implements
+ *
+ * @see java.io.Serializable
+ */
+ private static final long serialVersionUID = 7540810742476175576L;
+
+ /**
+ * @see javax.servlet.http.HttpServlet#doDelete(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ protected void doDelete(HttpServletRequest arg0, HttpServletResponse arg1)
+ throws ServletException, IOException {
+ GDataRequestHandler hanlder = HANDLER_FACTORY.getDeleteHandler();
+ if(LOGGER.isInfoEnabled())
+ LOGGER.info("Process DELETE request");
+
+ hanlder.processRequest(arg0, arg1);
+ }
+
+ /**
+ * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1)
+ throws ServletException, IOException {
+ GDataRequestHandler hanlder = HANDLER_FACTORY.getQueryHandler();
+ if(LOGGER.isInfoEnabled())
+ LOGGER.info("Process GET request");
+
+ hanlder.processRequest(arg0, arg1);
+ }
+
+ /**
+ * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ protected void doPost(HttpServletRequest arg0, HttpServletResponse arg1)
+ throws ServletException, IOException {
+ GDataRequestHandler hanlder = HANDLER_FACTORY.getInsertHandler();
+ if(LOGGER.isInfoEnabled())
+ LOGGER.info("Process POST request");
+ hanlder.processRequest(arg0, arg1);
+ }
+
+ /**
+ * @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ protected void doPut(HttpServletRequest arg0, HttpServletResponse arg1)
+ throws ServletException, IOException {
+ GDataRequestHandler hanlder = HANDLER_FACTORY.getUpdateHandler();
+ if(LOGGER.isInfoEnabled())
+ LOGGER.info("Process PUT request");
+ hanlder.processRequest(arg0, arg1);
+ }
+
+ /**
+ * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
+ */
+ @Override
+ public void init(ServletConfig arg0) {
+ /*
+ * The Factory implementation could be configured as an initial
+ * parameter or by an external config file.
+ *
+ */
+ HANDLER_FACTORY = RequestHandlerFactory
+ .getInstance(DefaultRequestHandlerFactory.class);
+
+ }
+
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/AbstractGdataServlet.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/AbstractGdataServlet.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/AbstractGdataServlet.java (revision 0)
@@ -0,0 +1,97 @@
+/**
+ * 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.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * Provides an abstract class to be subclassed to create an GDATA servlet
+ * suitable for a GDATA serverside implementation.
+ *
+ * @see javax.servlet.http.HttpServlet
+ *
+ * @author Simon Willnauer
+ *
+ */
+public abstract class AbstractGdataServlet extends HttpServlet {
+ private static final String METHOD_HEADER_NAME = "x-http-method-override";
+
+ private static final String METHOD_DELETE = "DELETE";
+
+ private static final String METHOD_GET = "GET";
+
+ private static final String METHOD_POST = "POST";
+
+ private static final String METHOD_PUT = "PUT";
+
+ /**
+ * This overwrites the protected service method to dispatch
+ * the request to the correponding do method. There is
+ * ususaly no need for overwriting this method. The GData protool and the
+ * Google GData API uses the x-http-method-override header to
+ * get through firewalls. The http method will be overritten by the
+ * x-http-method-override and dispatched to the
+ * doXxx methods defined in this class. This method
+ * is an GDATA-specific version of the {@link javax.servlet.Servlet#service}
+ * method.
+ *
+ * @see HttpServlet#service(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ protected void service(HttpServletRequest arg0, HttpServletResponse arg1)
+ throws ServletException, IOException {
+ if (arg0.getHeader(METHOD_HEADER_NAME) == null) {
+ super.service(arg0, arg1);
+ return;
+ }
+ overrideMethod(arg0, arg1);
+
+ }
+
+ private void overrideMethod(HttpServletRequest arg0,
+ HttpServletResponse arg1) throws ServletException, IOException {
+ final String method = arg0.getMethod();
+ final String overrideHeaderMethod = arg0.getHeader(METHOD_HEADER_NAME);
+ if (overrideHeaderMethod.equals(method)) {
+ super.service(arg0, arg1);
+ return;
+ }
+ // These methodes are use by GDATA Client APIs
+ if (overrideHeaderMethod.equals(METHOD_DELETE)) {
+ doDelete(arg0, arg1);
+ } else if (overrideHeaderMethod.equals(METHOD_GET)) {
+ doGet(arg0, arg1);
+ } else if (overrideHeaderMethod.equals(METHOD_POST)) {
+ doPost(arg0, arg1);
+ } else if (overrideHeaderMethod.equals(METHOD_PUT)) {
+ doPut(arg0, arg1);
+ } else {
+ // if another method has been overwritten follow the HttpServlet
+ // implementation
+ super.service(arg0, arg1);
+ }
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultGetHandler.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultGetHandler.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultGetHandler.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.servlet.handler;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.server.GDataRequestException;
+import org.apache.lucene.gdata.server.Service;
+import org.apache.lucene.gdata.server.ServiceException;
+import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.BaseFeed;
+
+/**
+ * Default Handler implementation. This handler processes the incoming
+ * {@link org.apache.lucene.gdata.server.GDataRequest} and retrieves the
+ * requested feed from the underlaying 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
+ * {@link org.apache.lucene.gdata.server.GDataRequest} instance passed to the
+ * {@link Service} class.
+ *
+ *
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class DefaultGetHandler extends AbstractGdataRequestHandler {
+ private static final Log LOG = LogFactory.getLog(DefaultGetHandler.class);
+
+ /**
+ * @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ public void processRequest(HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException {
+ try {
+ initializeRequestHandler(request, response, GDataRequestType.GET);
+ } catch (GDataRequestException e) {
+ sendError();
+ return;
+ }
+ Service service = getService();
+ try {
+ if (LOG.isInfoEnabled())
+ LOG.info("Requested output formate: "
+ + this.feedRequest.getRequestedResponseFormat());
+ this.feedResponse.setOutputFormat(this.feedRequest
+ .getRequestedResponseFormat());
+ if(this.feedRequest.isFeedRequested()){
+ BaseFeed feed = service
+ .getFeed(this.feedRequest, this.feedResponse);
+
+ this.feedResponse.sendResponse(feed, this.feedRequest.getExtensionProfile());
+ }else{
+ BaseEntry entry = service.getSingleEntry(this.feedRequest,this.feedResponse);
+ if(entry == null){
+ this.feedResponse.setError(HttpServletResponse.SC_NOT_FOUND);
+ sendError();
+ }
+ this.feedResponse.sendResponse(entry, this.feedRequest.getExtensionProfile());
+ }
+
+
+ } catch (ServiceException e) { // TODO handle exceptions to send exact
+ // response
+ LOG.error("Could not process GetFeed request - " + e.getMessage(),
+ e);
+ this.feedResponse.setError(HttpServletResponse.SC_BAD_REQUEST); // TODO
+ // change
+ // this
+ sendError();
+ }
+
+
+
+ }
+
+
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultRequestHandlerFactory.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultRequestHandlerFactory.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultRequestHandlerFactory.java (revision 0)
@@ -0,0 +1,69 @@
+/**
+ * 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.servlet.handler;
+
+/**
+ * Default implementation for RequestHandlerFactory Builds the
+ * {@link org.apache.lucene.gdata.servlet.handler.GDataRequestHandler}
+ * instances.
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class DefaultRequestHandlerFactory extends RequestHandlerFactory {
+
+ DefaultRequestHandlerFactory() {
+ //
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getUpdateHandler()
+ */
+ @Override
+ public GDataRequestHandler getUpdateHandler() {
+
+ return new DefaultUpdateHandler();
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getDeleteHandler()
+ */
+ @Override
+ public GDataRequestHandler getDeleteHandler() {
+
+ return new DefaultDeleteHandler();
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getQueryHandler()
+ */
+ @Override
+ public GDataRequestHandler getQueryHandler() {
+
+ return new DefaultGetHandler();
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getInsertHandler()
+ */
+ @Override
+ public GDataRequestHandler getInsertHandler() {
+
+ return new DefaultInsertHandler();
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultDeleteHandler.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultDeleteHandler.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultDeleteHandler.java (revision 0)
@@ -0,0 +1,84 @@
+/**
+ * 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.servlet.handler;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.server.FeedNotFoundException;
+import org.apache.lucene.gdata.server.GDataRequestException;
+import org.apache.lucene.gdata.server.Service;
+import org.apache.lucene.gdata.server.ServiceException;
+import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType;
+
+/**
+ * Default Handler implementation. This handler processes the incoming
+ * {@link org.apache.lucene.gdata.server.GDataRequest} and deletes the requested
+ * feed entry from the storage and the search component.
+ *
+ * The handler sends following response to the client:
+ *
+ *
+ *
if the entry could be deleted - HTTP status code 200 OK
+ *
if an error occures - HTTP status code 500 INTERNAL SERVER ERROR
+ *
if the resource could not found - HTTP status code 404 NOT FOUND
+ *
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class DefaultDeleteHandler extends AbstractGdataRequestHandler {
+ private static final Log LOG = LogFactory
+ .getLog(DefaultDeleteHandler.class);
+
+ /**
+ * @throws ServletException
+ * @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ public void processRequest(HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException {
+ try {
+ initializeRequestHandler(request, response,GDataRequestType.DELETE);
+ } catch (GDataRequestException e) {
+ sendError();
+ return;
+ }
+
+ Service service = getService();
+ try {
+ service.deleteEntry(this.feedRequest, this.feedResponse);
+ } catch (FeedNotFoundException e) {
+ LOG.error("Could not process DeleteFeed request Feed Not Found- "
+ + e.getMessage(), e);
+ setError(HttpServletResponse.SC_NOT_FOUND);
+ sendError();
+ } catch (ServiceException e) {
+ LOG.error("Could not process DeleteFeed request - "
+ + e.getMessage(), e);
+ setError(HttpServletResponse.SC_BAD_REQUEST);
+ sendError();
+ }
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultUpdateHandler.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultUpdateHandler.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultUpdateHandler.java (revision 0)
@@ -0,0 +1,94 @@
+/**
+ * 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.servlet.handler;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.server.FeedNotFoundException;
+import org.apache.lucene.gdata.server.GDataRequestException;
+import org.apache.lucene.gdata.server.Service;
+import org.apache.lucene.gdata.server.ServiceException;
+import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType;
+
+import com.google.gdata.data.BaseEntry;
+
+/**
+ * Default Handler implementation. This handler processes the incoming
+ * {@link org.apache.lucene.gdata.server.GDataRequest} and updates the requested
+ * feed entry in the storage and the search component.
+ *
+ * The handler sends following response to the client:
+ *
+ *
+ *
if the entry was successfully updated - HTTP status code 200 OK
+ *
if an error occures - HTTP status code 500 INTERNAL SERVER ERROR
+ *
if the resource could not found - HTTP status code 404 NOT FOUND
+ *
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class DefaultUpdateHandler extends AbstractGdataRequestHandler {
+ private static final Log LOG = LogFactory
+ .getLog(DefaultUpdateHandler.class);
+
+ /**
+ * @throws ServletException
+ * @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ public void processRequest(HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException {
+ try {
+ initializeRequestHandler(request, response,GDataRequestType.UPDATE);
+ } catch (GDataRequestException e) {
+ sendError();
+ return;
+ }
+
+ Service service = getService();
+ try {
+ BaseEntry entry = service.updateEntry(this.feedRequest,
+ this.feedResponse);
+ setFeedResponseFormat();
+ setFeedResponseStatus(HttpServletResponse.SC_OK);
+ this.feedResponse.sendResponse(entry, this.feedRequest.getExtensionProfile());
+ }catch (FeedNotFoundException e) {
+ LOG.error("Could not process UpdateFeed request - "
+ + e.getMessage(), e);
+ setError(HttpServletResponse.SC_NOT_FOUND);
+
+ sendError();
+ }
+ catch (ServiceException e) {
+
+ LOG.error("Could not process UpdateFeed request - "
+ + e.getMessage(), e);
+ setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+
+ sendError();
+ }
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/GDataRequestHandlerException.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/GDataRequestHandlerException.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/GDataRequestHandlerException.java (revision 0)
@@ -0,0 +1,64 @@
+/**
+ * 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.servlet.handler;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public class GDataRequestHandlerException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -418225239671624153L;
+
+
+ /**
+ *
+ */
+ public GDataRequestHandlerException() {
+ super();
+
+ }
+
+ /**
+ * @param arg0
+ */
+ public GDataRequestHandlerException(String arg0) {
+ super(arg0);
+
+ }
+
+ /**
+ * @param arg0
+ * @param arg1
+ */
+ public GDataRequestHandlerException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+
+ }
+
+ /**
+ * @param arg0
+ */
+ public GDataRequestHandlerException(Throwable arg0) {
+ super(arg0);
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultInsertHandler.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultInsertHandler.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultInsertHandler.java (revision 0)
@@ -0,0 +1,83 @@
+/**
+ * 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.servlet.handler;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.server.GDataRequestException;
+import org.apache.lucene.gdata.server.Service;
+import org.apache.lucene.gdata.server.ServiceException;
+import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType;
+
+import com.google.gdata.data.BaseEntry;
+
+/**
+ * Default Handler implementation. This handler processes the incoming
+ * {@link org.apache.lucene.gdata.server.GDataRequest} and inserts the requested
+ * feed entry into the storage and the search component.
+ *
+ * The handler sends following response to the client:
+ *
+ *
+ *
if the entry was added - HTTP status code 200 OK
+ *
if an error occures - HTTP status code 500 INTERNAL SERVER ERROR
+ *
if the resource could not found - HTTP status code 404 NOT FOUND
+ *
+ *
The added entry will be send back to the client if the insert request was successful.
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class DefaultInsertHandler extends AbstractGdataRequestHandler {
+ private static final Log LOG = LogFactory.getLog(DefaultInsertHandler.class);
+ /**
+ * @throws ServletException
+ * @see org.apache.lucene.gdata.servlet.handler.GDataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ public void processRequest(HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException {
+ try {
+ initializeRequestHandler(request,response,GDataRequestType.INSERT);
+ } catch (GDataRequestException e) {
+ sendError();
+ return;
+ }
+
+ Service service = getService();
+ try{
+ BaseEntry entry = service.createEntry(this.feedRequest,this.feedResponse);
+ setFeedResponseFormat();
+ setFeedResponseStatus(HttpServletResponse.SC_CREATED);
+ this.feedResponse.sendResponse(entry, this.feedRequest.getExtensionProfile());
+
+ }catch (ServiceException e) {
+ LOG.error("Could not process GetFeed request - "+e.getMessage(),e);
+ setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ this.feedResponse.sendError();
+ }
+
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/GDataRequestHandler.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/GDataRequestHandler.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/GDataRequestHandler.java (revision 0)
@@ -0,0 +1,55 @@
+/**
+ * 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.servlet.handler;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * Based on the Command pattern [GoF], the Command and Controller Strategy
+ * suggests providing a generic interface to the handler components to which the
+ * controller may delegate responsibility, minimizing the coupling among these
+ * components.
+ *
+ * Adding to or changing the work that needs to be completed by these handlers
+ * does not require any changes to the interface between the controller and the
+ * handlers, but rather to the type and/or content of the commands. This provides
+ * a flexible and easily extensible mechanism for developers to add request
+ * handling behaviors.
+ *
+ * The controller invokes the processRequest method from the corresponding servlet doXXX
+ * method to delegate the request to the handler.
+ *
+ *
+ * @author Simon Willnauer
+ *
+ */
+public interface GDataRequestHandler {
+ /**
+ * Processes the GDATA Client request
+ *
+ * @param request - the client request to be processed
+ * @param response - the response to the client request
+ * @throws ServletException - if a servlet exception is thrown by the request or response
+ * @throws IOException - if an input/output error occurs due to accessing an IO steam
+ */
+ public abstract void processRequest(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException;
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractGdataRequestHandler.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractGdataRequestHandler.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractGdataRequestHandler.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.servlet.handler;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.server.GDataRequest;
+import org.apache.lucene.gdata.server.GDataRequestException;
+import org.apache.lucene.gdata.server.GDataResponse;
+import org.apache.lucene.gdata.server.Service;
+import org.apache.lucene.gdata.server.ServiceFactory;
+import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public abstract class AbstractGdataRequestHandler implements
+ GDataRequestHandler {
+ private final static Log LOG = LogFactory
+ .getLog(AbstractGdataRequestHandler.class);
+
+
+ protected GDataRequest feedRequest;
+ protected GDataResponse feedResponse;
+
+ /**
+ * @see org.apache.lucene.gdata.servlet.handler.GDataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ public abstract void processRequest(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException;
+
+ protected void initializeRequestHandler(final HttpServletRequest request, final HttpServletResponse response, final GDataRequestType type)
+ throws GDataRequestException {
+ this.feedRequest = new GDataRequest(request, type);
+ this.feedResponse = new GDataResponse(response);
+ try {
+ this.feedRequest.initializeRequest();
+ } catch (GDataRequestException e) {
+ this.feedResponse.setError(HttpServletResponse.SC_NOT_FOUND);
+ LOG.warn("Couldn't initialize FeedRequest - " + e.getMessage(), e);
+ throw e;
+ }
+ }
+
+
+
+ protected void sendError() throws IOException {
+ this.feedResponse.sendError();
+
+ }
+
+ protected void setFeedResponseFormat() {
+ this.feedResponse.setOutputFormat(this.feedRequest.getRequestedResponseFormat());
+ }
+
+ protected void setFeedResponseStatus(int status) {
+ this.feedResponse.setResponseCode(status);
+ }
+
+ protected void setError(int error) {
+ this.feedResponse.setError(error);
+ }
+
+ protected Service getService() throws ServletException {
+ ServiceFactory serviceFactory = ServiceFactory.getInstance();
+ Service service = serviceFactory.getService();
+ if(service == null)
+ throw new ServletException("Service not available");
+ return service;
+ }
+
+
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/package.html
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/package.html (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/package.html (revision 0)
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+GData Request Handler.
+
+
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/RequestHandlerFactory.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/RequestHandlerFactory.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/RequestHandlerFactory.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.servlet.handler;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public abstract class RequestHandlerFactory {
+
+ private static RequestHandlerFactory INSTANCE = null;
+
+ /**
+ * This method creates a singleton instance of the given type. The fist call
+ * will create an instance of the given class which will be returned in
+ * every subsequent call. Any subsequent call to this method will ignore the
+ * given class object.
+ *
+ * @param factoryImplementation -
+ * the factory implementation (must be a subtype of this Class)
+ *
+ * @return - a singleton instance of the given type
+ *
+ */
+ public static synchronized RequestHandlerFactory getInstance(
+ Class factoryImplementation) {
+ if (INSTANCE == null) {
+
+ INSTANCE = createInstance(factoryImplementation);
+ }
+ return INSTANCE;
+ }
+
+ /**
+ * Singleton - Pattern using private constructor
+ *
+ */
+ RequestHandlerFactory() {
+ super();
+
+ }
+
+ private static RequestHandlerFactory createInstance(
+ final Class qualifiedClass) {
+ if (qualifiedClass == null)
+ throw new IllegalArgumentException(
+ "Factory class is null -- must be a implementation of org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory");
+ try {
+ return (RequestHandlerFactory) qualifiedClass.newInstance();
+ } catch (Exception e) {
+ FactoryImplementationException ex = new FactoryImplementationException(
+ "Factory implementation could not be created", e.getCause());
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ }
+
+ /**
+ * Creates a UpdateHandler which processes a GDATA UPDATE request.
+ * @return - an RequestHandlerInstance
+ */
+ public abstract GDataRequestHandler getUpdateHandler();
+
+ /**
+ * Creates a DeleteHandler which processes a GDATA DELETE request.
+ * @return - an RequestHandlerInstance
+ */
+ public abstract GDataRequestHandler getDeleteHandler();
+
+ /**
+ * Creates a QueryHandler which processes a GDATA Query / Get request.
+ * @return - an RequestHandlerInstance
+ */
+ public abstract GDataRequestHandler getQueryHandler();
+
+ /**
+ * Creates a InsertHandler which processes a GDATA Insert request.
+ * @return - an RequestHandlerInstance
+ */
+ public abstract GDataRequestHandler getInsertHandler();
+
+
+
+ private static class FactoryImplementationException extends
+ RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3166033278825112569L;
+
+ /**
+ * Constructs a new FactoryImplementationException with the specified
+ * cause and message
+ *
+ * @param arg0 -
+ * the detail message
+ * @param arg1 -
+ * the throw cause
+ */
+ public FactoryImplementationException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+
+ }
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/package.html
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/package.html (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/package.html (revision 0)
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+Servlets acting as basic interfaces for gdata requests.
+
+
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java (revision 0)
@@ -0,0 +1,286 @@
+package org.apache.lucene.gdata.storage.lucenestorage;
+
+import java.io.File;
+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.server.registry.GDataServerRegistry;
+import org.apache.lucene.gdata.storage.IDGenerator;
+import org.apache.lucene.gdata.storage.StorageController;
+import org.apache.lucene.gdata.storage.StorageException;
+import org.apache.lucene.gdata.storage.lucenestorage.configuration.StorageConfigurator;
+import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter;
+import org.apache.lucene.index.IndexModifier;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+
+/**
+ * TODO document this
+ * @author Simon Willnauer
+ *
+ */
+public class StorageCoreController implements StorageController{
+ protected static final Log LOG = LogFactory.getLog(StorageCoreController.class);
+ private IndexSearcher searcher;
+ private static StorageCoreController coreController;
+ private final Directory storageDir;
+ private final StorageModifier modifier;
+ private ReferenceCounter storageQuery;
+ private StorageBuffer currentBuffer;
+ private Object storageControllerLock = new Object();
+ private static final int DEFAULT_STORAGE_BUFFER_SIZE = 10;
+ private static final int DEFAULT_STORAGE_PERSIST_FACTOR = 10;
+ private static final String STORAGELOG = ".lucenestorage";
+ private int storageBufferSize;
+ private int storagePersistFactor;
+ private StorageConfigurator configurator;
+ private IDGenerator idGenerator;
+ private int indexOptimizeInterval;
+
+ private StorageCoreController()throws IOException, StorageException{
+ this(null);
+ }
+
+
+
+
+ private StorageCoreController(final Directory dir) throws IOException, StorageException {
+ synchronized (StorageCoreController.class) {
+ try{
+ this.idGenerator = new IDGenerator(10);
+ }catch (Exception e) {
+ throw new StorageException("Can't create ID Generator",e);
+ }
+
+ boolean createNewStorage = false;
+
+ if(dir == null){
+ this.configurator = StorageConfigurator.getStorageConfigurator();
+ String storageDirPath = this.configurator.getStorageDirectory();
+ File storeDir = new File(storageDirPath);
+ File storageLog = new File(storeDir.getAbsolutePath()+System.getProperty("file.separator")+STORAGELOG);
+ try{
+ if(storeDir.isDirectory() && !storageLog.exists()){
+
+ if(createLuceneStorageLog(storeDir)){
+ this.storageDir = FSDirectory.getDirectory(storeDir,true);
+ createNewStorage = true;
+ }
+ else
+ throw new StorageException("could not create storage log file in "+storageDirPath);
+
+ }else
+ this.storageDir = FSDirectory.getDirectory(storeDir,false);
+ }catch (IOException e) {
+ storageLog.delete();
+ throw e;
+ }
+ this.indexOptimizeInterval = this.configurator.getIndexOptimizeInterval();
+ this.storageBufferSize = this.configurator.getStorageBufferSize() < DEFAULT_STORAGE_BUFFER_SIZE?DEFAULT_STORAGE_BUFFER_SIZE:this.configurator.getStorageBufferSize();
+ this.storagePersistFactor = this.configurator.getStoragepersistFactor() < DEFAULT_STORAGE_PERSIST_FACTOR? DEFAULT_STORAGE_PERSIST_FACTOR:this.configurator.getStoragepersistFactor();
+
+ }
+ else
+ this.storageDir = dir;
+
+ this.currentBuffer = new StorageBuffer(this.storageBufferSize);
+ this.modifier = createStorageModifier(createNewStorage);
+ this.searcher = new IndexSearcher(this.storageDir);
+
+
+ GDataServerRegistry.getRegistry().registerStorage(this);// TODO reverse dependency here
+
+
+
+ }
+
+ }
+ private StorageModifier createStorageModifier(boolean create) throws IOException{
+ IndexModifier indexModifier = new IndexModifier(this.storageDir,new StandardAnalyzer(),create);
+ return new StorageModifier(indexModifier,this.currentBuffer,this.storagePersistFactor,this.indexOptimizeInterval);
+ }
+ /**TODO document this
+ * @return
+ */
+ public StorageModifier getStorageModifier(){
+ return this.modifier;
+ }
+
+ /**TODO document this
+ * @return
+ * @throws IOException
+ * @throws StorageException
+ */
+ public static StorageCoreController getStorageCoreController() throws IOException, StorageException{
+ synchronized (StorageCoreController.class) {
+ if(coreController == null)
+ coreController = new StorageCoreController();
+ return coreController;
+ }
+ }
+ /**TODO document this
+ * @param dir
+ * @return
+ * @throws IOException
+ * @throws StorageException
+ */
+ protected static StorageCoreController getStorageCoreController(final Directory dir) throws IOException, StorageException{
+ synchronized (StorageCoreController.class) {
+ if(coreController == null)
+ coreController = new StorageCoreController(dir);
+ return coreController;
+ }
+ }
+
+ /**TODO document this
+ * @return
+ * @throws IOException
+ */
+ public ReferenceCounter getStorageQuery() throws IOException {
+ synchronized (this.storageControllerLock) {
+
+ if(this.storageQuery == null){
+ this.storageQuery = getNewStorageQueryHolder(new StorageQuery(this.currentBuffer,this.searcher));
+ if(LOG.isInfoEnabled())
+ LOG.info("Relese new StorageQuery");
+ }
+ this.storageQuery.increamentReference();
+ return this.storageQuery;
+ }
+ }
+
+ private ReferenceCounter getNewStorageQueryHolder(final StorageQuery query){
+ ReferenceCounter holder = new ReferenceCounter(query){
+ public void close(){
+ try{
+ if(LOG.isInfoEnabled())
+ LOG.info("close StorageQuery -- zero references remaining");
+ this.resource.close();
+ }catch (IOException e) {
+ LOG.warn("Error during close call on StorageQuery"+e.getMessage(),e);
+ }
+ }
+ };
+ holder.increamentReference();
+ return holder;
+ }
+
+
+
+ protected void registerNewStorageQuery() throws IOException{
+ if(LOG.isInfoEnabled())
+ LOG.info("new StorageQuery requested -- create new storage buffer");
+ synchronized (this.storageControllerLock) {
+ if(this.storageQuery != null)
+ this.storageQuery.decrementRef();
+ this.searcher = new IndexSearcher(this.storageDir);
+ this.storageQuery = null;
+ this.currentBuffer = new StorageBuffer(this.storageBufferSize);
+
+ }
+
+ }
+
+
+ protected StorageBuffer releaseNewStorageBuffer() {
+ synchronized (this.storageControllerLock) {
+ return this.currentBuffer;
+ }
+ }
+
+ /**TODO document this
+ * @return
+ * @throws IOException
+ */
+ public IndexModifier createIndexModifier() throws IOException {
+ if(LOG.isInfoEnabled())
+ LOG.info("new IndexModifier created - release to StorageModifier");
+ synchronized (this.storageControllerLock) {
+ return new IndexModifier(this.storageDir,new StandardAnalyzer(),false);
+ }
+ }
+
+ private void close() throws IOException{
+ synchronized (this.storageControllerLock) {
+ if(LOG.isInfoEnabled())
+ LOG.info("StorageController has been closed -- server is shutting down -- release all resources");
+ if(this.storageQuery != null)
+ this.storageQuery.decrementRef();
+ coreController = null;
+ this.modifier.close();
+ //TODO make sure all resources will be released
+ }
+ }
+ /**TODO document this
+ * @return
+ */
+ public int getStorageBufferSize() {
+ return this.storageBufferSize;
+ }
+ /**
+ * @param storageBufferSize
+ */
+ public void setStorageBufferSize(int storageBufferSize) {
+ this.storageBufferSize = storageBufferSize;
+ }
+ /**TODO document this
+ * @return
+ */
+ public int getStoragePersistFactor() {
+ return this.storagePersistFactor;
+ }
+ /**
+ * @param storagePersistFactor
+ */
+ public void setStoragePersistFactor(int storagePersistFactor) {
+ this.storagePersistFactor = storagePersistFactor;
+ }
+ /**
+ * @throws IOException
+ * @throws StorageException
+ */
+ public void forceWrite()throws IOException, StorageException{
+ this.modifier.forceWrite();
+ }
+
+
+ private boolean createLuceneStorageLog(File storageDirectory) throws IOException{
+ if(storageDirectory.isDirectory() && !storageDirectory.exists()){
+ storageDirectory.createNewFile();
+ }
+ File file = new File(storageDirectory.getAbsolutePath()+System.getProperty("file.separator")+STORAGELOG);
+ return file.createNewFile();
+
+
+ }
+
+
+ /**TODO document this
+ * @return
+ * @throws StorageException
+ */
+ public synchronized String releaseID() throws StorageException{
+ try{
+ return this.idGenerator.getUID();
+ }catch (InterruptedException e) {
+ throw new StorageException("Can't release new ID",e);
+ }
+
+ }
+
+
+
+ /**
+ * @see org.apache.lucene.gdata.storage.StorageController#destroy()
+ */
+ public void destroy() {
+ try{
+ close();
+ }catch (Exception e) {
+ LOG.error("Closing StorageCoreController failed -- "+e.getMessage(),e);
+ }
+ }
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageModifier.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageModifier.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageModifier.java (revision 0)
@@ -0,0 +1,236 @@
+package org.apache.lucene.gdata.storage.lucenestorage;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.gdata.storage.StorageException;
+import org.apache.lucene.index.IndexModifier;
+import org.apache.lucene.index.Term;
+
+/**
+ * TODO document this
+ * @author Simon Willnauer
+ *
+ */
+public class StorageModifier {
+ protected static final Log LOG = LogFactory.getLog(StorageModifier.class);
+
+ private final List deletedDocumentQueue;
+ private final List deletedForUpdateDocumentQueue;
+
+ private final Map documentMap;
+
+
+ private volatile int persistFactor;
+
+ private volatile int modifiedCounter = 0;
+
+ private static int DEFAULT_PERSIST_FACTOR = 10;
+
+ private StorageBuffer buffer;
+
+ private IndexModifier modifier;
+
+ private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false);
+
+ private Lock readLock = this.lock.readLock();
+
+ private Lock writeLock = this.lock.writeLock();
+ private final static int DEFAULT_OPTIMIZE_INTERVAL = 10;
+ private final int optimizeInterval;
+ private int optimizeCounter = 0;
+
+ /**
+ * TODO document this
+ * @param modifier
+ * @param buffer
+ * @param persitsFactor
+ * @param optimizeInterval
+ */
+ public StorageModifier(final IndexModifier modifier,
+ final StorageBuffer buffer, int persitsFactor,int optimizeInterval) {
+ this.deletedDocumentQueue = new LinkedList();
+ this.deletedForUpdateDocumentQueue = new LinkedList();
+ this.documentMap = new HashMap(persitsFactor);
+ this.buffer = buffer;
+
+ this.persistFactor = persitsFactor > 0 ? persitsFactor
+ : DEFAULT_PERSIST_FACTOR;
+ this.modifier = modifier;
+ this.optimizeInterval = optimizeInterval < DEFAULT_OPTIMIZE_INTERVAL?DEFAULT_OPTIMIZE_INTERVAL:optimizeInterval;
+
+ }
+
+ /**
+ * TODO document this
+ * @param wrapper
+ * @throws StorageException
+ */
+ public void updateEntry(StorageEntryWrapper wrapper)
+ throws StorageException {
+ try {
+ this.readLock.lock();
+ Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID, wrapper.getEntryId());
+ this.buffer.addEntry(wrapper);
+ this.deletedForUpdateDocumentQueue.add(tempTerm);
+ this.documentMap.put(wrapper.getEntryId(),wrapper.getLuceneDocument());
+ storageModified();
+ } finally {
+ this.readLock.unlock();
+ }
+ }
+
+ /**
+ * TODO document this
+ * @param wrapper
+ * @throws StorageException
+ */
+ public void insertEntry(StorageEntryWrapper wrapper) throws StorageException {
+ this.readLock.lock();
+ try {
+
+ this.buffer.addEntry(wrapper);
+ this.documentMap.put(wrapper.getEntryId(),wrapper.getLuceneDocument());
+ storageModified();
+ } finally {
+ this.readLock.unlock();
+ }
+ }
+
+ /**
+ *TODO document this
+ * @param entryId
+ * @param feedId
+ * @throws StorageException
+ *
+ */
+ public void deleteEntry(final String entryId, final String feedId) throws StorageException {
+ try {
+ this.readLock.lock();
+ Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID, entryId);
+ this.buffer.addDeleted(entryId, feedId);
+ this.deletedDocumentQueue.add(tempTerm);
+ storageModified();
+ } finally {
+ this.readLock.unlock();
+ }
+ }
+
+ private void storageModified() throws StorageException {
+ this.readLock.unlock();
+ this.writeLock.lock();
+
+ try {
+ incrementCounter();
+ if (this.persistFactor > this.modifiedCounter)
+ return;
+
+ if (LOG.isInfoEnabled())
+ LOG.info("Storage modified for " + this.modifiedCounter
+ + " times. Write Persistent index");
+ writePersistentIndex((this.optimizeCounter >= this.optimizeInterval));
+ requestNewIndexModifier();
+
+ this.modifiedCounter = 0;
+ } catch (IOException e) {
+ LOG.error("Writing persistent index failed - Recovering", e);
+ } finally {
+ this.readLock.lock();
+ this.writeLock.unlock();
+ }
+
+ }
+
+ protected void forceWrite() throws IOException, StorageException {
+ this.writeLock.lock();
+ try {
+ if (LOG.isInfoEnabled())
+ LOG.info("ForceWrite called -- current modifiedCounter: "
+ + this.modifiedCounter + " - persisting changes");
+ writePersistentIndex(true);
+ requestNewIndexModifier();
+ this.modifiedCounter = 0;
+ } finally {
+ this.writeLock.unlock();
+ }
+ }
+
+ private void requestNewIndexModifier() throws IOException, StorageException {
+ StorageCoreController controller = StorageCoreController
+ .getStorageCoreController();
+ controller.registerNewStorageQuery();
+ this.buffer = controller.releaseNewStorageBuffer();
+ this.modifier = controller.createIndexModifier();
+ }
+
+ private void writePersistentIndex(final boolean optimize) throws IOException {
+ try {
+ /*
+ * first delete all updated documents
+ */
+ for(Term entryIdTerm : this.deletedForUpdateDocumentQueue) {
+ this.modifier.deleteDocuments(entryIdTerm);
+ }
+ /*
+ * add all documents
+ */
+ Collection documents = this.documentMap.values();
+ for (Document doc : documents) {
+ this.modifier.addDocument(doc);
+ }
+ /*
+ * delete all documents marked as deleted. As the DocumentIDs are
+ * unique the document marked as deleted must not persist after the
+ * index has been written.
+ * In the case of an update of a document and a previous delete the concurrency component will not allow an update.
+ * new inserted entries can not be deleted accidently-
+ */
+ for (Term entryIdTerm : this.deletedDocumentQueue) {
+ this.modifier.deleteDocuments(entryIdTerm);
+ }
+ this.modifier.flush();
+ if(optimize){
+ if(LOG.isInfoEnabled())
+ LOG.info("Optimizing index -- optimize interval "+this.optimizeInterval);
+ this.modifier.optimize();
+ }
+
+ } finally {
+ if(optimize)
+ this.optimizeCounter = 0;
+ this.modifier.close();
+ this.deletedForUpdateDocumentQueue.clear();
+ this.deletedDocumentQueue.clear();
+ this.documentMap.clear();
+ }
+ }
+
+ protected void close()throws IOException{
+ this.writeLock.lock();
+ try {
+ if (LOG.isInfoEnabled())
+ LOG.info("ForceWrite called -- current modifiedCounter: "
+ + this.modifiedCounter + " - persisting changes");
+
+ writePersistentIndex(true);
+ this.modifiedCounter = 0;
+ } finally {
+ this.writeLock.unlock();
+ }
+ }
+
+ private void incrementCounter(){
+ this.optimizeCounter++;
+ this.modifiedCounter++;
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageEntryWrapper.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageEntryWrapper.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageEntryWrapper.java (revision 0)
@@ -0,0 +1,188 @@
+/**
+ * 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.IOException;
+import java.io.StringWriter;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.ExtensionProfile;
+import com.google.gdata.util.common.xml.XmlWriter;
+
+/**
+ * This immutable class wrapps Entries for an internal Storage representation of
+ * an entry. This class also acts as a Documentfactory for lucene documents to
+ * be stored inside the index.
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class StorageEntryWrapper implements Comparable {
+ private static final String INTERNAL_ENCODING = "UTF-8";
+
+ /**
+ * lucene field name Entry id
+ */
+ public final static String FIELD_ENTRY_ID = "entryId";
+
+ /**
+ * lucene field name feed id
+ */
+ public final static String FIELD_FEED_ID = "feedId";
+
+ /**
+ * lucene field name entry content
+ */
+ public final static String FIELD_CONTENT = "content";
+
+ /**
+ * lucene field name creating timestamp
+ */
+ public final static String FIELD_TIMESTAMP = "timestamp";
+
+ private final String entryId;
+
+ private final String feedId;
+
+ private final String content;
+
+ private final transient BaseEntry entry;
+
+ private final Long timestamp;
+
+ private transient Document document;
+
+ private StorageOperation operation;
+
+ private final ExtensionProfile profile;
+
+ /**
+ * Creates a new StorageEntryWrapper.
+ *
+ * @param entry -
+ * the entry to wrap
+ * @param feedId -
+ * the feed id
+ * @param operation -
+ * the StorageOperation
+ * @param profile -
+ * the ExtensionProfil for the given entry
+ * @throws IOException -
+ * if the entry content can not be generated
+ */
+ protected StorageEntryWrapper(final BaseEntry entry, final String feedId,
+ StorageOperation operation, final ExtensionProfile profile)
+ throws IOException {
+ this.entry = entry;
+ this.operation = operation;
+ this.entryId = entry.getId();
+ this.feedId = feedId;
+ this.profile = profile;
+ this.content = buildContent();
+ this.timestamp = new Long(System.currentTimeMillis());
+
+ }
+
+ private String buildContent() throws IOException {
+ StringWriter writer = new StringWriter();
+ XmlWriter xmlWriter = new XmlWriter(writer, INTERNAL_ENCODING);
+ this.entry.generateAtom(xmlWriter, this.profile);
+ return writer.toString();
+
+ }
+
+ /**
+ * @return - the lucene document representing the entry
+ */
+ public Document getLuceneDocument() {
+ if (this.document != null)
+ return this.document;
+ this.document = new Document();
+ this.document.add(new Field("entryId", this.entryId, Field.Store.YES,
+ Field.Index.UN_TOKENIZED));
+ this.document.add(new Field("feedId", this.feedId, Field.Store.YES,
+ Field.Index.UN_TOKENIZED));
+ this.document.add(new Field("content", this.content,
+ Field.Store.COMPRESS, Field.Index.UN_TOKENIZED));
+ this.document.add(new Field("timestamp", this.timestamp.toString(),
+ Field.Store.YES, Field.Index.UN_TOKENIZED));
+
+ return this.document;
+
+ }
+
+ /**
+ * @return - the wrapped entry
+ */
+ public BaseEntry getEntry() {
+ return this.entry;
+ }
+
+ /**
+ * @return - the entry id
+ */
+ public String getEntryId() {
+ return this.entryId;
+ }
+
+ /**
+ * @return - the feed id
+ */
+ public String getFeedId() {
+ return this.feedId;
+ }
+
+ /**
+ * Storage operations
+ *
+ * @author Simon Willnauer
+ *
+ */
+ public static enum StorageOperation {
+ /**
+ * delete
+ */
+ DELETE,
+ /**
+ * update
+ */
+ UPDATE,
+ /**
+ * insert
+ */
+ INSERT
+ }
+
+ /**
+ * @return the specified storage operation
+ */
+ public StorageOperation getOperation() {
+ return this.operation;
+ }
+
+ /**
+ * @see java.lang.Comparable#compareTo(T)
+ */
+ public int compareTo(StorageEntryWrapper arg0) {
+ return arg0.timestamp == this.timestamp ? 0
+ : (arg0.timestamp > this.timestamp ? 1 : -1);
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/configuration/StorageConfigurator.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/configuration/StorageConfigurator.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/configuration/StorageConfigurator.java (revision 0)
@@ -0,0 +1,144 @@
+/**
+ * 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.configuration;
+
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * This clas loads the Storage configuration file and sets all properties. If
+ * the properties can not be loaded an {@link java.lang.Error} will be thrown.
+ * The configuration file lucenestorage.properties.xml should be available in the classpath.
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class StorageConfigurator {
+ private final int storageBufferSize;
+
+ private final int storagepersistFactor;
+
+ private final String storageDirectory;
+
+ private final boolean keepRecoveredFiles;
+
+ private final boolean recover;
+
+ private static StorageConfigurator INSTANCE = null;
+
+ private final int indexOptimizeInterval;
+
+ private StorageConfigurator() {
+ InputStream stream = StorageConfigurator.class
+ .getResourceAsStream("/lucenestorage.properties.xml");
+ Properties properties = new Properties();
+ try {
+ properties.loadFromXML(stream);
+
+ } catch (Exception e) {
+ throw new StorageConfigurationError("Could not load properties", e);
+ }
+ this.storageBufferSize = Integer.parseInt(properties
+ .getProperty("gdata.server.storage.lucene.buffersize"));
+ this.storagepersistFactor = Integer.parseInt(properties
+ .getProperty("gdata.server.storage.lucene.persistFactor"));
+ this.recover = Boolean.parseBoolean(properties
+ .getProperty("gdata.server.storage.lucene.recover"));
+ this.keepRecoveredFiles = Boolean.parseBoolean(properties
+ .getProperty("gdata.server.storage.lucene.recover.keepFiles"));
+ this.storageDirectory = properties
+ .getProperty("gdata.server.storage.lucene.directory");
+ this.indexOptimizeInterval = Integer.parseInt(properties
+ .getProperty("gdata.server.storage.lucene.optimizeInterval"));
+
+ }
+
+ /**
+ * @return - the storage configurator
+ */
+ public static synchronized StorageConfigurator getStorageConfigurator() {
+ if (INSTANCE == null)
+ INSTANCE = new StorageConfigurator();
+ return INSTANCE;
+ }
+
+ /**
+ * Keep recovering files. -- will use a lot of disk space
+ *
+ * @return true if the storage is supposed to keep the
+ * recovering files.
+ */
+ public boolean isKeepRecoveredFiles() {
+ return this.keepRecoveredFiles;
+ }
+
+ /**
+ * @return true if the storage is supposed to use recovering.
+ * @see org.apache.lucene.gdata.storage.lucenestorage.StorageModifier
+ */
+ public boolean isRecover() {
+ return this.recover;
+ }
+
+ /**
+ * @return - the configured storage buffer size
+ * @see org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer
+ */
+ public int getStorageBufferSize() {
+ return this.storageBufferSize;
+ }
+
+ /**
+ * @return - the configured storage directory
+ * @see org.apache.lucene.gdata.storage.lucenestorage.StorageModifier
+ */
+ public String getStorageDirectory() {
+ return this.storageDirectory;
+ }
+
+ /**
+ * @return - the persist factor
+ * @see org.apache.lucene.gdata.storage.lucenestorage.StorageModifier
+ */
+ public int getStoragepersistFactor() {
+ return this.storagepersistFactor;
+ }
+
+ protected class StorageConfigurationError extends Error {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 5261674332036111464L;
+
+ protected StorageConfigurationError(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+
+ }
+
+ }
+
+ /**
+ * @return - the optimize interval
+ * @see org.apache.lucene.gdata.storage.lucenestorage.StorageModifier
+ */
+ public int getIndexOptimizeInterval() {
+
+ return this.indexOptimizeInterval;
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/configuration/package.html
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/configuration/package.html (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/configuration/package.html (revision 0)
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+Lucene Storage utils
+
+
Property changes on: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/configuration/package.html
___________________________________________________________________
Name: svn:executable
+ *
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/ModifiedEntryFilter.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/ModifiedEntryFilter.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/ModifiedEntryFilter.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.storage.lucenestorage;
+
+import java.io.IOException;
+import java.util.BitSet;
+import java.util.List;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermDocs;
+import org.apache.lucene.search.Filter;
+
+/**
+ * The {@link ModifiedEntryFilter} filters the given entryIds from the lucene
+ * {@link org.apache.lucene.search.Hits} set. This filter is used to prevent the
+ * storage from retrieving already deleted or updated entries still remainig in
+ * the {@link org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer}.
+ *
+ * @see org.apache.lucene.search.Filter
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class ModifiedEntryFilter extends Filter {
+ /**
+ * impl Serializable
+ */
+ private static final long serialVersionUID = -1551686287704213591L;
+
+ private final List entyIds;
+
+ /**
+ * Creates a new {@link ModifiedEntryFilter}
+ * @param entryIds the entry id's to filter
+ *
+ */
+ public ModifiedEntryFilter(List entryIds) {
+ super();
+ this.entyIds = entryIds;
+ }
+
+ /**
+ * @see org.apache.lucene.search.Filter#bits(org.apache.lucene.index.IndexReader)
+ */
+ @Override
+ public BitSet bits(IndexReader reader) throws IOException {
+ BitSet bitSet = new BitSet(reader.maxDoc());
+ bitSet.flip(0, reader.maxDoc()); // set all docs
+ int[] docs = new int[1];
+ int[] freq = new int[1];
+ for (String id : this.entyIds) {
+ if (id != null) {
+ TermDocs termDocs = reader.termDocs(new Term(
+ StorageEntryWrapper.FIELD_ENTRY_ID, id));
+ int count = termDocs.read(docs, freq);
+ if (count == 1)
+ bitSet.flip(docs[0]);
+
+ }
+ }
+
+ return bitSet;
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageImplementation.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageImplementation.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageImplementation.java (revision 0)
@@ -0,0 +1,259 @@
+/**
+ * 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.IOException;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.storage.Storage;
+import org.apache.lucene.gdata.storage.StorageException;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
+import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.BaseFeed;
+import com.google.gdata.data.ExtensionProfile;
+import com.google.gdata.data.Feed;
+
+/**
+ * This is an implementation of the
+ * {@link org.apache.lucene.gdata.storage.Storage} interface. The
+ * StorageImplementation provides access to the
+ * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageQuery} and the
+ * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageModifier}. This
+ * class will be instanciated per client request.
+ *
+ *
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class StorageImplementation implements Storage {
+ private final StorageCoreController controller;
+
+ private ExtensionProfile profile;
+
+ private static final Log LOG = LogFactory
+ .getLog(StorageImplementation.class);
+
+ /**
+ * Creates a new StorageImplementation
+ *
+ * @throws StorageException -
+ * if the
+ * {@link org.apache.lucene.gdata.storage.StorageController} can
+ * not be created
+ * @throws IOException -
+ * if the
+ * {@link org.apache.lucene.gdata.storage.StorageController} can
+ * not be created
+ * @see StorageCoreController#getStorageCoreController()
+ *
+ */
+ public StorageImplementation() throws IOException, StorageException {
+ this.controller = StorageCoreController.getStorageCoreController();
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.storage.Storage#storeEntry(com.google.gdata.data.BaseEntry,
+ * java.lang.String)
+ */
+ public BaseEntry storeEntry(BaseEntry entry, String feedId)
+ throws StorageException {
+ if (this.profile == null)
+ throw new StorageException(
+ "Can process ExtensionProfile not set -- is null");
+ if (feedId == null)
+ throw new StorageException("No feed ID specified -- is null");
+ StorageModifier modifier = this.controller.getStorageModifier();
+ String id = this.controller.releaseID();
+ entry.setId(feedId + id);
+ if (LOG.isInfoEnabled())
+ LOG.info("Store entry " + id + " -- feed: " + feedId);
+
+ try {
+ StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,
+ feedId, StorageOperation.INSERT, this.profile);
+ modifier.insertEntry(wrapper);
+ } catch (IOException e) {
+ StorageException ex = new StorageException("Can't create Entry -- "
+ + e.getMessage(), e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+
+ }
+
+ return entry;
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.storage.Storage#deleteEntry(java.lang.String,
+ * java.lang.String)
+ */
+ public void deleteEntry(String entryId, String feedId)
+ throws StorageException {
+ if (this.profile == null)
+ throw new StorageException(
+ "Can process ExtensionProfile not set -- is null");
+ if (feedId == null)
+ throw new StorageException("No feed ID specified -- is null");
+ if (entryId == null)
+ throw new StorageException("No entry ID specified -- is null");
+ if (LOG.isInfoEnabled())
+ LOG.info("delete entry " + entryId + " -- feed: " + feedId);
+ StorageModifier modifier = this.controller.getStorageModifier();
+ modifier.deleteEntry(entryId, feedId);
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.storage.Storage#updateEntry(com.google.gdata.data.BaseEntry,
+ * java.lang.String)
+ */
+ public BaseEntry updateEntry(BaseEntry entry, String feedId)
+ throws StorageException {
+ if (this.profile == null)
+ throw new StorageException(
+ "Can process ExtensionProfile not set -- is null");
+ if (feedId == null)
+ throw new StorageException("No feed ID specified -- is null");
+ if (entry == null)
+ throw new StorageException("enrty is null");
+ if (entry.getId() == null)
+ throw new StorageException("No entry ID specified -- is null");
+ if (LOG.isInfoEnabled())
+ LOG.info("update entry " + entry.getId() + " -- feed: " + feedId);
+ StorageModifier modifier = this.controller.getStorageModifier();
+
+ try {
+ StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,
+ feedId, StorageOperation.UPDATE, this.profile);
+ modifier.updateEntry(wrapper);
+ } catch (IOException e) {
+ LOG.error("Can't update entry for feedID: " + feedId
+ + "; entryId: " + entry.getId() + " -- " + e.getMessage(),
+ e);
+ StorageException ex = new StorageException("Can't create Entry -- "
+ + e.getMessage(), e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+
+ }
+
+ return entry;
+
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.storage.Storage#getFeed(java.lang.String,
+ * int, int)
+ */
+ @SuppressWarnings("unchecked")
+ public BaseFeed getFeed(String feedId, int startIndex, int resultCount)
+ throws StorageException {
+ if (this.profile == null)
+ throw new StorageException(
+ "Can process ExtensionProfile not set -- is null");
+ if (feedId == null)
+ throw new StorageException("No feed ID specified -- is null");
+ if (LOG.isInfoEnabled())
+ LOG.info("get feed: " + feedId + " startindex: " + startIndex
+ + " resultCount: " + resultCount);
+ ReferenceCounter query = null;
+ try {
+ query = this.controller.getStorageQuery();
+ List resultList = query.get().getLatestFeedQuery(feedId,
+ resultCount, startIndex, this.profile);
+ BaseFeed feed = new Feed();
+ feed.getEntries().addAll(resultList);
+ return feed;
+ } catch (Exception e) {
+ LOG.error("Can't get latest feed for feedID: " + feedId + " -- "
+ + e.getMessage(), e);
+ StorageException ex = new StorageException("Can't create Entry -- "
+ + e.getMessage(), e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+
+ } finally {
+ if (query != null)
+ query.decrementRef();
+ }
+
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.storage.Storage#getEntry(java.lang.String,
+ * java.lang.String)
+ */
+ public BaseEntry getEntry(String entryId, String feedId)
+ throws StorageException {
+ if (this.profile == null)
+ throw new StorageException(
+ "Can process ExtensionProfile not set -- is null");
+ if (feedId == null)
+ throw new StorageException("No feed ID specified -- is null");
+ if (entryId == null)
+ throw new StorageException("No entry ID specified -- is null");
+ if (LOG.isInfoEnabled())
+ LOG.info("get entry " + entryId + " -- feed: " + feedId);
+ ReferenceCounter query = null;
+ try {
+ query = this.controller.getStorageQuery();
+ return query.get().singleEntryQuery(entryId, feedId, this.profile);
+ } catch (Exception e) {
+ LOG.error("Can't get entry for feedID: " + feedId + "; entryId: "
+ + entryId + " -- " + e.getMessage(), e);
+ StorageException ex = new StorageException("Can't create Entry -- "
+ + e.getMessage(), e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+
+ } finally {
+ if (query != null)
+ query.decrementRef();
+ }
+
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.storage.Storage#getEntries(java.util.List,
+ * java.lang.String)
+ */
+ public List getEntries(List entryIdList, String feedId)
+ throws StorageException {
+ throw new StorageException("not implemented yet");
+ // TODO implement this
+
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.storage.Storage#close()
+ */
+ public void close() {
+ //
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.storage.Storage#setExtensionProfile(com.google.gdata.data.ExtensionProfile)
+ */
+ public void setExtensionProfile(ExtensionProfile profile) {
+ this.profile = profile;
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageQuery.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageQuery.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageQuery.java (revision 0)
@@ -0,0 +1,342 @@
+/**
+ * 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.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.gdata.server.FeedNotFoundException;
+import org.apache.lucene.gdata.server.GDataEntityBuilder;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Hit;
+import org.apache.lucene.search.Hits;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.BooleanClause.Occur;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.ExtensionProfile;
+import com.google.gdata.util.ParseException;
+
+/**
+ * StorageQuery wrapps a Lucene {@link org.apache.lucene.search.IndexSearcher}
+ * and a {@link org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer} to
+ * perform all request on the lucene storage.
+ * The wrapped components are thread - safe.
+ *
+ * An instance of this class will serve all client requests. To obtain the
+ * current instance of the {@link StorageQuery} the method
+ * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#getStorageQuery()}
+ * has to be invoked. This method will release the current StorageQuery.
+ *
+ * @see org.apache.lucene.search.IndexSearcher
+ * @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController
+ * @see org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class StorageQuery {
+ private final StorageBuffer buffer;
+
+ private final Searcher searcher;
+
+ /*
+ * Sort the result by timestamp desc
+ */
+ private final Sort timeStampSort = new Sort(new SortField(StorageEntryWrapper.FIELD_TIMESTAMP,
+ SortField.STRING, true));
+
+ /**
+ * Creates a new StorageQuery
+ *
+ * @param buffer -
+ * the buffer instance to get the buffered inserts, updates from.
+ * @param searcher -
+ * the searcher instance to use to query the storage index.
+ *
+ *
+ */
+ protected StorageQuery(final StorageBuffer buffer, final Searcher searcher) {
+
+ this.buffer = buffer;
+ this.searcher = searcher;
+
+ }
+
+ private Hits storageQuery(List entryId) throws IOException {
+ BooleanQuery query = new BooleanQuery();
+ /*
+ * query the index using a BooleanQuery
+ */
+ for (String id : entryId) {
+ TermQuery termQuery = new TermQuery(new Term(
+ StorageEntryWrapper.FIELD_ENTRY_ID, id));
+ // use an OR query
+ query.add(new BooleanClause(termQuery, Occur.SHOULD));
+ }
+
+ return this.searcher.search(query, new ModifiedEntryFilter(this.buffer
+ .getExculdList()));
+ }
+
+ /*
+ * query the storage index for a entire feed.
+ */
+ private Hits storageFeedQuery(final String feedId, final Sort sort)
+ throws IOException {
+ TermQuery query = new TermQuery(new Term(StorageEntryWrapper.FIELD_FEED_ID, feedId));
+ return this.searcher.search(query, new ModifiedEntryFilter(this.buffer
+ .getExculdList()), sort);
+
+ }
+
+ /*
+ * get a single entry
+ */
+ private Hits storageQuery(String entryId) throws IOException {
+ TermQuery termQuery = new TermQuery(new Term(
+ StorageEntryWrapper.FIELD_ENTRY_ID, entryId));
+ /*
+ * Filter entries inside the buffer, buffered entries might contain
+ * deleted entries. These entries must be found!!
+ */
+ return this.searcher.search(termQuery, new ModifiedEntryFilter(
+ this.buffer.getExculdList()));
+
+ }
+
+ /**
+ * This method fetches the latest feed entries from the storage. Feed
+ * ususaly requested via a search query or as a simple query to the REST
+ * interface.
+ *
+ * The REST interface requestes all the entries from a Storage. The Storage
+ * retrieves the entries corresponding to the parameters specified. This
+ * method first requests the latest entries or updated entries from the
+ * {@link StorageBuffer}. If the buffer already contains enought entries
+ * for the the specified result count the entires will be returned. If not,
+ * the underlaying lucene index will be searcher for all documents of the
+ * specified feed sorted by storing timestamp desc.
+ *
+ *
+ * The entries will be searched in a feed context specified by the given
+ * feed ID
+ *
+ *
+ *
+ * @param feedId -
+ * the requested feed, this id will be used to retrieve the
+ * entries.
+ * @param resultCount -
+ * how many entries are requested
+ * @param startIndex -
+ * the offset of the entriy to start from.
+ * @param profil -
+ * the extension profile used to create the entriy instances
+ * @return - an ordered list of {@link BaseEntry} objects, or an empty list
+ * if no entries could be found
+ * @throws IOException -
+ * if the index could not be queries or the entries could not be
+ * build
+ * @throws FeedNotFoundException -
+ * if the requested feed is not registered
+ * @throws ParseException -
+ * if an entry could not be parsed while building it from the
+ * Lucene Document.
+ */
+ // TODO check input parameter
+ public List getLatestFeedQuery(final String feedId,
+ final int resultCount, final int startIndex,
+ final ExtensionProfile profil) throws IOException,
+ FeedNotFoundException, ParseException {
+ List returnList = new ArrayList(resultCount);
+ List bufferedWrapperList = this.buffer
+ .getSortedEntries(feedId);
+ int alreadyAdded = 0;
+ int offset = startIndex - 1;
+ if (bufferedWrapperList != null
+ && bufferedWrapperList.size() >= startIndex) {
+
+ for (; alreadyAdded < resultCount; alreadyAdded++) {
+ if ((bufferedWrapperList.size() - offset) > 0) {
+ StorageEntryWrapper wrappedEntry = bufferedWrapperList
+ .get(offset++);
+ returnList.add(wrappedEntry.getEntry());
+ } else
+ break;
+ }
+ // reset offset
+ offset = startIndex - 1;
+ if (alreadyAdded == resultCount)
+ return returnList;
+ } else {
+ /*
+ * if the buffersize is less than the startindex the buffersize must
+ * be considered. Sublists would not be a repeatable read part of
+ * the whole list
+ */
+ if (bufferedWrapperList != null)
+ offset = startIndex - 1 - bufferedWrapperList.size();
+ }
+
+ Hits hits = storageFeedQuery(feedId, this.timeStampSort);
+ if (hits.length() > 0) {
+
+ for (; (offset < hits.length()) && (alreadyAdded < resultCount); offset++, alreadyAdded++) {
+ Document doc = hits.doc(offset);
+ BaseEntry entry = buildEntryFromLuceneDocument(doc, profil);
+ returnList.add(entry);
+ }
+
+ }
+ return returnList;
+ }
+
+ /**
+ * This method retrieves a single entry from the storage. If the
+ * {@link StorageBuffer} does not contain the requested entry the
+ * underlaying storage index will be searched.
+ *
+ * The Entry will be searched in a feed context specified by the given feed
+ * ID
+ *
+ *
+ * @param entryId -
+ * the entry to fetch
+ * @param feedId -
+ * the feedid eg. feed context
+ * @param profil -
+ * the extension profile used to create the entriy instances
+ * @return - the requested {@link BaseEntry} or null if the
+ * entry can not be found
+ * @throws IOException -
+ * if the index could not be queries or the entries could not be
+ * build
+ * @throws FeedNotFoundException -
+ * if the requested feed is not registered
+ * @throws ParseException -
+ * if an entry could not be parsed while building it from the
+ * Lucene Document.
+ */
+ public BaseEntry singleEntryQuery(final String entryId,
+ final String feedId, final ExtensionProfile profil)
+ throws IOException, FeedNotFoundException, ParseException {
+ StorageEntryWrapper wrapper = this.buffer.getEntry(entryId, feedId);
+
+ if (wrapper == null) {
+ Hits hits = storageQuery(entryId);
+ if (hits.length() <= 0)
+ return null;
+ Document doc = hits.doc(0);
+
+ return buildEntryFromLuceneDocument(doc, profil);
+ }
+ return wrapper.getEntry();
+
+ }
+
+ /**
+ * Fetches the requested entries from the storage. The given list contains
+ * entry ids to be looked up in the storage. First the {@link StorageBuffer}
+ * will be queried for the entry ids. If not all of the entries remain in
+ * the buffer the underlaying lucene index will be searched. The entries are
+ * not guaranteed to be in the same order as they are in the given id list.
+ * Entry ID's not found in the index or the buffer will be omitted.
+ *
+ * The entries will be searched in a feed context specified by the given
+ * feed ID
+ *
+ *
+ * @param entryIds -
+ * the entriy ids to fetch.
+ * @param feedId -
+ * the feed id eg. feed context.
+ * @param profil -
+ * the extension profile used to create the entry instances.
+ * @return - the list of entries corresponding to the given entry id list.
+ * @throws IOException -
+ * if the index could not be queries or the entries could not be
+ * build
+ * @throws FeedNotFoundException -
+ * if the requested feed is not registered
+ * @throws ParseException -
+ * if an entry could not be parsed while building it from the
+ * Lucene Document.
+ */
+ public List entryQuery(List entryIds,
+ final String feedId, final ExtensionProfile profil)
+ throws IOException, FeedNotFoundException, ParseException {
+ List resultList = new ArrayList(entryIds.size());
+ List searchList = new ArrayList(entryIds.size());
+ for (String entry : entryIds) {
+
+ StorageEntryWrapper bufferedEntry = this.buffer.getEntry(entry,
+ feedId);
+ if (bufferedEntry != null) {
+ resultList.add(bufferedEntry.getEntry());
+ } else
+ searchList.add(entry);
+ }
+ if (searchList.isEmpty())
+ return resultList;
+
+ Hits hits = storageQuery(searchList);
+ Iterator hitIterator = hits.iterator();
+ while (hitIterator.hasNext()) {
+ Hit hit = (Hit) hitIterator.next();
+ Document doc = hit.getDocument();
+ BaseEntry entry = buildEntryFromLuceneDocument(doc, profil);
+ resultList.add(entry);
+
+ }
+
+ return resultList;
+
+ }
+
+ private BaseEntry buildEntryFromLuceneDocument(final Document doc,
+ final ExtensionProfile profil) throws FeedNotFoundException,
+ ParseException, IOException {
+ StringReader reader = new StringReader(doc.getField(StorageEntryWrapper.FIELD_CONTENT)
+ .stringValue());
+ return GDataEntityBuilder.buildEntry(doc.getField(StorageEntryWrapper.FIELD_FEED_ID)
+ .stringValue(), reader, profil);
+
+ }
+
+ /**
+ * Closes all resources used in the {@link StorageQuery}. The instance can
+ * not be reused after invoking this method.
+ *
+ * @throws IOException -
+ * if the resouces can not be closed
+ */
+ public void close() throws IOException {
+ this.searcher.close();
+ this.buffer.close();
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/util/ReferenceCounter.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/util/ReferenceCounter.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/util/ReferenceCounter.java (revision 0)
@@ -0,0 +1,77 @@
+/**
+ * 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.util;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A reference counting utility. This is use to keep track of released objects
+ * of Type.
+ *
+ * @author Simon Willnauer
+ * @param -
+ * the type of the object
+ *
+ */
+public abstract class ReferenceCounter {
+ protected final Type resource;
+
+ private AtomicInteger refcounter = new AtomicInteger();
+
+ /**
+ * @param resource -
+ * the resouce to track
+ *
+ */
+ public ReferenceCounter(Type resource) {
+ this.resource = resource;
+ }
+
+ /**
+ *
+ * Decrements the reference. If no references remain the
+ * {@link ReferenceCounter#close()} method will be inoked;
+ */
+ public final void decrementRef() {
+ if (this.refcounter.decrementAndGet() == 0)
+ close();
+ }
+
+ /**
+ * A custom implementation. Performs an action if no reference remaining
+ *
+ */
+ protected abstract void close();
+
+ /**
+ * Increments the reference
+ *
+ * @return the refernece object
+ */
+ public final ReferenceCounter increamentReference() {
+ this.refcounter.incrementAndGet();
+ return this;
+ }
+
+ /**
+ * @return - the resource to keep track of
+ */
+ public final Type get() {
+ return this.resource;
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/util/package.html
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/util/package.html (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/util/package.html (revision 0)
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+Storage Configuration
+
+
Property changes on: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/util/package.html
___________________________________________________________________
Name: svn:executable
+ *
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageBuffer.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageBuffer.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageBuffer.java (revision 0)
@@ -0,0 +1,249 @@
+/**
+ * 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.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
+
+/**
+ * The StorageBuffer is used to buffer incoming updates, deletes and inserts to
+ * the storage. The storage uses an lucene index to store the enries. As
+ * modifying the index all the time an altering request comes in is not
+ * efficent. The entries will be added to the buffer to be available for
+ * incoming storage queries. If the loadfactor for the
+ * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageModifier} is
+ * reached the modifier will perform a batch update on the index. Each entry
+ * will be associated with a feed id inside a associative datastructure to
+ * return a requested entry efficiently.
+ *
+ * This implementation uses {@link java.util.concurrent.locks.ReadWriteLock}.
+ * The read lock may be held simultaneously by multiple reader threads, so long
+ * as there are no writers. The write lock is exclusive.
+ *
+ * @see java.util.concurrent.locks.ReentrantReadWriteLock
+ * @see org.apache.lucene.gdata.storage.lucenestorage.StorageModifier
+ * @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class StorageBuffer {
+ private static final Log LOG = LogFactory.getLog(StorageBuffer.class);
+
+ private final Map> bufferMap;
+
+ private final List excludeList;
+
+ private final ReadWriteLock lock = new ReentrantReadWriteLock(true);
+
+ private final Lock readLock = this.lock.readLock();
+
+ private final Lock writeLock = this.lock.writeLock();
+
+ private final static int DEFAULT_BUFFER_COUNT = 10;
+
+ /**
+ * Constructs a new StorageBuffer.
+ *
+ * The expectedBufferCount sould be higher than the maximum of entries added
+ * to the buffer, resizing the buffer is very efficient. For detailed
+ * infomation {@link HashMap} as this is used inside the buffer
+ *
+ *
+ * @param expectedBufferCount -
+ * the expected size of the buffer
+ *
+ */
+ protected StorageBuffer(final int expectedBufferCount) {
+ this.bufferMap = new HashMap>(
+ expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT
+ : expectedBufferCount);
+ this.excludeList = new ArrayList(
+ expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT
+ : expectedBufferCount);
+ }
+
+ /**
+ * Adds a {@link StorageEntryWrapper} to the buffer. If a wrapper
+ * representing the same entry are already in the buffer the wrapper will be
+ * replaced.
+ *
+ * @param wrapper -
+ * the wrapper to buffer
+ */
+ public void addEntry(final StorageEntryWrapper wrapper) {
+ this.writeLock.lock();
+ try {
+ if (LOG.isInfoEnabled())
+ LOG.info(" Buffering wrapper - " + wrapper.getOperation()
+ + " ID: " + wrapper.getEntryId() + " FeedID: "
+ + wrapper.getFeedId());
+ if (wrapper.getOperation().equals(StorageOperation.DELETE))
+ return;
+
+ String feedId = wrapper.getFeedId();
+ if (this.bufferMap.containsKey(feedId))
+ this.bufferMap.get(feedId).put(wrapper.getEntryId(), wrapper);
+ else {
+ Map newFeedMap = new HashMap(
+ 20);
+ newFeedMap.put(wrapper.getEntryId(), wrapper);
+ this.bufferMap.put(feedId, newFeedMap);
+ }
+ } finally {
+ /*
+ * add all to exclude from searches doc will be available via the
+ * buffer
+ */
+ this.excludeList.add(wrapper.getEntryId());
+ this.writeLock.unlock();
+ }
+ }
+
+ /**
+ * Returns all entries for the given feed id sorted by the update timestamp
+ * desc.
+ *
+ * @param feedId -
+ * the feed id
+ * @return a {@link List} of all {@link StorageEntryWrapper} object buffered
+ * in this buffer or an empty list if not entry has been buffered
+ * for the given feed
+ */
+ public List getSortedEntries(String feedId) {
+ this.readLock.lock();
+ try {
+ if (!this.bufferMap.containsKey(feedId))
+ return null;
+ Map tempMap = this.bufferMap
+ .get(feedId);
+ if (tempMap == null)
+ return null;
+ Collection col = tempMap.values();
+ List returnList = new ArrayList(
+ col);
+ Collections.sort(returnList);
+ return returnList;
+
+ } finally {
+ this.readLock.unlock();
+ }
+
+ }
+
+ /**
+ * Adds a deleted entry to the buffer.
+ *
+ * @param entryId -
+ * the deleted entry id
+ * @param feedId -
+ * the feed of the entry
+ */
+ public void addDeleted(final String entryId, final String feedId) {
+ this.writeLock.lock();
+ try {
+ this.excludeList.add(entryId);
+ Map tempMap = this.bufferMap
+ .get(feedId);
+ if (tempMap == null)
+ return;
+ tempMap.remove(entryId);
+ } finally {
+ this.writeLock.unlock();
+
+ }
+
+ }
+
+ /**
+ * Returns an entry for the given entry id in the feed context spezified by
+ * the feed id;
+ *
+ * @param entryId -
+ * the id of the entry to return
+ * @param feedId -
+ * the feed containing the entry
+ * @return - the entry or null if the corresponding entry is
+ * not in the buffer.
+ */
+ public StorageEntryWrapper getEntry(final String entryId,
+ final String feedId) {
+ this.readLock.lock();
+ try {
+
+ if (this.bufferMap.containsKey(feedId))
+ return this.bufferMap.get(feedId).get(entryId);
+ return null;
+
+ } finally {
+ this.readLock.unlock();
+ }
+ }
+
+ /**
+ * The buffer contains updated and delete entries. These entries are already
+ * available in the lucene index but should not be found during search.
+ *
+ *
+ * this list contains all entries should not be found by the index searcher
+ *
+ *
+ * @see ModifiedEntryFilter
+ * @return - a {@link List} of entries to be omitted from a lucene index
+ * search
+ */
+ public List getExculdList() {
+ this.readLock.lock();
+ try {
+ return this.excludeList;
+ } finally {
+ this.readLock.unlock();
+ }
+ }
+
+ // not synchronized
+ private void clearBuffer() {
+ this.bufferMap.clear();
+ this.excludeList.clear();
+
+ }
+
+ /**
+ * clears the buffer -
+ */
+ public void close() {
+ this.writeLock.lock();
+ try {
+ clearBuffer();
+ } finally {
+ this.writeLock.unlock();
+ }
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/package.html
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/package.html (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/package.html (revision 0)
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+Lucene storage implementation
+
+
Property changes on: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/package.html
___________________________________________________________________
Name: svn:executable
+ *
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/IDGenerator.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/IDGenerator.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/IDGenerator.java (revision 0)
@@ -0,0 +1,171 @@
+/**
+ * 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;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This is the main entry ID generator to generate unique ids for each entry.
+ * The Generator uses {@link java.security.SecureRandom} Numbers and the
+ * {@link java.lang.System#currentTimeMillis()} to create a semi-unique sting;
+ * The string will be digested by a {@link java.security.MessageDigest} which
+ * returns a byte array. The generator encodes the byte array as a hex string.
+ *
+ * The generated Id's will cached in a
+ * {@link java.util.concurrent.BlockingQueue} and reproduced if an id has been
+ * removed.
+ *
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class IDGenerator {
+ private final SecureRandom secureRandom;
+
+ private final MessageDigest mdigest;
+
+ private final BlockingQueue blockingQueue;
+
+ private Thread runner;
+
+ private static final int DEFAULT_CAPACITY = 10;
+
+ protected static final Log LOGGER = LogFactory.getLog(IDGenerator.class);
+
+ /**
+ * Constructs a new ID generator. with a fixed capacity of prebuild ids. The
+ * default capacity is 10. Every given parameter less than 10 will be
+ * ignored.
+ *
+ * @param capacity -
+ * capacity of the prebuild id queue
+ * @throws NoSuchAlgorithmException -
+ * if the algorithm does not exist
+ */
+ public IDGenerator(int capacity) throws NoSuchAlgorithmException {
+
+ this.secureRandom = SecureRandom.getInstance("SHA1PRNG");
+ this.mdigest = MessageDigest.getInstance("SHA-1");
+ this.blockingQueue = new ArrayBlockingQueue(
+ (capacity < DEFAULT_CAPACITY ? DEFAULT_CAPACITY : capacity),
+ false);
+ startIDProducer();
+
+ }
+
+ /**
+ * This method takes a gnerated id from the IDProducer queue and retruns it.
+ * If no ID is available this method will wait until an ID is produced. This
+ * implementation is thread-safe.
+ *
+ * @return a UID
+ * @throws InterruptedException -
+ * if interrupted while waiting
+ */
+ public String getUID() throws InterruptedException {
+ return this.blockingQueue.take();
+ }
+
+ private void startIDProducer() {
+ if (this.runner == null) {
+ UIDProducer producer = new UIDProducer(this.blockingQueue,
+ this.secureRandom, this.mdigest);
+ this.runner = new Thread(producer);
+ this.runner.start();
+ }
+ }
+
+ /**
+ * @return the current size of the queue
+ */
+ public int getQueueSize() {
+ return this.blockingQueue.size();
+ }
+
+ /**
+ * Stops the id-producer
+ */
+ public void stopIDGenerator() {
+ this.runner.interrupt();
+ }
+
+ private class UIDProducer implements Runnable {
+ SecureRandom random;
+
+ BlockingQueue queue;
+
+ MessageDigest digest;
+
+ UIDProducer(BlockingQueue queue, SecureRandom random,
+ MessageDigest digest) {
+ this.queue = queue;
+ this.random = random;
+ this.digest = digest;
+
+ }
+
+ /**
+ * @see java.lang.Runnable#run()
+ */
+ public void run() {
+
+ while (true) {
+ try {
+ this.queue.put(produce());
+ } catch (InterruptedException e) {
+ LOGGER
+ .warn("UIDProducer has been interrupted -- runner is going down");
+ return;
+ }
+ }
+
+ }
+
+ private String produce() {
+ String randomNumber = new Integer(this.random.nextInt()).toString();
+ byte[] byteResult = this.digest.digest(randomNumber.getBytes());
+ return hexEncode(byteResult);
+ }
+
+ }
+
+ /**
+ * Encodes a given byte array into a hex string.
+ *
+ * @param input -
+ * the byte array to encode
+ * @return hex string representation of the given byte array
+ */
+ static String hexEncode(byte[] input) {
+ StringBuffer result = new StringBuffer();
+ char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f' };
+ for (int idx = 0; idx < input.length; ++idx) {
+ byte b = input[idx];
+ result.append(digits[(b & 0xf0) >> 4]);
+ result.append(digits[b & 0x0f]);
+ }
+ return result.toString();
+ }
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageException.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageException.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageException.java (revision 0)
@@ -0,0 +1,76 @@
+/**
+ * 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;
+
+/**
+ * The StorageException will be throw if any error or exception inside the
+ * storage implementation occures. This exception hides all other exceptions
+ * from inside the storage.
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class StorageException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4997572416934126511L;
+
+ /**
+ * Constructs a new StorageException
+ */
+ public StorageException() {
+ super();
+
+ }
+
+ /**
+ * Constructs a new StorageException
+ *
+ * @param message -
+ * the exception message
+ */
+ public StorageException(String message) {
+ super(message);
+
+ }
+
+ /**
+ * Constructs a new StorageException
+ *
+ * @param message -
+ * the exception message
+ * @param cause -
+ * the root cause of this exception
+ */
+ public StorageException(String message, Throwable cause) {
+ super(message, cause);
+
+ }
+
+ /**
+ * Constructs a new StorageException
+ *
+ * @param cause -
+ * the root cause of this exception
+ */
+ public StorageException(Throwable cause) {
+ super(cause);
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/Storage.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/Storage.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/Storage.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.storage;
+
+import java.util.List;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.BaseFeed;
+import com.google.gdata.data.ExtensionProfile;
+
+/**
+ * This is the main storage interface. The Storage represents the internal
+ * server storage. It acts as a Database to persist the feed data.
+ * This inferface is not public yet!!
+ *
+ * @author Simon Willnauer
+ *
+ */
+public interface Storage {
+
+ /**
+ * This stores an incoming entry for a later retrival.
+ * The Entry will be associated with the feedid.
+ * @param entry - the entry
+ * @param feedId - the feedID
+ * @return - the stored Entry
+ * @throws StorageException
+ */
+ public abstract BaseEntry storeEntry(BaseEntry entry, String feedId)
+ throws StorageException;
+
+ /**
+ * @param entryId
+ * @param feedId
+ * @throws StorageException
+ */
+ public abstract void deleteEntry(String entryId, String feedId)
+ throws StorageException;
+
+ /**
+ * @param entry
+ * @param feedId
+ * @return
+ * @throws StorageException
+ */
+ public abstract BaseEntry updateEntry(BaseEntry entry, String feedId)
+ throws StorageException;
+
+ /**
+ * @param feedId
+ * @param startIndex
+ * @param resultCount
+ * @return
+ * @throws StorageException
+ */
+ public abstract BaseFeed getFeed(String feedId, int startIndex,
+ int resultCount) throws StorageException;
+
+ /**
+ * @param entryId
+ * @param feedId
+ * @return
+ * @throws StorageException
+ */
+ public abstract BaseEntry getEntry(String entryId, String feedId)
+ throws StorageException;
+
+ /**
+ * @param entryIdList
+ * @param feedId
+ * @return
+ * @throws StorageException
+ */
+ public abstract List getEntries(List entryIdList,
+ String feedId) throws StorageException;
+
+ /**
+ * @param profile
+ */
+ public abstract void setExtensionProfile(final ExtensionProfile profile);
+
+ /**
+ * close this storage instance
+ */
+ public abstract void close();
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageController.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageController.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageController.java (revision 0)
@@ -0,0 +1,27 @@
+/**
+ * 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;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public interface StorageController {
+/**
+ * Destroys the controller
+ */
+public abstract void destroy();
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageFactory.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageFactory.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageFactory.java (revision 0)
@@ -0,0 +1,44 @@
+/**
+ * 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;
+
+import java.io.IOException;
+
+import org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation;
+
+/**
+ *TODO document me
+ * @author Simon Willnauer
+ *
+ */
+public class StorageFactory {
+ /**
+ * Creates a {@link Storage} instance
+ * @return - a storage instance
+ * @throws StorageException - if the storage can not be created
+ */
+ public static Storage getStorage()throws StorageException{
+ try {
+ return new StorageImplementation();
+ } catch (IOException e) {
+ StorageException ex = new StorageException("Can't create Storage instance -- "
+ + e.getMessage(), e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+
+ }
+ }
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/package.html
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/package.html (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/package.html (revision 0)
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+Feed / Enty storage
+
+
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/FeedNotFoundException.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/FeedNotFoundException.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/FeedNotFoundException.java (revision 0)
@@ -0,0 +1,52 @@
+package org.apache.lucene.gdata.server;
+
+
+/**
+ * Will be thrown if a requested feed could not be found or is not
+ * registerd.
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class FeedNotFoundException extends ServiceException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs a FeedNotFoundException
+ */
+ public FeedNotFoundException() {
+ super();
+
+ }
+
+ /**
+ * @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: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataResponse.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataResponse.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataResponse.java (revision 0)
@@ -0,0 +1,242 @@
+/**
+ * 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;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.lucene.gdata.server.GDataRequest.OutputFormat;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.BaseFeed;
+import com.google.gdata.data.ExtensionProfile;
+import com.google.gdata.util.common.xml.XmlWriter;
+import com.google.gdata.util.common.xml.XmlWriter.Namespace;
+
+/**
+ * The FeedRequest Class wraps the curren 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
+ * executed within this class.
+ *
+ * The GData basicly writes two different kinds ouf reponse to the output
+ * stream.
+ *
+ *
update, delete or insert requests will respond with a statuscode and if
+ * successful the feed entry modified or created
+ *
get requests will respond with a statuscode and if successful the
+ * requested feed
+ *
+ *
+ * For this purpose the {@link GDataResponse} class provides the overloaded
+ * method
+ * {@link org.apache.lucene.gdata.server.GDataResponse#sendResponse(BaseEntry, ExtensionProfile)}
+ * which sends the entry e.g feed to the output stream.
+ *
+ *
+ *
+ *
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class GDataResponse {
+ private int error;
+
+ private boolean isError = false;
+
+ private String encoding;
+
+ private OutputFormat outputFormat;
+
+ private final HttpServletResponse response;
+
+ private static final String DEFAUL_NAMESPACE_URI = "http://www.w3.org/2005/Atom";
+
+ private static final Namespace DEFAULT_NAMESPACE = new Namespace("",
+ DEFAUL_NAMESPACE_URI);
+
+ /**
+ * Creates a new GDataResponse
+ *
+ * @param response -
+ * The underlaying {@link HttpServletResponse}
+ */
+ public GDataResponse(HttpServletResponse response) {
+ if (response == null)
+ throw new IllegalArgumentException("response must not be null");
+ this.response = response;
+ this.response.setContentType("text/xml");
+ }
+
+ /**
+ * Sets an error code to this FeedResponse.
+ *
+ * @param errorCode -
+ * {@link HttpServletResponse} error code
+ */
+ public void setError(int errorCode) {
+ this.isError = true;
+ this.error = errorCode;
+ }
+ /**
+ * Sets the status of the underlaying response
+ * @see HttpServletResponse
+ * @param responseCode - the status of the response
+ */
+ public void setResponseCode(int responseCode){
+ this.response.setStatus(responseCode);
+ }
+ /**
+ * This method sends the specified error to the user if set
+ *
+ * @throws IOException -
+ * if an I/O Exception occures
+ */
+ public void sendError() throws IOException {
+ if (this.isError)
+ this.response.sendError(this.error);
+ }
+
+ /**
+ * @return - the {@link HttpServletResponse} writer
+ * @throws IOException -
+ * If an I/O exception occures
+ */
+ public Writer getWriter() throws IOException {
+ return this.response.getWriter();
+ }
+
+ /**
+ * 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.
+ *
+ * @param feed -
+ * the feed to respond to the client
+ * @param profile -
+ * the extension profil for the feed to write
+ * @throws IOException -
+ * if an I/O exception accures, often caused by an already
+ * closed Writer or OutputStream
+ *
+ */
+ public void sendResponse(BaseFeed feed, ExtensionProfile profile)
+ throws IOException {
+ if (feed == null)
+ throw new IllegalArgumentException("feed must not be null");
+ if(profile == null)
+ throw new IllegalArgumentException("extension profil must not be null");
+ XmlWriter writer = createWriter();
+
+ if (this.outputFormat.equals(OutputFormat.ATOM))
+ feed.generateAtom(writer, profile);
+ else
+ feed.generateRss(writer, profile);
+
+ }
+
+ /**
+ *
+ * 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 the specified response format is ATOM the default namespace will be set to ATOM.
+ * @param entry -
+ * the modified / created entry to send
+ * @param profile -
+ * the entries extension profile
+ * @throws IOException -
+ * if an I/O exception accures, often caused by an already
+ * closed Writer or OutputStream
+ */
+ public void sendResponse(BaseEntry entry, ExtensionProfile profile)
+ throws IOException {
+ if (entry == null)
+ throw new IllegalArgumentException("entry must not be null");
+ if(profile == null)
+ throw new IllegalArgumentException("extension profil must not be null");
+ XmlWriter writer = createWriter();
+ if (this.outputFormat.equals(OutputFormat.ATOM))
+ entry.generateAtom(writer, profile);
+ else
+ entry.generateRss(writer, profile);
+ }
+
+ private XmlWriter createWriter() throws IOException {
+ XmlWriter writer = new XmlWriter(getWriter(), this.encoding);
+ // set the default namespace to Atom if Atom is the response format
+ if(this.outputFormat.equals(OutputFormat.ATOM))
+ writer.setDefaultNamespace(DEFAULT_NAMESPACE);
+ return writer;
+ }
+
+ /**
+ * This encoding will be used to encode the xml representation of feed or
+ * entry written to the {@link HttpServletResponse} output stream.
+ *
+ * @return - the entry / feed encoding
+ */
+ public String getEncoding() {
+ return this.encoding;
+ }
+
+ /**
+ * This encoding will be used to encode the xml representation of feed or
+ * entry written to the {@link HttpServletResponse} output stream. UTF-8
+ * ISO-8859-1
+ *
+ * @param encoding -
+ * string represents the encoding
+ */
+ public void setEncoding(String encoding) {
+ this.encoding = encoding;
+ }
+
+ /**
+ * @return - the response
+ * {@link org.apache.lucene.gdata.server.GDataRequest.OutputFormat}
+ */
+ public OutputFormat getOutputFormat() {
+ return this.outputFormat;
+ }
+
+ /**
+ * @param outputFormat -
+ * the response
+ * {@link org.apache.lucene.gdata.server.GDataRequest.OutputFormat}
+ */
+ public void setOutputFormat(OutputFormat outputFormat) {
+ this.outputFormat = outputFormat;
+ }
+ /**
+ * @see Object#toString()
+ */
+ @Override
+ public String toString(){
+ StringBuilder builder = new StringBuilder(" GDataResponse: ");
+ builder.append("Error: ").append(this.error);
+ builder.append(" outputFormat: ").append(getOutputFormat());
+ builder.append(" encoding: ").append(this.encoding);
+
+ return builder.toString();
+
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceException.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceException.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceException.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.server;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public class ServiceException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7099825107871876584L;
+
+ /**
+ *
+ */
+ public ServiceException() {
+ super();
+
+ }
+
+ /**
+ * @param arg0
+ */
+ public ServiceException(String arg0) {
+ super(arg0);
+
+ }
+
+ /**
+ * @param arg0
+ * @param arg1
+ */
+ public ServiceException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+
+ }
+
+ /**
+ * @param arg0
+ */
+ public ServiceException(Throwable arg0) {
+ super(arg0);
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/Service.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/Service.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/Service.java (revision 0)
@@ -0,0 +1,139 @@
+/**
+ * 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;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.BaseFeed;
+
+
+/**
+ * The Service class represents an interface to access the GData service
+ * componentes of the GData-Server. It encapsulates all interactions with the
+ * GData client.
+ *
+ * This class provides the base level common functionality required to access
+ * the GData components. It is also designed to act as a base class that can be
+ * extended for specific types of underlaying server components as different
+ * indexing or storage components.
+ *
+ *
+ * It could also encapsulate caching mechanismn build on top of the storage to
+ * reduce load on the storage component
+ *
+ *
+ * @author Simon Willnauer
+ *
+ *
+ */
+public abstract class Service {
+
+ /**
+ * Service method to create an entry in an already created and existing
+ * feed. This method will create the entry and passes the entry to the
+ * indexing component to make the new entry accessable via get-queries.
+ * The response and the corresponding http status code will be added to the
+ * given FeedResponse.
+ *
+ * @param request -
+ * the current FeedRequest
+ * @param response -
+ * the current FeedResponse
+ * @return - the entry which has been created
+ * @throws ServiceException -
+ * if the corresponding feed does not exist or the storage can
+ * not be accessed
+ */
+ public abstract BaseEntry createEntry(final GDataRequest request,
+ final GDataResponse response) throws ServiceException;
+
+ /**
+ * Service Method to delete an entry specified in the given FeedRequest.
+ * This method will remove the entry permanently. There will be no
+ * possiblity to restore the entry. The response and the corresponding http
+ * status code will be added to the given FeedResponse.
+ *
+ * @param request -
+ * the current FeedRequest
+ * @param response -
+ * the current FeedResponse
+ * @return - the entry wich has been deleted
+ * @throws ServiceException -
+ * if the entry does not exist or the storage can not be
+ * accessed
+ */
+ public abstract BaseEntry deleteEntry(GDataRequest request, final GDataResponse response)
+ throws ServiceException;
+
+ /**
+ * Service method to update an existing entry in a existing feed context.
+ * The entry version will be checked and a ServiceException
+ * will be thrown if the version to update is outdated. The new entry will
+ * be passed to the indexing component to make the version accessable via
+ * get-queries.
+ *
+ * @param request -
+ * the current FeedRequest
+ * @param response -
+ * the current FeedResponse
+ * @return - the entry wich has been updated
+ * @throws ServiceException -
+ * if the corresponding feed does not exist, the storage can not
+ * be accessed or the version to update is out of date.
+ */
+ public abstract BaseEntry updateEntry(final GDataRequest request,
+ final GDataResponse response) throws ServiceException;
+
+ /**
+ * Service method to retrieve a requested Feed. The feed will also be added to
+ * the given FeedResponse instance and can also be accessed
+ * via the FeedResponse object.
+ *
+ * @param request -
+ * the current FeedRequest
+ * @param response -
+ * the current FeedResponse
+ * @return - the requested feed
+ *
+ * @throws ServiceException -
+ * If the storage can not be accessed or the requested feed does
+ * not exist.
+ */
+ public abstract BaseFeed getFeed(final GDataRequest request, final GDataResponse response)
+ throws ServiceException;
+
+ /**
+ * Service method to retrieve a requested entry. The entry will also be added to
+ * the given FeedResponse instance and can also be accessed
+ * via the FeedResponse object.
+ *
+ * @param request -
+ * the current FeedRequest
+ * @param response -
+ * the current FeedResponse
+ * @return - the requested entry
+ *
+ * @throws ServiceException -
+ * If the storage can not be accessed or the requested entry does
+ * not exist.
+ */
+ public abstract BaseEntry getSingleEntry(final GDataRequest request, final GDataResponse response)
+ throws ServiceException;
+
+
+
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataService.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataService.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataService.java (revision 0)
@@ -0,0 +1,275 @@
+/**
+ * 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;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
+import org.apache.lucene.gdata.storage.Storage;
+import org.apache.lucene.gdata.storage.StorageException;
+import org.apache.lucene.gdata.storage.StorageFactory;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.BaseFeed;
+import com.google.gdata.data.DateTime;
+import com.google.gdata.data.Generator;
+import com.google.gdata.data.Link;
+import com.google.gdata.util.ParseException;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public class GDataService extends Service {
+ private static final Log LOGGER = LogFactory.getLog(GDataService.class);
+
+ private Storage storage;
+
+ private GDataServerRegistry registry = GDataServerRegistry.getRegistry();
+
+ private static final Generator generator;
+
+ private static final String generatorName = "Lucene GData-Server";
+
+ private static final String generatorURI = "http://lucene.apache.org";
+ static {
+ generator = new Generator();
+ generator.setName(generatorName);
+ generator.setUri(generatorURI);
+ generator.setVersion("0.1");
+ }
+
+ protected GDataService() throws ServiceException {
+ try {
+ this.storage = StorageFactory.getStorage();
+
+ } catch (StorageException e) {
+ LOGGER
+ .fatal(
+ "Can't get Storage Instance -- can't serve any requests",
+ e);
+ ServiceException ex = new ServiceException(
+ "Can't get Storage instance" + e.getMessage(), e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.Service#createEntry(org.apache.lucene.gdata.server.GDataRequest,
+ * org.apache.lucene.gdata.server.GDataResponse)
+ */
+ @Override
+ public BaseEntry createEntry(GDataRequest request, GDataResponse response)
+ throws ServiceException {
+
+ checkFeedIsRegisterd(request);
+ if (LOGGER.isInfoEnabled())
+ LOGGER.info("create Entry for feedId: " + request.getFeedId());
+ BaseEntry entry = buildEntry(request);
+ setUpdateTime(entry);
+ try {
+
+ this.storage.storeEntry(entry, request.getFeedId());
+ } catch (Exception e) {
+ ServiceException ex = new ServiceException("Could not store entry",
+ e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ return entry;
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.Service#deleteEntry(org.apache.lucene.gdata.server.GDataRequest,
+ * org.apache.lucene.gdata.server.GDataResponse)
+ */
+ @Override
+ public BaseEntry deleteEntry(GDataRequest request, GDataResponse response)
+ throws ServiceException {
+ checkFeedIsRegisterd(request);
+ String entryid = request.getEntryId();
+ String feedid = request.getFeedId();
+ try {
+ this.storage.deleteEntry(entryid, feedid);
+ } catch (Exception e) {
+ ServiceException ex = new ServiceException(
+ "Could not delete entry", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ return null;
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.Service#updateEntry(org.apache.lucene.gdata.server.GDataRequest,
+ * org.apache.lucene.gdata.server.GDataResponse)
+ */
+ @Override
+ public BaseEntry updateEntry(GDataRequest request, GDataResponse response)
+ throws ServiceException {
+ checkFeedIsRegisterd(request);
+
+ BaseEntry entry = buildEntry(request);
+ String feedid = request.getFeedId();
+ if (LOGGER.isInfoEnabled())
+ LOGGER.info("update Entry" + entry.getId() + " for feedId: "
+ + feedid);
+ setUpdateTime(entry);
+ try {
+ this.storage.updateEntry(entry, feedid);
+ } catch (StorageException e) {
+ ServiceException ex = new ServiceException(
+ "Could not update entry", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ return entry;
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.Service#getFeed(org.apache.lucene.gdata.server.GDataRequest,
+ * org.apache.lucene.gdata.server.GDataResponse)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public BaseFeed getFeed(GDataRequest request, GDataResponse response)
+ throws ServiceException {
+ checkFeedIsRegisterd(request);
+
+ try {
+ // TODO remove when storing feeds is implemented just for
+ // development
+ BaseFeed feed = this.storage.getFeed(request.getFeedId(), request
+ .getStartIndex(), request.getItemsPerPage());
+ buildDynamicFeedElements(request, feed);
+ List list = feed.getEntries();
+ addContextPath(list, request.getContextPath());
+ return feed;
+ } catch (StorageException e) {
+ ServiceException ex = new ServiceException("Could not get feed", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+
+ }
+
+ /*
+ * build the dynamic elements like self link and next link
+ */
+ private void buildDynamicFeedElements(final GDataRequest request,
+ final BaseFeed feed) {
+ feed.setGenerator(generator);
+ feed.setItemsPerPage(request.getItemsPerPage());
+ feed.getLinks().add(
+ buildLink(Link.Rel.SELF, Link.Type.ATOM, request.getSelfId()));
+ // TODO add next link
+ }
+
+ private Link buildLink(String rel, String type, String href) {
+ Link retVal = new Link();
+ retVal.setHref(href);
+ retVal.setRel(rel);
+ retVal.setType(type);
+ return retVal;
+ }
+
+ /*
+ * every entry has an ID which has to have a prefix. The prefix is the
+ * context path of the requested feed. This will be used to request the
+ * entry directly
+ */
+ private void addContextPath(List list, final String contextPath) {
+ for (BaseEntry entry : list) {
+ addcontextPath(entry, contextPath);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private BaseEntry addcontextPath(final BaseEntry entry,
+ final String contextPath) {
+ String id = contextPath + entry.getId();
+ entry.setId(id);
+ Link self = new Link();
+ self.setRel("self");
+ self.setHref(id);
+ self.setType("application/atom+xml");
+ entry.getLinks().add(self);
+ return entry;
+ }
+
+ private BaseEntry buildEntry(final GDataRequest request)
+ throws ServiceException {
+ try {
+ return GDataEntityBuilder.buildEntry(request);
+
+ } catch (ParseException e) {
+ ServiceException ex = new ServiceException(
+ "Could not parse entry from incoming request", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ } catch (IOException e) {
+ ServiceException ex = new ServiceException(
+ "Could not read or open input stream", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ }
+
+ /*
+ * checks whether the reqeuested feed is registered
+ */
+ private void checkFeedIsRegisterd(final GDataRequest request)
+ throws FeedNotFoundException {
+ if (!this.registry.isFeedRegistered(request.getFeedId()))
+ throw new FeedNotFoundException(
+ "Feed could not be found - is not registed - Feed ID:"
+ + request.getFeedId());
+ this.storage.setExtensionProfile(request.getExtensionProfile());
+ }
+
+ private BaseEntry setUpdateTime(final BaseEntry entry) {
+ entry.setUpdated(DateTime.now());
+ return entry;
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.Service#getSingleEntry(org.apache.lucene.gdata.server.GDataRequest,
+ * org.apache.lucene.gdata.server.GDataResponse)
+ */
+ @Override
+ public BaseEntry getSingleEntry(GDataRequest request, GDataResponse response)
+ throws ServiceException {
+ checkFeedIsRegisterd(request);
+
+ try {
+ BaseEntry entry = this.storage.getEntry(request.getEntryId(),
+ request.getFeedId());
+ if(entry == null)
+ return null;
+ addcontextPath(entry, request.getContextPath());
+ return entry;
+ } catch (StorageException e) {
+ ServiceException ex = new ServiceException("Could not get feed", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataEntityBuilder.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataEntityBuilder.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataEntityBuilder.java (revision 0)
@@ -0,0 +1,171 @@
+/**
+ * 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;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.lucene.gdata.server.registry.DataBuilderException;
+import org.apache.lucene.gdata.server.registry.FeedInstanceConfigurator;
+import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.BaseFeed;
+import com.google.gdata.data.ExtensionProfile;
+import com.google.gdata.util.ParseException;
+
+/**
+ * {@link com.google.gdata.data.BaseFeed},
+ * {@link com.google.gdata.data.BaseEntry} instances have to be build from a
+ * {@link java.io.Reader} instance as they come in from a client request or out
+ * of a storage.
+ *
+ * To provide a generic builder class the {@link GDataEntityBuilder} requests
+ * the type of the feed / entry and the corresponding
+ * {@link com.google.gdata.data.ExtensionProfile} form the global
+ * {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry} and builds the
+ * instances from the provided reader.
+ *
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class GDataEntityBuilder {
+ private static final GDataServerRegistry REGISTRY = GDataServerRegistry.getRegistry(); // TODO find another way for getting the registered feeds
+
+ /**
+ * Builds a {@link BaseFeed} instance from the {@link Reader} provided by
+ * the {@link GDataRequest}
+ *
+ * @param request -
+ * the request to build the instance from
+ * @return - a BaseFeed instance
+ * @throws FeedNotFoundException -
+ * if the feed is not registered
+ * @throws IOException -
+ * if an I/O Exception occures on the provided reader
+ * @throws ParseException -
+ * if the feed could not be parsed
+ */
+ public static BaseFeed buildFeed(final GDataRequest request)
+ throws FeedNotFoundException, IOException, ParseException {
+ if (request == null)
+ throw new IllegalArgumentException("request must not be null");
+ return buildFeed(request.getFeedId(), request.getReader(),request.getExtensionProfile());
+ }
+
+ /**
+ * Builds a {@link BaseFeed} from the provided {@link Reader}
+ *
+ * @param feedId -
+ * the feed ID to request the feed type from the registry
+ * @param reader -
+ * the reader to build the feed from
+ * @param profile - extension profile to parse the resource
+ * @return - a BaseFeed instance
+ * @throws FeedNotFoundException -
+ * if the feed is not registered
+ * @throws IOException -
+ * if an I/O Exception occures on the provided reader
+ * @throws ParseException -
+ * if the feed could not be parsed
+ */
+ public static BaseFeed buildFeed(final String feedId, final Reader reader,final ExtensionProfile profile)
+ throws FeedNotFoundException, ParseException, IOException {
+
+ BaseFeed retVal = null;
+ try {
+ retVal = (BaseFeed) createEntityInstance(feedId);
+ } catch (FeedNotFoundException e) {
+ throw e;
+ } catch (Exception e) {
+ DataBuilderException ex = new DataBuilderException(
+ "Could not build Feed for Feed class ", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ retVal.parseAtom(profile, reader);
+
+ return retVal;
+ }
+
+ /**
+ * Builds a {@link BaseEntry} instance from the {@link Reader} provided by
+ * the {@link GDataRequest}
+ *
+ * @param request -
+ * the request to build the instance from
+ * @return - a BaseEntry instance
+ * @throws FeedNotFoundException -
+ * if the feed, requested by the client is not registered
+ * @throws IOException -
+ * if an I/O Exception occures on the provided reader
+ * @throws ParseException -
+ * if the entry could not be parsed
+ */
+ public static BaseEntry buildEntry(final GDataRequest request)
+ throws FeedNotFoundException, IOException, ParseException {
+ if (request == null)
+ throw new IllegalArgumentException("request must not be null");
+ return buildEntry(request.getFeedId(), request.getReader(),request.getExtensionProfile());
+ }
+
+ /**
+ * Builds a {@link BaseFeed} instance from the {@link Reader} provided by
+ * the {@link GDataRequest}
+ * @param feedId -
+ * the feed ID to request the feed type from the registry
+ * @param reader -
+ * the reader to build the feed from
+ * @param profile - extension profile to parse the resource
+ * @return - a BaseFeed instance
+ * @throws FeedNotFoundException -
+ * if the feed is not registered
+ * @throws IOException -
+ * if an I/O Exception occures on the provided reader
+ * @throws ParseException -
+ * if the entry could not be parsed
+ */
+ public static BaseEntry buildEntry(final String feedId, final Reader reader,final ExtensionProfile profile)
+ throws FeedNotFoundException, ParseException, IOException {
+
+ BaseEntry retVal = null;
+ try {
+ retVal = ((BaseFeed) createEntityInstance(feedId)).createEntry();
+ } catch (FeedNotFoundException e) {
+ throw e;
+ } catch (Exception e) {
+ DataBuilderException ex = new DataBuilderException(
+ "Could not build Entry for Entry class ", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ retVal.parseAtom(new ExtensionProfile(), reader);
+ return retVal;
+ }
+
+ private static Object createEntityInstance(String feedId)
+ throws FeedNotFoundException, InstantiationException,
+ IllegalAccessException {
+ FeedInstanceConfigurator config = REGISTRY.getFeedConfigurator(feedId);
+ if (config == null)
+ throw new FeedNotFoundException(
+ "No feed for requested feed ID found - " + feedId);
+ Class feedClass = config.getFeedType();
+ return feedClass.newInstance();
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataRequestException.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataRequestException.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataRequestException.java (revision 0)
@@ -0,0 +1,67 @@
+/**
+ * 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;
+
+/**
+ * This exception wraps all exceptions occure inside the {@link org.apache.lucene.gdata.server.GDataRequest}
+ * @author Simon Willnauer
+ *
+ */
+public class GDataRequestException extends Exception {
+
+ /**
+ * Serial version ID. -> Implements Serializable
+ */
+ private static final long serialVersionUID = -4440777051466950723L;
+
+ /**
+ * Constructs a new GDataException
+ */
+ public GDataRequestException() {
+ super();
+
+ }
+
+ /**
+ * Constructs a new GDataException with a given message string
+ * @param arg0 - the excpetion message
+ */
+ public GDataRequestException(String arg0) {
+ super(arg0);
+
+ }
+
+ /**
+ * Constructs a new GDataException with a given message string and cause
+ * @param arg0 - the exception message
+ * @param arg1 - the exception who caused this exception
+ */
+ public GDataRequestException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+
+ }
+
+ /**
+ * Constructs a new GDataException with a given cause
+ * @param arg0 - exception cause
+ */
+ public GDataRequestException(Throwable arg0) {
+ super(arg0);
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/DataBuilderException.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/DataBuilderException.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/DataBuilderException.java (revision 0)
@@ -0,0 +1,62 @@
+/**
+ * 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;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public class DataBuilderException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3802958802500735198L;
+
+ /**
+ *
+ */
+ public DataBuilderException() {
+ super();
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param message
+ */
+ public DataBuilderException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public DataBuilderException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param cause
+ */
+ public DataBuilderException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryBuilder.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryBuilder.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryBuilder.java (revision 0)
@@ -0,0 +1,41 @@
+/**
+ * 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 com.google.gdata.data.ExtensionProfile;
+import com.google.gdata.data.Feed;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public class RegistryBuilder {
+
+ /**
+ *
+ */
+ public static void buildRegistry(){
+ // TODO Implement this!! -- just for develping purposes
+ GDataServerRegistry reg = GDataServerRegistry.getRegistry();
+ FeedInstanceConfigurator configurator = new FeedInstanceConfigurator();
+ configurator.setFeedType(Feed.class);
+ configurator.setFeedId("weblog");
+ configurator.setExtensionProfileClass(ExtensionProfile.class);
+ reg.registerFeed(configurator);
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/GDataServerRegistry.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/GDataServerRegistry.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/GDataServerRegistry.java (revision 0)
@@ -0,0 +1,154 @@
+/**
+ * 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.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.storage.StorageController;
+
+import com.google.gdata.data.ExtensionProfile;
+
+/**
+ *
+ * The FeedRegistry represents the registry component of the GData Server. All
+ * feed configurations will be registered here. Feed configurations contain
+ * several informationsa about GData feed like:
+ *
+ *
the feed id - where the feed can be accessed via http methodes
+ *
the feed type - feed types are implementations of the abstract
+ * {@link com.google.gdata.data.BaseFeed}
+ *
+ * The registry will be set up at start up of the server application and can be
+ * accessed from other components to get configurations according to incoming
+ * requests.
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class GDataServerRegistry {
+ private static GDataServerRegistry INSTANCE;
+
+ private StorageController storageInstance;
+
+ private static final Log LOGGER = LogFactory
+ .getLog(GDataServerRegistry.class);
+
+ private final Map feedTypMap = new HashMap();
+
+ private GDataServerRegistry() {
+ // private - singleton
+ }
+
+ /**
+ * @return a Sinleton registry instance
+ */
+ public static synchronized GDataServerRegistry getRegistry() {
+ if (INSTANCE == null)
+ INSTANCE = new GDataServerRegistry();
+ return INSTANCE;
+ }
+
+ /**
+ * Registers a {@link FeedInstanceConfigurator}
+ *
+ * @param configurator -
+ * the configurator to register in the registry
+ */
+ public void registerFeed(FeedInstanceConfigurator configurator) {
+ if (configurator == null) {
+ LOGGER.warn("Feedconfigurator is null -- skip registration");
+ return;
+ }
+ this.feedTypMap.put(configurator.getFeedId(), configurator);
+ }
+
+ /**
+ * Looks up the {@link FeedInstanceConfigurator} by the given feed id.
+ *
+ * @param feedId
+ * @return - the {@link FeedInstanceConfigurator} or null if
+ * the no configuration for this feed has been registered
+ */
+ public FeedInstanceConfigurator getFeedConfigurator(String feedId) {
+ if (feedId == null)
+ throw new IllegalArgumentException(
+ "Feed URL is null - must not be null to get registered feedtype");
+ return this.feedTypMap.get(feedId);
+ }
+
+ protected void flushRegistry() {
+ this.feedTypMap.clear();
+ }
+
+ /**
+ * @param feedId -
+ * the id of the feed as the feed is registered
+ * @return - true if and only if the feed is registered,
+ * otherwise false.
+ */
+ public boolean isFeedRegistered(String feedId) {
+ return this.feedTypMap.containsKey(feedId);
+
+ }
+
+ /**
+ * @param storage
+ */
+ public void registerStorage(StorageController storage) {
+ if (this.storageInstance != null)
+ throw new IllegalStateException(
+ "Storage already registered -- Instance of "
+ + this.storageInstance.getClass());
+ this.storageInstance = storage;
+ }
+
+ /**
+ * Destroys the registry and release all resources
+ */
+ public void destroy() {
+ flushRegistry();
+ this.storageInstance.destroy();
+ this.storageInstance = null;
+
+ }
+
+ /**
+ * Creates the {@link ExtensionProfile} for a registered feed
+ * @param feedId - the feed id
+ * @return - the extension profil for this feed of null if
+ * the feed is not registered or the extension profile could not be
+ * instanciated
+ */
+ public ExtensionProfile getExtensionProfile(final String feedId) {
+ FeedInstanceConfigurator configurator = this.feedTypMap.get(feedId);
+ if (configurator == null)
+ return null;
+ Class clazz = configurator.getExtensionProfilClass();
+ try {
+ return (ExtensionProfile) clazz.newInstance();
+ } catch (Exception e) {
+ LOGGER
+ .error("Can not create instance of ExtensionProfil for class: "
+ + clazz + " -- feedId: " + feedId);
+
+ }
+ return null;
+ }
+
+}
Property changes on: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/GDataServerRegistry.java
___________________________________________________________________
Name: svn:executable
+ *
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryContextListener.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryContextListener.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryContextListener.java (revision 0)
@@ -0,0 +1,65 @@
+/**
+ * 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 javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This Listener creates the
+ * {@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.
+ *
+ * This ContextListener has to be configured in the web.xml
+ * deployment descriptor.
+ *
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class RegistryContextListener implements ServletContextListener {
+ private GDataServerRegistry serverRegistry;
+
+ private static final Log LOG = LogFactory
+ .getLog(RegistryContextListener.class);
+
+
+
+ /**
+ * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
+ */
+ public void contextInitialized(ServletContextEvent arg0) {
+ LOG.info("RegistryContextListener has been loaded");
+ RegistryBuilder.buildRegistry();
+ this.serverRegistry = GDataServerRegistry.getRegistry();
+ }
+
+ /**
+ * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
+ */
+ public void contextDestroyed(ServletContextEvent arg0) {
+ LOG.info("Destroying context");
+ this.serverRegistry.destroy();
+
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/FeedInstanceConfigurator.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/FeedInstanceConfigurator.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/FeedInstanceConfigurator.java (revision 0)
@@ -0,0 +1,66 @@
+/**
+ * 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;
+
+/**
+ * @author Simon Willnauer
+ *
+ */
+public class FeedInstanceConfigurator {
+ private Class feedType;
+ private String feedId;
+ private Class extensionProfileClass;
+ /**
+ * @return Returns the feedType.
+ */
+ public Class getFeedType() {
+ return this.feedType;
+ }
+ /**
+ * @param feedType The feedType to set.
+ */
+ public void setFeedType(Class feedType) {
+ this.feedType = feedType;
+ }
+ /**
+ * @return Returns the feedURL.
+ */
+ public String getFeedId() {
+ return this.feedId;
+ }
+ /**
+ * @param feedURL The feedURL to set.
+ */
+ public void setFeedId(String feedURL) {
+ this.feedId = feedURL;
+ }
+
+ /**
+ * @return - the extension profile for this feed
+ */
+ public Class getExtensionProfilClass(){
+ return this.extensionProfileClass;
+ }
+
+ /**
+ * @param extensionProfilClass
+ */
+ public void setExtensionProfileClass(Class extensionProfilClass){
+ this.extensionProfileClass = extensionProfilClass;
+ }
+
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/package.html
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/package.html (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/package.html (revision 0)
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+Internal registry - registering feeds and configurations
+
+
\ No newline at end of file
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceFactory.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceFactory.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceFactory.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.server;
+
+
+/**
+ * The {@link ServiceFactory} creates {@link Service} implementations to access
+ * the GData - Server components.
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class ServiceFactory {
+
+ private static ServiceFactory INSTANCE = null;
+
+ /**
+ * @return - a Singleton Instance of the factory
+ */
+ public static synchronized ServiceFactory getInstance() {
+ if (INSTANCE == null)
+ INSTANCE = new ServiceFactory();
+ return INSTANCE;
+
+ }
+
+ private ServiceFactory() {
+ // private constructor --> singleton
+ }
+
+ /**
+ * Creates a {@link Service} implementation.
+ *
+ * @return a Service Implementation
+ */
+ public Service getService() {
+ try{
+ return new GDataService();
+ }catch (Exception e) {
+ //
+ }
+ return null;
+ }
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataRequest.java
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataRequest.java (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataRequest.java (revision 0)
@@ -0,0 +1,442 @@
+/**
+ * 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;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
+
+import com.google.gdata.data.ExtensionProfile;
+
+/**
+ * The GDataRequest Class wraps the incoming HttpServletRequest. Needed
+ * information coming with the HttpServletRequest can be accessed directly. It
+ * represents an abstraction on the plain HttpServletRequest. Every GData
+ * specific data coming from the client will be availiable and can be accessed
+ * via the GDataRequest.
+ *
+ * GDataRequest instances will be passed to any action requested by the client.
+ * This class also holds the logic to retrieve important information like
+ * response format, the reqeusted feed instance and query parameters.
+ *
+ *
+ *
+ * @author Simon Willnauer
+ *
+ */
+/* this class might be extracted as an interface in later development */
+public class GDataRequest {
+
+ private static final Log LOG = LogFactory.getLog(GDataRequest.class);
+
+ private static final String RESPONSE_FORMAT_PARAMETER = "alt";
+
+ private static final String RESPONSE_FORMAT_PARAMETER_RSS = "rss";
+
+ private static final int DEFAULT_ITEMS_PER_PAGE = 25;
+
+ private static final int DEFAULT_START_INDEX = 1;
+
+ private static final String START_INDEX_NEXT_PAGE_PARAMETER = "start-index";
+
+ private static final String ITEMS_PER_PAGE_PARAMETER = "max-results";
+
+ private String contextPath;
+
+ @SuppressWarnings("unused")
+ private static final String RESPONSE_FORMAT_PARAMETER_ATOM = "atom";
+
+ // Atom is the default resopnse format
+ private OutputFormat responseFormat = OutputFormat.ATOM;
+
+ private final HttpServletRequest request;
+
+ private String feedId = null;
+
+ private String entryId = null;
+
+ private ExtensionProfile extensionProfile= null;
+
+ private String entryVersion = null;
+
+ private GDataRequestType type;
+
+ /**
+ * Creates a new FeedRequest
+ *
+ * @param requst -
+ * the incoming HttpServletReqeust
+ * @param type -
+ * the request type
+ *
+ */
+ public GDataRequest(final HttpServletRequest requst,
+ final GDataRequestType type) {
+ if (requst == null)
+ throw new IllegalArgumentException("request must not be null ");
+ if (type == null)
+ throw new IllegalArgumentException("request type must not be null ");
+ this.request = requst;
+ this.type = type;
+
+ }
+
+ /**
+ * Initialize the GDataRequest. This will initialize all needed values /
+ * attributes in this request.
+ *
+ * @throws GDataRequestException
+ */
+ public void initializeRequest() throws GDataRequestException {
+ generateIdentificationProperties();
+ setOutputFormat();
+ /*
+ * ExtensionProfile is used for building the Entry / Feed Instances from an inputstream or reader
+ */
+ this.extensionProfile = GDataServerRegistry.getRegistry().getExtensionProfile(this.feedId);
+ if(this.extensionProfile == null)
+ throw new GDataRequestException("feed is not registered or extension profile could not be created");
+ }
+
+ /**
+ * @return - the id of the requested feed
+ */
+ public String getFeedId() {
+
+ return this.feedId;
+ }
+
+ /**
+ * @return - the entry id of the requested Entry if specified, otherwise
+ * null
+ */
+ public String getEntryId() {
+
+ return this.entryId;
+ }
+
+ /**
+ * @return the version Id of the requested Entry if specified, otherwise
+ * null
+ */
+ public String getEntryVersion() {
+ return this.entryVersion;
+ }
+
+ /**
+ * A Reader instance to read form the client input stream
+ *
+ * @return - the HttpServletRequest {@link Reader}
+ * @throws IOException -
+ * if an I/O Exception occures
+ */
+ public Reader getReader() throws IOException {
+ return this.request.getReader();
+ }
+
+ /**
+ * Returns the {@link HttpServletRequest} parameter map containig all GET
+ * request parameters.
+ *
+ * @return the parameter map
+ */
+ @SuppressWarnings("unchecked")
+ public Map getQueryParameter() {
+ return this.request.getParameterMap();
+ }
+
+ /**
+ * The {@link HttpServletRequest} request parameter names
+ *
+ * @return parameter names enumeration
+ */
+ @SuppressWarnings("unchecked")
+ public Enumeration getQueryParameterNames() {
+ return this.request.getParameterNames();
+ }
+
+ /**
+ * Either Atom or RSS
+ *
+ * @return - The output format requested by the client
+ */
+ public OutputFormat getRequestedResponseFormat() {
+
+ return this.responseFormat;
+ }
+
+ private void generateIdentificationProperties()
+ throws GDataRequestException {
+ /* generate all needed data to identify the requested feed/entry */
+ String pathInfo = this.request.getPathInfo();
+ /*
+ * TODO this has to be changed to support the category queries. Category
+ * queries could also be rewrited in the Servlet.
+ */
+ if (pathInfo.length() <= 1)
+ throw new GDataRequestException(
+ "No feed or entry specified for this request");
+ StringTokenizer tokenizer = new StringTokenizer(pathInfo, "/");
+ this.feedId = tokenizer.nextToken();
+ this.entryId = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : "";
+ this.entryVersion = tokenizer.hasMoreTokens() ? tokenizer.nextToken()
+ : "";
+
+ }
+
+ private void setOutputFormat() {
+ String formatParameter = this.request
+ .getParameter(RESPONSE_FORMAT_PARAMETER);
+ if (formatParameter == null)
+ return;
+ if (formatParameter.equalsIgnoreCase(RESPONSE_FORMAT_PARAMETER_RSS))
+ this.responseFormat = OutputFormat.RSS;
+
+ }
+
+ /**
+ * @return - the number of returned items per page
+ */
+ public int getItemsPerPage() {
+
+ if (this.request.getParameter(ITEMS_PER_PAGE_PARAMETER) == null)
+ return DEFAULT_ITEMS_PER_PAGE;
+ int retval = -1;
+ try {
+ retval = new Integer(this.request
+ .getParameter(ITEMS_PER_PAGE_PARAMETER)).intValue();
+ } catch (Exception e) {
+ LOG.warn("Intems per page could not be parsed - " + e.getMessage(),
+ e);
+ }
+ return retval < 0 ? DEFAULT_ITEMS_PER_PAGE : retval;
+ }
+
+ /**
+ * Start index represents the number of the first entry of the query -
+ * result. The order depends on the query. Is the query a search query the
+ * this value will be assinged to the score in a common feed query the value
+ * will be assigned to the update time of the entries.
+ *
+ * @return - the requested start index
+ */
+ public int getStartIndex() {
+ if (this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER) == null)
+ return DEFAULT_START_INDEX;
+ int retval = -1;
+ try {
+ retval = new Integer(this.request
+ .getParameter(START_INDEX_NEXT_PAGE_PARAMETER)).intValue();
+ } catch (Exception e) {
+ LOG.warn("Start-index could not be parsed - " + e.getMessage(), e);
+ }
+ return retval < 0 ? DEFAULT_START_INDEX : retval;
+ }
+
+ /**
+ * The selfid is href pointing to the requested resource
+ *
+ * @return - the self id
+ */
+ public String getSelfId() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(buildRequestIDString(false));
+
+ builder.append(getQueryString());
+
+ return builder.toString();
+ }
+
+ /**
+ * The href id of the next page of the requested resource.
+ *
+ * @return the id of the next page
+ */
+ public String getNextId() {
+ // StringBuilder builder = new StringBuilder();
+ // builder.append(buildRequestIDString());
+ //
+ // builder.append(getQueryString());
+ //
+ // if(this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER)==
+ // null){
+ // builder.append("&").append(START_INDEX_NEXT_PAGE_PARAMETER).append("=");
+ // builder.append(DEFAULT_ITEMS_PER_PAGE+1);
+ // }
+ // else{
+ //
+ // int next = 0;
+ // try{
+ // next =
+ // Integer.parseInt(this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER));
+ // }catch (Exception e) {
+ // //
+ // }
+ //
+ // if(next < 0)
+ // builder.append(DEFAULT_ITEMS_PER_PAGE+1);
+ // else
+ // builder.append(next+DEFAULT_ITEMS_PER_PAGE);
+ // int pos = builder.indexOf(START_INDEX_NEXT_PAGE_PARAMETER);
+ // boolean end = builder.lastIndexOf("&",pos) < pos;
+ // builder.replace(pos+START_INDEX_NEXT_PAGE_PARAMETER.length()+1,pos+START_INDEX_NEXT_PAGE_PARAMETER.length()+3,""+next);
+ //
+ //
+ // System.out.println(end);
+ // }
+ //
+ //
+ //
+ // return builder.toString();
+ return buildRequestIDString(false);
+
+ }
+
+ private String buildRequestIDString(boolean endingSlash) {
+ StringBuilder builder = new StringBuilder("http://");
+ builder.append(this.request.getHeader("Host"));
+ builder.append(this.request.getRequestURI());
+ if (endingSlash && !this.request.getRequestURI().endsWith("/"))
+ builder.append("/");
+
+ return builder.toString();
+ }
+
+ /**
+ * This will return the current query string including all parameters.
+ * Additionaly the max-resul parameter will be added if not
+ * specified.
+ *
+ * max-resul indicates the number of results returned to the
+ * client. The default value is 25.
+ *
+ *
+ * @return - the query string incluing all parameters
+ */
+ public String getQueryString() {
+ String retVal = this.request.getQueryString();
+
+ if (this.request.getParameter(ITEMS_PER_PAGE_PARAMETER) != null)
+ return retVal;
+ String tempString = (retVal == null ? "?" + ITEMS_PER_PAGE_PARAMETER
+ + "=" + DEFAULT_ITEMS_PER_PAGE : "&" + ITEMS_PER_PAGE_PARAMETER
+ + "=" + DEFAULT_ITEMS_PER_PAGE);
+
+ return retVal == null ? tempString : retVal + tempString;
+
+ }
+
+ /**
+ * This enum represents the OutputFormat of the GDATA Server
+ *
+ * @author Simon Willnauer
+ *
+ */
+ public static enum OutputFormat {
+ /**
+ * Output format ATOM. ATOM is the default response format.
+ */
+ ATOM,
+ /**
+ * Output format RSS
+ */
+ RSS
+ }
+
+ /**
+ * Returns the requested path including the domain name and the requested
+ * resource http://www.apache.org/path/resource/
+ *
+ * @return the context path
+ */
+ public String getContextPath() {
+ if (this.contextPath == null)
+ this.contextPath = buildRequestIDString(true);
+ return this.contextPath;
+ }
+
+ /**
+ * Indicates the request type
+ *
+ * @author Simon Willnauer
+ *
+ */
+ public enum GDataRequestType {
+ /**
+ * Type FeedRequest
+ */
+ GET,
+ /**
+ * Type UpdateRequest
+ */
+ UPDATE,
+ /**
+ * Type DeleteRequest
+ */
+ DELETE,
+ /**
+ * Type InsertRequest
+ */
+ INSERT
+ }
+
+ /**
+ * {@link GDataRequestType}
+ *
+ * @return the current request type
+ */
+ public GDataRequestType getType() {
+ return this.type;
+ }
+
+ /**
+ * If the reuquest is a {@link GDataRequestType#GET} request and there is
+ * no entry id specified, the requested resource is a feed.
+ *
+ * @return - true if an only if the requested resource is a feed
+ */
+ public boolean isFeedRequested() {
+
+ return (this.type.equals(GDataRequestType.GET) && (this.entryId == null|| this.entryId.length() == 0|| (this.entryId.equals('/'))));
+ }
+
+ /**
+ * * If the reuquest is a {@link GDataRequestType#GET} request and there is
+ * an entry id specified, the requested resource is an entry.
+ *
+ * @return - true if an only if the requested resource is an entry
+ */
+ public boolean isEntryRequested() {
+ return !this.isFeedRequested();
+ }
+
+ /**
+ * @return - the extensionProfile for the requested resource
+ */
+ public ExtensionProfile getExtensionProfile() {
+ return this.extensionProfile;
+ }
+
+}
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/package.html
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/package.html (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/package.html (revision 0)
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+GData-Server classes encapsulation all protocol-level interactions and underlaying GData components.
+
+
\ No newline at end of file
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/data/package.html
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/data/package.html (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/data/package.html (revision 0)
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+Contains classes for the internal representation of GData feeds and entries.
+
+
\ No newline at end of file
Index: trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/package.html
===================================================================
--- trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/package.html (revision 0)
+++ trunk/contrib/gdata-server/src/java/org/apache/lucene/gdata/package.html (revision 0)
@@ -0,0 +1 @@
+Top-level package.
\ No newline at end of file
Index: trunk/contrib/gdata-server/src/java/lucenestorage.properties.xml
===================================================================
--- trunk/contrib/gdata-server/src/java/lucenestorage.properties.xml (revision 0)
+++ trunk/contrib/gdata-server/src/java/lucenestorage.properties.xml (revision 0)
@@ -0,0 +1,11 @@
+
+
+
+Lucene Storage Properties
+20
+20
+20
+/tmp/storage/
+true
+false
+
Index: trunk/contrib/gdata-server/build.xml
===================================================================
--- trunk/contrib/gdata-server/build.xml (revision 0)
+++ trunk/contrib/gdata-server/build.xml (revision 0)
@@ -0,0 +1,50 @@
+
+
+
+
+
+ Serverside Google Data API implementation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Prepare dist directory
+
+
+
+
+ Distributing GData War
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file