From 4707eea96c4bf5ce0acd4981a2ac7819ea5a7d72 Mon Sep 17 00:00:00 2001
From: Yonik Seeley
Date: Mon, 26 Jun 2006 18:14:53 +0000
Subject: [PATCH] gdata dev update from Simon 2006-06-06
git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@417265 13f79535-47bb-0310-9956-ffa450edef68
---
contrib/gdata-server/build.xml | 18 +-
.../gdata-server/lib/commons-beanutils.jar | 2 +
.../lib/commons-collections-3.2.jar | 2 +
.../gdata-server/lib/commons-digester-1.7.jar | 2 +
.../src/java/lucenestorage.properties.xml | 11 -
.../gdata/server/GDataEntityBuilder.java | 314 +++---
.../lucene/gdata/server/GDataRequest.java | 951 ++++++++++--------
.../lucene/gdata/server/GDataResponse.java | 504 +++++-----
.../lucene/gdata/server/GDataService.java | 669 +++++++-----
.../apache/lucene/gdata/server/Service.java | 25 +-
.../lucene/gdata/server/ServiceException.java | 103 +-
.../lucene/gdata/server/ServiceFactory.java | 145 ++-
.../server/registry/DataBuilderException.java | 62 --
.../registry/FeedInstanceConfigurator.java | 66 --
.../server/registry/GDataServerRegistry.java | 402 +++++---
.../server/registry/RegistryBuilder.java | 81 +-
.../registry/RegistryContextListener.java | 139 +--
.../lucene/gdata/server/registry/package.html | 2 +-
.../gdata/servlet/AbstractGdataServlet.java | 20 +-
.../servlet/RequestControllerServlet.java | 220 ++--
.../handler/AbstractGdataRequestHandler.java | 198 ++--
.../servlet/handler/DefaultDeleteHandler.java | 165 ++-
.../servlet/handler/DefaultGetHandler.java | 236 +++--
.../servlet/handler/DefaultInsertHandler.java | 167 +--
.../handler/DefaultRequestHandlerFactory.java | 214 ++--
.../servlet/handler/DefaultUpdateHandler.java | 179 ++--
.../handler/RequestHandlerFactory.java | 218 ++--
.../lucene/gdata/storage/IDGenerator.java | 8 +-
.../apache/lucene/gdata/storage/Storage.java | 346 +++++--
.../gdata/storage/StorageController.java | 84 +-
.../lucene/gdata/storage/StorageFactory.java | 44 -
.../storage/lucenestorage/StorageBuffer.java | 91 +-
.../lucenestorage/StorageCoreController.java | 678 +++++++------
.../lucenestorage/StorageEntryWrapper.java | 386 +++----
.../lucenestorage/StorageImplementation.java | 779 +++++++++-----
.../lucenestorage/StorageModifier.java | 677 ++++++++-----
.../storage/lucenestorage/StorageQuery.java | 806 +++++++++------
.../configuration/StorageConfigurator.java | 13 +-
.../lucene/gdata/server/TestGDataRequest.java | 79 +-
.../gdata/server/TestGDataResponse.java | 7 +-
.../server/registry/TestFeedRegistry.java | 230 +++--
.../registry/TestGDataEntityBuilder.java | 67 +-
.../lucenestorage/TestStorageModifier.java | 632 +++++++-----
.../lucenestorage/TestStorageQuery.java | 431 ++++----
contrib/gdata-server/webroot/WEB-INF/web.xml | 81 +-
45 files changed, 6168 insertions(+), 4386 deletions(-)
create mode 100644 contrib/gdata-server/lib/commons-beanutils.jar
create mode 100644 contrib/gdata-server/lib/commons-collections-3.2.jar
create mode 100644 contrib/gdata-server/lib/commons-digester-1.7.jar
diff --git a/contrib/gdata-server/build.xml b/contrib/gdata-server/build.xml
index e3210b9baec..5251383f22e 100644
--- a/contrib/gdata-server/build.xml
+++ b/contrib/gdata-server/build.xml
@@ -16,7 +16,11 @@
-
+
+
+
+
+
@@ -36,15 +40,19 @@
Distributing GData War
+ webxml="webroot/WEB-INF/web.xml" >
+
+
+
-
-
+
+
+
-
+
\ No newline at end of file
diff --git a/contrib/gdata-server/lib/commons-beanutils.jar b/contrib/gdata-server/lib/commons-beanutils.jar
new file mode 100644
index 00000000000..e2113569e52
--- /dev/null
+++ b/contrib/gdata-server/lib/commons-beanutils.jar
@@ -0,0 +1,2 @@
+AnyObjectId[b1b89c9c921f16af22a88db3ff28975a8e40d886] was removed in git history.
+Apache SVN contains full history.
\ No newline at end of file
diff --git a/contrib/gdata-server/lib/commons-collections-3.2.jar b/contrib/gdata-server/lib/commons-collections-3.2.jar
new file mode 100644
index 00000000000..8071d63ea7a
--- /dev/null
+++ b/contrib/gdata-server/lib/commons-collections-3.2.jar
@@ -0,0 +1,2 @@
+AnyObjectId[75580be255065727b20b41c2d338b14792bb35cd] was removed in git history.
+Apache SVN contains full history.
\ No newline at end of file
diff --git a/contrib/gdata-server/lib/commons-digester-1.7.jar b/contrib/gdata-server/lib/commons-digester-1.7.jar
new file mode 100644
index 00000000000..97d5d0558a8
--- /dev/null
+++ b/contrib/gdata-server/lib/commons-digester-1.7.jar
@@ -0,0 +1,2 @@
+AnyObjectId[1783dbea232ced6db122268f8faa5ce773c7ea42] was removed in git history.
+Apache SVN contains full history.
\ No newline at end of file
diff --git a/contrib/gdata-server/src/java/lucenestorage.properties.xml b/contrib/gdata-server/src/java/lucenestorage.properties.xml
index 8c0c5be75b2..e69de29bb2d 100644
--- a/contrib/gdata-server/src/java/lucenestorage.properties.xml
+++ b/contrib/gdata-server/src/java/lucenestorage.properties.xml
@@ -1,11 +0,0 @@
-
-
-
-Lucene Storage Properties
-20
-20
-20
-/tmp/storage/
-true
-false
-
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataEntityBuilder.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataEntityBuilder.java
index 32853fa70ee..62e8584fa4f 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataEntityBuilder.java
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataEntityBuilder.java
@@ -12,160 +12,160 @@
* 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();
- }
-
-}
+ */
+package org.apache.lucene.gdata.server;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.lucene.gdata.server.registry.ProvidedService;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.BaseFeed;
+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.
+ *
+ *
+ * This build will not returne the abstract base classes.
+ *
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class GDataEntityBuilder {
+
+ /**
+ * 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 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 IOException, ParseException {
+ if (request == null)
+ throw new IllegalArgumentException("request must not be null");
+ ProvidedService config = request.getConfigurator();
+ return buildFeed(request.getReader(), config);
+ }
+
+ /**
+ * Builds a {@link BaseFeed} from the provided {@link Reader}
+ *
+ *
+ * @param reader -
+ * the reader to build the feed from
+ * @param config -
+ * the feed instance config containing the extension profile to
+ * parse the resource
+ * @return - a BaseFeed instance
+ *
+ * @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 Reader reader,
+ final ProvidedService config) throws ParseException, IOException {
+
+ BaseFeed retVal = null;
+ retVal = createEntityInstance(config);
+ retVal.parseAtom(config.getExtensionProfile(), 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 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 IOException, ParseException {
+ if (request == null)
+ throw new IllegalArgumentException("request must not be null");
+ ProvidedService config = request.getConfigurator();
+ return buildEntry(request.getReader(), config);
+ }
+
+ /**
+ * Builds a {@link BaseFeed} instance from the {@link Reader} provided by
+ * the {@link GDataRequest}
+ *
+ * @param reader -
+ * the reader to build the feed from
+ * @param config -
+ * the instance config containing the extension profile to parse
+ * the resource
+ * @return - a BaseFeed instance
+ *
+ * @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 Reader reader,
+ final ProvidedService config) throws ParseException, IOException {
+
+ BaseEntry e = createEntityInstance(config).createEntry();
+ e.parseAtom(config.getExtensionProfile(), reader);
+ return e;
+ }
+
+ private static BaseFeed createEntityInstance(
+ final ProvidedService config) {
+ if(config.getFeedType() == null)
+ throw new IllegalArgumentException("feedtype is null in ProvidedService");
+
+ BaseFeed retVal = null;
+ try {
+ retVal = (BaseFeed) config.getFeedType().newInstance();
+ } catch (Exception e) {
+ throw new EntityBuilderException("Can't instanciate Feed for feedType "+config.getFeedType().getName(),e);
+ }
+ return retVal;
+ }
+ static class EntityBuilderException extends RuntimeException{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7224011324202237951L;
+
+ EntityBuilderException(String arg0) {
+ super(arg0);
+
+ }
+
+ EntityBuilderException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+
+ }
+
+ }
+}
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataRequest.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataRequest.java
index 35efe9ab9c4..ea14cda3a0e 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataRequest.java
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataRequest.java
@@ -12,431 +12,526 @@
* 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;
- }
-
-}
+ */
+
+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.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.server.authentication.AuthenticationController;
+import org.apache.lucene.gdata.server.registry.ComponentType;
+import org.apache.lucene.gdata.server.registry.ProvidedService;
+import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
+import org.apache.lucene.gdata.storage.Storage;
+import org.apache.lucene.gdata.storage.StorageController;
+
+/**
+ * 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";
+
+ private static final String HTTP_HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
+
+ private static final String HTTP_HEADER_AUTH = "Authorization";
+
+ // Atom is the default resopnse format
+ private OutputFormat responseFormat = OutputFormat.ATOM;
+
+ private final HttpServletRequest request;
+
+ private String feedId = null;
+
+ private String entryId = null;
+
+ private ProvidedService configurator = 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();
+ // TODO remove this dependency
+ StorageController controller = GDataServerRegistry.getRegistry()
+ .lookup(StorageController.class,
+ ComponentType.STORAGECONTROLLER);
+ try {
+
+ Storage storage = controller.getStorage();
+
+ String service = storage.getServiceForFeed(this.feedId);
+ /*
+ * ExtensionProfile and the type is used for building the Entry /
+ * Feed Instances from an inputstream or reader
+ *
+ */
+ this.configurator = GDataServerRegistry.getRegistry()
+ .getProvidedService(service);
+ if (this.configurator == null)
+ throw new GDataRequestException(
+ "feed is not registered or extension profile could not be created");
+
+ } catch (Exception e) {
+ 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("?");
+ 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(false));
+ builder.append("?");
+
+ Enumeration parameters = this.request.getParameterNames();
+ while (parameters.hasMoreElements()) {
+ String element = (String) parameters.nextElement();
+ String[] values = this.request.getParameterValues(element);
+ for (int i = 0; i < values.length; i++) {
+
+ builder.append(element).append("=");
+ if (element.equals(START_INDEX_NEXT_PAGE_PARAMETER)) {
+ int tempVal = DEFAULT_START_INDEX;
+ try {
+ tempVal = Integer.parseInt(values[i]);
+ } catch (Exception e) {
+ LOG.info("Can not parse StartIndex -- use defaut");
+ }
+ builder.append(tempVal + getItemsPerPage());
+ break;
+ }
+
+ builder.append(values[i]);
+
+ }
+ if (parameters.hasMoreElements())
+ builder.append("&");
+
+ }
+ if (this.request.getParameter(ITEMS_PER_PAGE_PARAMETER) == null) {
+ if (builder.charAt(builder.length() - 1) != '?')
+ builder.append('&');
+ builder.append(ITEMS_PER_PAGE_PARAMETER).append("=").append(
+ DEFAULT_ITEMS_PER_PAGE);
+ }
+ if (this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER) == null) {
+ builder.append('&');
+ builder.append(START_INDEX_NEXT_PAGE_PARAMETER).append("=");
+ builder.append(DEFAULT_ITEMS_PER_PAGE + 1);
+ }
+
+ return builder.toString();
+
+ }
+
+ 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 configuration for this request
+ */
+ public ProvidedService getConfigurator() {
+ return this.configurator;
+ }
+
+ /**
+ * @return - Returns the Internet Protocol (IP) address of the client or
+ * last proxy that sent the request.
+ */
+ public String getRemoteAddress() {
+ return this.request.getRemoteAddr();
+ }
+
+ /**
+ * @return - the value for the send auth token. The auth token will be send
+ * as a request Authentication header.
+ */
+ public String getAuthToken() {
+ String token = this.request.getHeader(HTTP_HEADER_AUTH);
+ if (token == null)
+ return null;
+ token = token.substring(token.indexOf("=") + 1);
+ return token;
+ }
+
+ /**
+ * @return - Returns an array containing all of the Cookie objects the
+ * client sent with underlaying HttpServletRequest.
+ */
+ public Cookie[] getCookies() {
+ return this.request.getCookies();
+ }
+
+ /**
+ * @return - the cookie set instead of the authentication token or
+ * null
if not auth cookie is set
+ */
+ public Cookie getAuthCookie() {
+ Cookie[] cookies = this.request.getCookies();
+ if (cookies == null)
+ return null;
+ for (int i = 0; i < cookies.length; i++) {
+ if (cookies[i].getName().equals(AuthenticationController.TOKEN_KEY))
+ return cookies[i];
+ }
+ return null;
+ }
+
+ /**
+ * @return - the date string of the If-Modified-Since HTTP
+ * request header, or null if header is not set
+ */
+ public String getModifiedSince() {
+ return this.request.getHeader(HTTP_HEADER_IF_MODIFIED_SINCE);
+ }
+
+ /**
+ * @return - the underlaying HttpServletRequest
+ */
+ public HttpServletRequest getHttpServletRequest() {
+
+ return this.request;
+ }
+}
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataResponse.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataResponse.java
index 870cc1bc3ad..1f54cdef46d 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataResponse.java
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataResponse.java
@@ -12,231 +12,279 @@
* 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();
-
-
- }
-
-}
+ */
+
+package org.apache.lucene.gdata.server;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Date;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.lucene.gdata.server.GDataRequest.OutputFormat;
+import org.apache.lucene.gdata.utils.DateFormater;
+
+import com.google.gdata.data.BaseEntry;
+import com.google.gdata.data.BaseFeed;
+import com.google.gdata.data.DateTime;
+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.
+ *
+ *
+ * This class will set the HTTP Last-Modified Header to enable
+ * clients to send If-Modified-Since request header to avoid
+ * retrieving the content again if it hasn't changed. If the content hasn't
+ * changed since the If-Modified-Since time, then the GData service returns a
+ * 304 (Not Modified) HTTP response.
+ *
+ *
+ *
+ *
+ *
+ * @author Simon Willnauer
+ *
+ */
+public class GDataResponse {
+ private int error;
+
+ private boolean isError = false;
+
+ private String encoding;
+
+ private OutputFormat outputFormat;
+
+ private final HttpServletResponse response;
+
+ protected static final String XMLMIME_ATOM = "text/xml";
+
+ protected static final String XMLMIME_RSS = "text/xml";
+
+ private static final String DEFAUL_NAMESPACE_URI = "http://www.w3.org/2005/Atom";
+
+ private static final Namespace DEFAULT_NAMESPACE = new Namespace("",
+ DEFAUL_NAMESPACE_URI);
+
+ private static final String HEADER_LASTMODIFIED = "Last-Modified";
+
+ /**
+ * 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;
+
+ }
+
+ /**
+ * 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");
+ DateTime time = feed.getUpdated();
+ if (time != null)
+ setLastModifiedHeader(time.getValue());
+ XmlWriter writer = createWriter();
+
+ if (this.outputFormat.equals(OutputFormat.ATOM)) {
+ this.response.setContentType(XMLMIME_ATOM);
+ feed.generateAtom(writer, profile);
+ } else {
+ this.response.setContentType(XMLMIME_RSS);
+ 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");
+ DateTime time = entry.getUpdated();
+ if (time != null)
+ setLastModifiedHeader(time.getValue());
+ 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();
+
+ }
+
+ protected void setLastModifiedHeader(long lastModified) {
+ String lastMod = DateFormater.formatDate(new Date(lastModified),
+ DateFormater.HTTP_HEADER_DATE_FORMAT);
+ this.response.setHeader(HEADER_LASTMODIFIED, lastMod);
+ }
+
+ /**
+ * @see HttpServletResponse#setStatus(int)
+ * @param status - the request status code
+ */
+ public void setStatus(int status){
+ this.response.setStatus(status);
+ }
+
+}
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataService.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataService.java
index 81b67f9404d..8cd52dbba9b 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataService.java
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/GDataService.java
@@ -1,275 +1,398 @@
-/**
- * Copyright 2004 The Apache Software Foundation
+/**
+ * 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.Date;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.data.ServerBaseEntry;
+import org.apache.lucene.gdata.data.ServerBaseFeed;
+import org.apache.lucene.gdata.server.registry.ComponentType;
+import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
+import org.apache.lucene.gdata.storage.ResourceNotFoundException;
+import org.apache.lucene.gdata.storage.Storage;
+import org.apache.lucene.gdata.storage.StorageController;
+import org.apache.lucene.gdata.storage.StorageException;
+
+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;
+
+/**
+ * default implementation of the {@link org.apache.lucene.gdata.server.Service}
+ * interface.
*
- * 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
+ * @author Simon Willnauer
*
- * 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;
- }
- }
-
-}
+ */
+public class GDataService implements Service {
+ private static final Log LOGGER = LogFactory.getLog(GDataService.class);
+
+ protected Storage storage;
+
+ protected 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";
+
+ private static final String XMLMIME = "application/atom+xml";
+ static {
+ generator = new Generator();
+ generator.setName(generatorName);
+ generator.setUri(generatorURI);
+ generator.setVersion("0.1");
+ }
+
+ protected GDataService() throws ServiceException {
+ try {
+ StorageController controller = GDataServerRegistry.getRegistry()
+ .lookup(StorageController.class,
+ ComponentType.STORAGECONTROLLER);
+ if (controller == null)
+ throw new StorageException(
+ "StorageController is not registered");
+ this.storage = controller.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)
+ */
+
+ public BaseEntry createEntry(GDataRequest request, GDataResponse response)
+ throws ServiceException {
+
+ if (LOGGER.isInfoEnabled())
+ LOGGER.info("create Entry for feedId: " + request.getFeedId());
+
+ ServerBaseEntry entry = buildEntry(request, response);
+ entry.setFeedId(request.getFeedId());
+ entry.setServiceConfig(request.getConfigurator());
+ setTimeStamps(entry.getEntry());
+ BaseEntry retVal = null;
+ try {
+ retVal = this.storage.storeEntry(entry);
+ } catch (Exception e) {
+ response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ ServiceException ex = new ServiceException("Could not store entry",
+ e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ return retVal;
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.Service#deleteEntry(org.apache.lucene.gdata.server.GDataRequest,
+ * org.apache.lucene.gdata.server.GDataResponse)
+ */
+
+ public BaseEntry deleteEntry(GDataRequest request, GDataResponse response)
+ throws ServiceException {
+
+ ServerBaseEntry entry = new ServerBaseEntry();
+ entry.setServiceConfig(request.getConfigurator());
+ entry.setFeedId(request.getFeedId());
+ entry.setId(request.getEntryId());
+ if (entry.getId() == null)
+ throw new ServiceException(
+ "entry id is null -- can not delete null entry");
+ try {
+ this.storage.deleteEntry(entry);
+ } catch (ResourceNotFoundException e) {
+ response.setError(HttpServletResponse.SC_BAD_REQUEST);
+ ServiceException ex = new ServiceException(
+ "Could not delete entry", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ } catch (Exception e) {
+ response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ 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)
+ */
+
+ public BaseEntry updateEntry(GDataRequest request, GDataResponse response)
+ throws ServiceException {
+
+ ServerBaseEntry entry = buildEntry(request, response);
+ entry.setFeedId(request.getFeedId());
+
+ entry.setServiceConfig(request.getConfigurator());
+ if (LOGGER.isInfoEnabled())
+ LOGGER.info("update Entry" + entry.getId() + " for feedId: "
+ + request.getFeedId());
+ if (entry.getId() == null) {
+ response.setError(HttpServletResponse.SC_BAD_REQUEST);
+ throw new ServiceException("Entry id is null can not update entry");
+ }
+ if (!entry.getId().equals(request.getEntryId())) {
+ if (LOGGER.isInfoEnabled())
+ LOGGER
+ .info("Entry id in the entry xml does not match the requested resource -- XML-ID:"
+ + entry.getId()
+ + "; Requested resource: "
+ + request.getEntryId());
+ response.setError(HttpServletResponse.SC_BAD_REQUEST);
+ throw new ServiceException(
+ "Entry id in the entry xml does not match the requested resource");
+ }
+ setTimeStamps(entry.getEntry());
+ BaseEntry retVal = null;
+ try {
+ retVal = this.storage.updateEntry(entry);
+ } catch (ResourceNotFoundException e) {
+ response.setError(HttpServletResponse.SC_BAD_REQUEST);
+ ServiceException ex = new ServiceException(
+ "Could not update entry", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ } catch (StorageException e) {
+ response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ ServiceException ex = new ServiceException(
+ "Could not update entry", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ return retVal;
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.Service#getFeed(org.apache.lucene.gdata.server.GDataRequest,
+ * org.apache.lucene.gdata.server.GDataResponse)
+ */
+ @SuppressWarnings("unchecked")
+ public BaseFeed getFeed(GDataRequest request, GDataResponse response)
+ throws ServiceException {
+
+ ServerBaseFeed feed = new ServerBaseFeed();
+ feed.setId(request.getFeedId());
+ feed.setStartIndex(request.getStartIndex());
+ feed.setItemsPerPage(request.getItemsPerPage());
+ feed.setServiceConfig(request.getConfigurator());
+ try {
+ BaseFeed retVal = this.storage.getFeed(feed);
+ dynamicElementFeedStragey(retVal, request);
+
+ return retVal;
+ /*
+ * resouce not found will be detected in Gdata request.
+ * the request queries the storage for the feed to get the serivce for the feed
+ */
+ } catch (StorageException e) {
+ response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ ServiceException ex = new ServiceException("Could not get feed", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+
+ }
+
+ private Link buildLink(String rel, String type, String href) {
+ Link retVal = new Link();
+ retVal.setHref(href);
+ retVal.setRel(rel);
+ retVal.setType(type);
+ return retVal;
+ }
+
+ private ServerBaseEntry buildEntry(final GDataRequest request,
+ final GDataResponse response) throws ServiceException {
+ try {
+ ServerBaseEntry entry = new ServerBaseEntry(GDataEntityBuilder
+ .buildEntry(request));
+ return entry;
+
+ } catch (ParseException e) {
+ response.setError(HttpServletResponse.SC_BAD_REQUEST);
+ ServiceException ex = new ServiceException(
+ "Could not parse entry from incoming request", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ } catch (IOException e) {
+ response.setError(HttpServletResponse.SC_BAD_REQUEST);
+ ServiceException ex = new ServiceException(
+ "Could not read or open input stream", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ }
+
+ private BaseEntry setTimeStamps(final BaseEntry entry) {
+ if (entry.getUpdated() == null)
+ entry.setUpdated(DateTime.now());
+ if (entry.getPublished() == null)
+ entry.setPublished(DateTime.now());
+ return entry;
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.Service#getSingleEntry(org.apache.lucene.gdata.server.GDataRequest,
+ * org.apache.lucene.gdata.server.GDataResponse)
+ */
+
+ public BaseEntry getSingleEntry(GDataRequest request, GDataResponse response)
+ throws ServiceException {
+
+ try {
+ ServerBaseEntry entry = new ServerBaseEntry();
+ entry.setServiceConfig(request.getConfigurator());
+ entry.setFeedId(request.getFeedId());
+ entry.setId(request.getEntryId());
+ if(entry.getId() == null){
+ response.setError(HttpServletResponse.SC_BAD_REQUEST);
+ throw new ServiceException("entry is null can't get entry");
+ }
+
+ BaseEntry retVal = null;
+ retVal = this.storage.getEntry(entry);
+ dynamicElementEntryStragey(retVal, request);
+ return retVal;
+ } catch (ResourceNotFoundException e) {
+ response.setError(HttpServletResponse.SC_BAD_REQUEST);
+ ServiceException ex = new ServiceException(
+ "Could not get entry", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ } catch (StorageException e) {
+ ServiceException ex = new ServiceException("Could not get feed", e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+ }
+
+ /*
+ * adds all dynamic element to the entry
+ */
+ private void dynamicElementEntryStragey(final BaseEntry entry,
+ final GDataRequest request) {
+ setSelfLink(entry, request.getContextPath());
+ }
+
+ /*
+ * adds all dynamic element to the feed entries
+ */
+ @SuppressWarnings("unchecked")
+ private void dynamicElementFeedStragey(final BaseFeed feed,
+ final GDataRequest request) {
+ buildDynamicFeedElements(request, feed);
+ List entryList = feed.getEntries();
+ for (BaseEntry entry : entryList) {
+ String id = request.getContextPath() + entry.getId();
+ setSelfLink(entry, id);
+ }
+
+ }
+
+ /*
+ * The selfLink is build from a prefix and the entry id. The prefix is the
+ * context path of the requested feed. This will be used to request the
+ * entry directly
+ */@SuppressWarnings("unchecked")
+ private BaseEntry setSelfLink(final BaseEntry entry, String id) {
+ Link self = buildLink(Link.Rel.SELF, XMLMIME, id);
+ entry.getLinks().add(self);
+ return entry;
+ }
+
+ /*
+ * 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.setStartIndex(request.getStartIndex());
+ feed.setId(request.getContextPath());
+ feed.getLinks().add(
+ buildLink(Link.Rel.SELF, Link.Type.ATOM, request.getSelfId()));
+ feed.getLinks().add(
+ buildLink(Link.Rel.NEXT, XMLMIME, request.getNextId()));
+
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.Service#close()
+ */
+ public void close() {
+ this.storage.close();
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.Service#getFeedLastModified(java.lang.String)
+ */
+ public Date getFeedLastModified(final String feedId) throws ServiceException {
+ try {
+ return new Date(this.storage.getFeedLastModified(feedId));
+
+ } catch (StorageException e) {
+ ServiceException ex = new ServiceException(
+ "Could not get Last update for feed -- "+feedId, e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.Service#getEntryLastModified(java.lang.String, java.lang.String)
+ */
+ public Date getEntryLastModified(final String entryId,final String feedId) throws ServiceException {
+ try {
+ return new Date(this.storage.getEntryLastModified(entryId, feedId));
+
+
+
+ } catch (StorageException e) {
+ ServiceException ex = new ServiceException(
+ "Could not get Last update for entry -- "+entryId, e);
+ ex.setStackTrace(e.getStackTrace());
+ throw ex;
+ }
+
+ }
+
+}
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/Service.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/Service.java
index bc1d8bf36a3..a3d7d8db4f7 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/Service.java
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/Service.java
@@ -16,6 +16,8 @@
package org.apache.lucene.gdata.server;
+import java.util.Date;
+
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.BaseFeed;
@@ -39,7 +41,7 @@ import com.google.gdata.data.BaseFeed;
*
*
*/
-public abstract class Service {
+public interface Service {
/**
* Service method to create an entry in an already created and existing
@@ -133,6 +135,27 @@ public abstract class Service {
public abstract BaseEntry getSingleEntry(final GDataRequest request, final GDataResponse response)
throws ServiceException;
+ /**
+ * will close the Service - service should not be used after this method has been called
+ */
+ public void close();
+
+ /**
+ * Retruns the date of the last modification for the given feed id
+ * @param feedId - the id of the feed
+ * @return - the last modified date or the current date if the date can not be retrieved
+ * @throws ServiceException - if the storage can not be accessed
+ */
+ public abstract Date getFeedLastModified(String feedId)throws ServiceException;
+
+ /**
+ * Retruns the date of the last modification for the given entry id
+ * @param entryId - the id of the entry
+ * @param feedId - the feed id this entry belongs to
+ * @return - the last modified date or the current date if the date can not be retrieved
+ * @throws ServiceException - if the storage can not be accessed
+ */
+ public abstract Date getEntryLastModified(String entryId, String feedId)throws ServiceException;
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceException.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceException.java
index 21eeec519bf..c7acbe40a0b 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceException.java
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceException.java
@@ -12,52 +12,59 @@
* 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
+ */
+
+package org.apache.lucene.gdata.server;
+
+/**
+ * The ServiceException is used to encapsulate all {@link java.lang.Exception}
+ * throw by underlaying layers of the
+ * {@link org.apache.lucene.gdata.server.Service} layer.
*
- */
-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);
-
- }
-
-}
+ * @author Simon Willnauer
+ *
+ */
+public class ServiceException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7099825107871876584L;
+
+ /**
+ * Constructs a new ServiceException
+ */
+ public ServiceException() {
+ super();
+
+ }
+
+ /**
+ * Constructs a new ServiceException
+ * @param arg0 - the exception message
+ */
+ public ServiceException(String arg0) {
+ super(arg0);
+
+ }
+
+ /**
+ * Constructs a new ServiceException
+ * @param arg0 - the exceptin message
+ * @param arg1 - the exception cause
+ */
+ public ServiceException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+
+ }
+
+ /**
+ * Constructs a new ServiceException
+ * @param arg0 - the exception cause
+ */
+ public ServiceException(Throwable arg0) {
+ super(arg0);
+
+ }
+
+}
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceFactory.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceFactory.java
index 2dcccf88ca7..08c2b2ceab4 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceFactory.java
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/ServiceFactory.java
@@ -1,57 +1,92 @@
-/**
- * Copyright 2004 The Apache Software Foundation
+/**
+ * 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 org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.gdata.server.administration.AdminService;
+import org.apache.lucene.gdata.server.administration.GDataAdminService;
+import org.apache.lucene.gdata.server.registry.Component;
+import org.apache.lucene.gdata.server.registry.ComponentType;
+import org.apache.lucene.gdata.server.registry.ServerComponent;
+
+
+/**
+ * The {@link ServiceFactory} creates {@link Service} implementations to access
+ * the GData - Server components.
+ * This class should not be access directy. The class will be registered in the {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry}.
+ * Use {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry#lookup(Class, ComponentType)}
*
- * 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
+ * @author Simon Willnauer
*
- * 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;
- }
-}
+ */
+@Component(componentType=ComponentType.SERVICEFACTORY)
+public class ServiceFactory implements ServerComponent {
+
+ private static final Log LOG = LogFactory.getLog(ServiceFactory.class);
+
+
+
+ /**
+ * public constructor to enable loading via the registry
+ * @see org.apache.lucene.gdata.server.registry.Component
+ * @see org.apache.lucene.gdata.server.registry.GDataServerRegistry
+ */
+ public ServiceFactory() {
+ //
+ }
+
+ /**
+ * Creates a {@link Service} instance.
+ *
+ * @return a Service instance
+ */
+ public Service getService() {
+ try{
+ return new GDataService();
+ }catch (Exception e) {
+ //
+ }
+ return null;
+ }
+
+ /**
+ * Creates a {@link AdminService} instance
+ * @return a AdminService instance
+ */
+ public AdminService getAdminService(){
+ try {
+ return new GDataAdminService();
+ } catch (ServiceException e) {
+ LOG.warn("Factory method can not create GDataAdminService returning null-- "+e.getMessage(),e);
+ }
+ return null;
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.registry.ServerComponent#initialize()
+ */
+ public void initialize() {
+ //
+ }
+
+ /**
+ * @see org.apache.lucene.gdata.server.registry.ServerComponent#destroy()
+ */
+ public void destroy() {
+ //
+ }
+}
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/DataBuilderException.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/DataBuilderException.java
index 3193b7a2de4..e69de29bb2d 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/DataBuilderException.java
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/DataBuilderException.java
@@ -1,62 +0,0 @@
-/**
- * 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
- }
-
-}
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/FeedInstanceConfigurator.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/FeedInstanceConfigurator.java
index 4913b2240ea..e69de29bb2d 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/FeedInstanceConfigurator.java
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/FeedInstanceConfigurator.java
@@ -1,66 +0,0 @@
-/**
- * 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;
- }
-
-
-}
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/GDataServerRegistry.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/GDataServerRegistry.java
index 44db88daa69..ea470b94a2c 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/GDataServerRegistry.java
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/GDataServerRegistry.java
@@ -1,154 +1,254 @@
-/**
- * Copyright 2004 The Apache Software Foundation
+/**
+ * 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;
+
+/**
*
- * 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
+ * The GDataServerRegistry represents the registry component of the GData
+ * Server. All provided services and server components will be registered here.
+ * The Gdata Server serves RSS / ATOM feeds for defined services. Each service
+ * provides n feeds of a defined subclass of
+ * {@link com.google.gdata.data.BaseFeed}. Each feed contains m entries
+ * of a defined subclass of {@link com.google.gdata.data.BaseEntry}. To
+ * generate RSS / ATOM formates a class of the type
+ * {@link com.google.gdata.data.ExtensionProfile} is also defined for a service.
+ *
+ * The entry,feed and the ExtensionProfile classes are defined in the
+ * gdata-config.xml and will be loaded when the server starts up.
+ *
+ *
+ * The components defined in the gdata-config.xml will also be loaded and
+ * instanciated at startup. If a component can not be loaded or an Exception
+ * occures the server will not start up. To cause of the exception or error will
+ * be logged to the standart server output.
+ *
+ * The GDataServerRegistry is a Singleton
*
- * 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;
- }
-
-}
+ * @author Simon Willnauer
+ *
+ */
+public class GDataServerRegistry {
+ private static GDataServerRegistry INSTANCE;
+
+ private static final Log LOGGER = LogFactory
+ .getLog(GDataServerRegistry.class);
+
+ private final Map serviceTypeMap = new HashMap();
+
+ private final Map componentMap = new HashMap(
+ 10);
+
+ 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 ProvidedService}
+ *
+ * @param configurator -
+ * the configurator to register in the registry
+ */
+ public void registerService(ProvidedService configurator) {
+ if (configurator == null) {
+ LOGGER.warn("Feedconfigurator is null -- skip registration");
+ return;
+ }
+ this.serviceTypeMap.put(configurator.getName(), configurator);
+ }
+
+ /**
+ * Looks up the {@link ProvidedServiceConfig} by the given service name.
+ *
+ * @param service
+ * @return - the {@link ProvidedServiceConfig} or null
if the
+ * no configuration for this service has been registered
+ */
+ public ProvidedService getProvidedService(String service) {
+ if (service == null)
+ throw new IllegalArgumentException(
+ "Service is null - must not be null to get registered feedtype");
+ return this.serviceTypeMap.get(service);
+ }
+
+ protected void flushRegistry() {
+ this.serviceTypeMap.clear();
+ this.componentMap.clear();
+ }
+
+ /**
+ * @param service -
+ * the name of the service
+ * @return - true
if and only if the service is registered,
+ * otherwise false
.
+ */
+ public boolean isServiceRegistered(String service) {
+ return this.serviceTypeMap.containsKey(service);
+
+ }
+
+ /**
+ * Destroys the registry and release all resources
+ */
+ public void destroy() {
+ for (ComponentBean component : this.componentMap.values()) {
+ component.getObject().destroy();
+ }
+ flushRegistry();
+
+ }
+
+ /**
+ * This method is the main interface to the Component Lookup Service of the
+ * registry. Every GDATA - Server component like STORAGE or the INDEXER
+ * component will be accessible via this method. To get a Component from the
+ * lookup service specify the expected Class as an argument and the
+ * component type of the component to return. For a lookup of the
+ * STORAGECONTORLER the code looks like:
+ *
+ * registryInstance.lookup(StorageController.class,ComponentType.STORAGECONTROLLER);
+ *
+ *
+ * @param
+ * the type of the expected return value
+ * @param clazz -
+ * Class object of the expected return value
+ * @param compType -
+ * The component type
+ * @return the registered component or null
if the component
+ * can not looked up.
+ */
+ @SuppressWarnings("unchecked")
+ public R lookup(Class clazz, ComponentType compType) {
+ ComponentBean bean = this.componentMap.get(compType);
+ if (bean == null)
+ return null;
+ if (bean.getSuperType().equals(clazz))
+ return (R) bean.getObject();
+ return null;
+ }
+
+ /**
+ * @param
+ * @param componentClass
+ * @throws RegistryException
+ */
+ @SuppressWarnings("unchecked")
+ public void registerComponent(final Class componentClass)
+ throws RegistryException {
+
+ if (componentClass == null)
+ throw new IllegalArgumentException(
+ "component class must not be null");
+
+ if(!checkImplementsServerComponent(componentClass))
+ throw new RegistryException("can not register component. the given class does not implement ServerComponent interface -- "+componentClass.getName());
+ try {
+
+ Component annotation = componentClass.getAnnotation(Component.class);
+ if (annotation == null)
+ throw new RegistryException(
+ "can not register component. the given class is not a component -- "
+ + componentClass.getName());
+ ComponentType type = annotation.componentType();
+ if (this.componentMap.containsKey(type))
+ throw new RegistryException("component already registered -- "
+ + type.name());
+ Class superType = type.getClass().getField(type.name())
+ .getAnnotation(SuperType.class).superType();
+ if (!checkSuperType(componentClass, superType))
+ throw new RegistryException("Considered Supertype <"
+ + superType.getName() + "> is not a super type of <"
+ + componentClass + ">");
+ ServerComponent comp = componentClass.newInstance();
+ comp.initialize();
+ ComponentBean bean = new ComponentBean(comp, superType);
+
+ this.componentMap.put(type, bean);
+
+ } catch (Exception e) {
+ throw new RegistryException("Can not register component -- "
+ + e.getMessage(), e);
+ }
+
+ }
+
+ private static boolean checkImplementsServerComponent(Class type){
+ if(type == null)
+ return false;
+ if(type.equals(Object.class))
+ return false;
+ if(type.equals(ServerComponent.class))
+ return true;
+ Class[] compInterfaces = type.getInterfaces();
+ for (int i = 0; i < compInterfaces.length; i++) {
+ if(checkImplementsServerComponent(compInterfaces[i]))
+ return true;
+ }
+ return checkImplementsServerComponent(type.getSuperclass());
+
+ }
+
+ private static boolean checkSuperType(Class type, Class consideredSuperType) {
+
+ if (type.equals(Object.class))
+ return false;
+ if (type.equals(consideredSuperType))
+ return true;
+ Class[] interfaces = type.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ if (interfaces[i].equals(consideredSuperType))
+ return true;
+ }
+ return checkSuperType(type.getSuperclass(), consideredSuperType);
+ }
+
+ private class ComponentBean {
+ private final Class superType;
+
+ private final ServerComponent object;
+
+ ComponentBean(final ServerComponent object, final Class superType) {
+ this.superType = superType;
+ this.object = object;
+ }
+
+ ServerComponent getObject() {
+ return this.object;
+ }
+
+ Class getSuperType() {
+ return this.superType;
+ }
+
+ }
+
+}
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryBuilder.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryBuilder.java
index fc75b0c3290..11cb0383731 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryBuilder.java
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryBuilder.java
@@ -12,30 +12,59 @@
* 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
+ */
+package org.apache.lucene.gdata.server.registry;
+
+import java.io.IOException;
+
+import org.apache.commons.digester.Digester;
+import org.xml.sax.SAXException;
+
+/**
+ * Reads the configuration file and creates the
+ * {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry} singleton
+ * instance. All services and components will be instanciated and registered in
+ * the registry.
*
- */
-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);
-
- }
-
-}
+ * @author Simon Willnauer
+ *
+ */
+class RegistryBuilder {
+
+ /**
+ * builds the {@link GDataServerRegistry} accessible via the
+ * {@link GDataServerRegistry#getRegistry()} method
+ *
+ * @throws IOException -
+ * if an IOException occures while reading the config file
+ * @throws SAXException -
+ * if the config file can not be parsed
+ */
+ static void buildRegistry() throws IOException, SAXException {
+
+ buildFromConfiguration(new Digester(), GDataServerRegistry
+ .getRegistry());
+
+ }
+
+ private static void buildFromConfiguration(Digester digester,
+ GDataServerRegistry registry) throws IOException, SAXException {
+
+ digester.setValidating(false);
+ digester.push(registry);
+ digester.addCallMethod("gdata/server-components/component",
+ "registerComponent", 0, new Class[] { Class.class });
+ digester.addObjectCreate("gdata/service", ProvidedServiceConfig.class);
+ digester.addSetProperties("gdata/service");
+ digester.addSetNext("gdata/service", "registerService");
+ digester.addBeanPropertySetter("gdata/service/feed-class", "feedType");
+ digester.addBeanPropertySetter("gdata/service/entry-class", "entryType");
+ digester.addBeanPropertySetter("gdata/service/extension-profile",
+ "extensionProfileClass");
+ digester.parse(RegistryBuilder.class
+ .getResourceAsStream("/gdata-config.xml"));
+ }
+
+
+
+}
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryContextListener.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryContextListener.java
index 8079be85a26..ffbed0b22e8 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryContextListener.java
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/RegistryContextListener.java
@@ -1,65 +1,80 @@
-/**
- * Copyright 2004 The Apache Software Foundation
+/**
+ * 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.
+ *
+ *
+ * When the
+ * {@link javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)}
+ * method is called the registry will be destroyed using
+ * {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry#destroy()}
+ * method.
*
- * 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
+ * @author Simon Willnauer
*
- * 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();
-
- }
-
-}
+ */
+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");
+
+ try {
+ RegistryBuilder.buildRegistry();
+ this.serverRegistry = GDataServerRegistry.getRegistry();
+ } catch (Exception e) {
+ this.serverRegistry.destroy();
+ LOG.error("can not register requiered components", e);
+ throw new RuntimeException("Can not register required components",
+ e);
+ }
+
+
+ }
+
+ /**
+ * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
+ */
+ public void contextDestroyed(ServletContextEvent arg0) {
+ LOG.info("Destroying context");
+ this.serverRegistry.destroy();
+
+ }
+
+}
diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/package.html b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/package.html
index 18ee7587528..dc9b7a6430f 100644
--- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/package.html
+++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/server/registry/package.html
@@ -5,6 +5,6 @@
-Internal registry - registering feeds and configurations
+Internal registry - registering services and server components