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

    - *
  1. update, delete or insert requests will respond with a statuscode and if - * successful the feed entry modified or created
  2. - *
  3. get requests will respond with a statuscode and if successful the - * requested feed
  4. - *
- * - * 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. + *

    + *
  1. update, delete or insert requests will respond with a statuscode and if + * successful the feed entry modified or created
  2. + *
  3. get requests will respond with a statuscode and if successful the + * requested feed
  4. + *
+ * + * 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: - *
    - *
  1. the feed id - where the feed can be accessed via http methodes
  2. - *
  3. the feed type - feed types are implementations of the abstract - * {@link com.google.gdata.data.BaseFeed}
  4. - *
- * 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 \ No newline at end of file diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/AbstractGdataServlet.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/AbstractGdataServlet.java index e942ffc7949..dfda9df868d 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/AbstractGdataServlet.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/AbstractGdataServlet.java @@ -18,10 +18,15 @@ package org.apache.lucene.gdata.servlet; import java.io.IOException; +import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + +import org.apache.lucene.gdata.server.registry.ComponentType; +import org.apache.lucene.gdata.server.registry.GDataServerRegistry; +import org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory; /** * @@ -42,7 +47,9 @@ public abstract class AbstractGdataServlet extends HttpServlet { private static final String METHOD_POST = "POST"; - private static final String METHOD_PUT = "PUT"; + private static final String METHOD_PUT = "PUT"; + + protected static RequestHandlerFactory HANDLER_FACTORY = null; /** * This overwrites the protected service method to dispatch @@ -92,6 +99,17 @@ public abstract class AbstractGdataServlet extends HttpServlet { super.service(arg0, arg1); } + } + + /** + * + * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig) + */ + public void init(ServletConfig arg0) throws ServletException { + HANDLER_FACTORY = GDataServerRegistry.getRegistry().lookup(RequestHandlerFactory.class,ComponentType.REQUESTHANDLERFACTORY); + if(HANDLER_FACTORY == null) + throw new ServletException("service not available"); + } } diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/RequestControllerServlet.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/RequestControllerServlet.java index 3842e4121ca..50d42dffda0 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/RequestControllerServlet.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/RequestControllerServlet.java @@ -1,122 +1,102 @@ -/** - * 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.servlet; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.lucene.gdata.servlet.handler.GDataRequestHandler; + +/** + * Provides a clean basic interface for GDATA Client API and requests to the + * GDATA Server. This Servlet dispatches the incoming requests to defined GDATA + * request handlers. Each of the handler processes the incoming request and + * responds according to the requested action. * - * 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.servlet; - -import java.io.IOException; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.lucene.gdata.servlet.handler.DefaultRequestHandlerFactory; -import org.apache.lucene.gdata.servlet.handler.GDataRequestHandler; -import org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory; - -/** - * Provides a clean basic interface for GDATA Client API and requests to the - * GDATA Server. This Servlet dispatches the incoming requests to defined GDATA - * request handlers. Each of the handler processes the incoming request and - * responds according to the requested action. - * - * @author Simon Willnauer - * - */ -public class RequestControllerServlet extends AbstractGdataServlet { - private static RequestHandlerFactory HANDLER_FACTORY = null; - private static final Log LOGGER = LogFactory.getLog(RequestControllerServlet.class); - - /** - * Version ID since this class implements - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 7540810742476175576L; - - /** - * @see javax.servlet.http.HttpServlet#doDelete(javax.servlet.http.HttpServletRequest, - * javax.servlet.http.HttpServletResponse) - */ - @Override - protected void doDelete(HttpServletRequest arg0, HttpServletResponse arg1) - throws ServletException, IOException { - GDataRequestHandler hanlder = HANDLER_FACTORY.getDeleteHandler(); - if(LOGGER.isInfoEnabled()) - LOGGER.info("Process DELETE request"); - - hanlder.processRequest(arg0, arg1); - } - - /** - * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, - * javax.servlet.http.HttpServletResponse) - */ - @Override - protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1) - throws ServletException, IOException { - GDataRequestHandler hanlder = HANDLER_FACTORY.getQueryHandler(); - if(LOGGER.isInfoEnabled()) - LOGGER.info("Process GET request"); - - hanlder.processRequest(arg0, arg1); - } - - /** - * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, - * javax.servlet.http.HttpServletResponse) - */ - @Override - protected void doPost(HttpServletRequest arg0, HttpServletResponse arg1) - throws ServletException, IOException { - GDataRequestHandler hanlder = HANDLER_FACTORY.getInsertHandler(); - if(LOGGER.isInfoEnabled()) - LOGGER.info("Process POST request"); - hanlder.processRequest(arg0, arg1); - } - - /** - * @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest, - * javax.servlet.http.HttpServletResponse) - */ - @Override - protected void doPut(HttpServletRequest arg0, HttpServletResponse arg1) - throws ServletException, IOException { - GDataRequestHandler hanlder = HANDLER_FACTORY.getUpdateHandler(); - if(LOGGER.isInfoEnabled()) - LOGGER.info("Process PUT request"); - hanlder.processRequest(arg0, arg1); - } - - /** - * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig) - */ - @Override - public void init(ServletConfig arg0) { - /* - * The Factory implementation could be configured as an initial - * parameter or by an external config file. - * - */ - HANDLER_FACTORY = RequestHandlerFactory - .getInstance(DefaultRequestHandlerFactory.class); - - } - - -} + */ +public class RequestControllerServlet extends AbstractGdataServlet { + private static final Log LOGGER = LogFactory.getLog(RequestControllerServlet.class); + + /** + * Version ID since this class implements + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 7540810742476175576L; + + /** + * @see javax.servlet.http.HttpServlet#doDelete(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + @Override + protected void doDelete(HttpServletRequest arg0, HttpServletResponse arg1) + throws ServletException, IOException { + GDataRequestHandler hanlder = HANDLER_FACTORY.getEntryDeleteHandler(); + if(LOGGER.isInfoEnabled()) + LOGGER.info("Process DELETE request"); + + hanlder.processRequest(arg0, arg1); + } + + /** + * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + @Override + protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1) + throws ServletException, IOException { + GDataRequestHandler hanlder = HANDLER_FACTORY.getFeedQueryHandler(); + if(LOGGER.isInfoEnabled()) + LOGGER.info("Process GET request"); + hanlder.processRequest(arg0, arg1); + } + + /** + * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + @Override + protected void doPost(HttpServletRequest arg0, HttpServletResponse arg1) + throws ServletException, IOException { + GDataRequestHandler hanlder = HANDLER_FACTORY.getEntryInsertHandler(); + if(LOGGER.isInfoEnabled()) + LOGGER.info("Process POST request"); + hanlder.processRequest(arg0, arg1); + } + + /** + * @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + @Override + protected void doPut(HttpServletRequest arg0, HttpServletResponse arg1) + throws ServletException, IOException { + GDataRequestHandler hanlder = HANDLER_FACTORY.getEntryUpdateHandler(); + if(LOGGER.isInfoEnabled()) + LOGGER.info("Process PUT request"); + hanlder.processRequest(arg0, arg1); + } + + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractGdataRequestHandler.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractGdataRequestHandler.java index 20b1f04ebe8..2742f4b1324 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractGdataRequestHandler.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/AbstractGdataRequestHandler.java @@ -1,96 +1,104 @@ -/** - * 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.servlet.handler; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.lucene.gdata.server.GDataRequest; +import org.apache.lucene.gdata.server.GDataRequestException; +import org.apache.lucene.gdata.server.GDataResponse; +import org.apache.lucene.gdata.server.Service; +import org.apache.lucene.gdata.server.ServiceFactory; +import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; +import org.apache.lucene.gdata.server.registry.ComponentType; +import org.apache.lucene.gdata.server.registry.GDataServerRegistry; + +/** + * @author Simon Willnauer * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.lucene.gdata.servlet.handler; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.lucene.gdata.server.GDataRequest; -import org.apache.lucene.gdata.server.GDataRequestException; -import org.apache.lucene.gdata.server.GDataResponse; -import org.apache.lucene.gdata.server.Service; -import org.apache.lucene.gdata.server.ServiceFactory; -import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; - -/** - * @author Simon Willnauer - * - */ -public abstract class AbstractGdataRequestHandler implements - GDataRequestHandler { - private final static Log LOG = LogFactory - .getLog(AbstractGdataRequestHandler.class); - - - protected GDataRequest feedRequest; - protected GDataResponse feedResponse; - - /** - * @see org.apache.lucene.gdata.servlet.handler.GDataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, - * javax.servlet.http.HttpServletResponse) - */ - public abstract void processRequest(HttpServletRequest request, - HttpServletResponse response) throws ServletException, IOException; - - protected void initializeRequestHandler(final HttpServletRequest request, final HttpServletResponse response, final GDataRequestType type) - throws GDataRequestException { - this.feedRequest = new GDataRequest(request, type); - this.feedResponse = new GDataResponse(response); - try { - this.feedRequest.initializeRequest(); - } catch (GDataRequestException e) { - this.feedResponse.setError(HttpServletResponse.SC_NOT_FOUND); - LOG.warn("Couldn't initialize FeedRequest - " + e.getMessage(), e); - throw e; - } - } - - - - protected void sendError() throws IOException { - this.feedResponse.sendError(); - - } - - protected void setFeedResponseFormat() { - this.feedResponse.setOutputFormat(this.feedRequest.getRequestedResponseFormat()); - } - - protected void setFeedResponseStatus(int status) { - this.feedResponse.setResponseCode(status); - } - - protected void setError(int error) { - this.feedResponse.setError(error); - } - - protected Service getService() throws ServletException { - ServiceFactory serviceFactory = ServiceFactory.getInstance(); - Service service = serviceFactory.getService(); - if(service == null) - throw new ServletException("Service not available"); - return service; - } - - - -} + */ +public abstract class AbstractGdataRequestHandler extends RequestAuthenticator implements + GDataRequestHandler { + private final static Log LOG = LogFactory + .getLog(AbstractGdataRequestHandler.class); + + protected Service service; + protected GDataRequest feedRequest; + protected GDataResponse feedResponse; + + /** + * @see org.apache.lucene.gdata.servlet.handler.GDataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + public abstract void processRequest(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException; + + protected void initializeRequestHandler(final HttpServletRequest request, final HttpServletResponse response, final GDataRequestType type) + throws GDataRequestException, ServletException { + this.feedRequest = new GDataRequest(request, type); + this.feedResponse = new GDataResponse(response); + getService(); + try { + this.feedRequest.initializeRequest(); + } catch (GDataRequestException e) { + this.feedResponse.setError(HttpServletResponse.SC_NOT_FOUND); + LOG.warn("Couldn't initialize FeedRequest - " + e.getMessage(), e); + throw e; + } + } + + + + protected void sendError() throws IOException { + this.feedResponse.sendError(); + + } + + protected void setFeedResponseFormat() { + this.feedResponse.setOutputFormat(this.feedRequest.getRequestedResponseFormat()); + } + + protected void setFeedResponseStatus(int status) { + this.feedResponse.setResponseCode(status); + } + + protected void setError(int error) { + this.feedResponse.setError(error); + } + + private void getService() throws ServletException { + GDataServerRegistry registry = GDataServerRegistry.getRegistry(); + ServiceFactory serviceFactory = registry.lookup(ServiceFactory.class,ComponentType.SERVICEFACTORY); + this.service = serviceFactory.getService(); + if(this.service == null) + throw new ServletException("Service not available"); + + } + + protected void closeService(){ + this.service.close(); + } + + + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultDeleteHandler.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultDeleteHandler.java index a4fef31c8c9..37fb4f5fe6d 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultDeleteHandler.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultDeleteHandler.java @@ -1,84 +1,83 @@ -/** - * Copyright 2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.lucene.gdata.servlet.handler; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.lucene.gdata.server.FeedNotFoundException; -import org.apache.lucene.gdata.server.GDataRequestException; -import org.apache.lucene.gdata.server.Service; -import org.apache.lucene.gdata.server.ServiceException; -import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; - -/** - * Default Handler implementation. This handler processes the incoming - * {@link org.apache.lucene.gdata.server.GDataRequest} and deletes the requested - * feed entry from the storage and the search component. - *

- * The handler sends following response to the client: - *

- *
    - *
  1. if the entry could be deleted - HTTP status code 200 OK
  2. - *
  3. if an error occures - HTTP status code 500 INTERNAL SERVER ERROR
  4. - *
  5. if the resource could not found - HTTP status code 404 NOT FOUND
  6. - *
+/** + * Copyright 2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.lucene.gdata.servlet.handler; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.lucene.gdata.data.GDataAccount.AccountRole; +import org.apache.lucene.gdata.server.GDataRequestException; +import org.apache.lucene.gdata.server.ServiceException; +import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; + +/** + * Default Handler implementation. This handler processes the incoming + * {@link org.apache.lucene.gdata.server.GDataRequest} and deletes the requested + * feed entry from the storage and the search component. + *

+ * The handler sends following response to the client: + *

+ *
    + *
  1. if the entry could be deleted - HTTP status code 200 OK
  2. + *
  3. if an error occures - HTTP status code 500 INTERNAL SERVER ERROR
  4. + *
  5. if the resource could not found - HTTP status code 404 NOT FOUND
  6. + *
* - * @author Simon Willnauer - * - */ -public class DefaultDeleteHandler extends AbstractGdataRequestHandler { - private static final Log LOG = LogFactory - .getLog(DefaultDeleteHandler.class); - - /** - * @throws ServletException - * @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, - * javax.servlet.http.HttpServletResponse) - */ - @Override - public void processRequest(HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { - try { - initializeRequestHandler(request, response,GDataRequestType.DELETE); - } catch (GDataRequestException e) { - sendError(); - return; - } - - Service service = getService(); - try { - service.deleteEntry(this.feedRequest, this.feedResponse); - } catch (FeedNotFoundException e) { - LOG.error("Could not process DeleteFeed request Feed Not Found- " - + e.getMessage(), e); - setError(HttpServletResponse.SC_NOT_FOUND); - sendError(); - } catch (ServiceException e) { - LOG.error("Could not process DeleteFeed request - " - + e.getMessage(), e); - setError(HttpServletResponse.SC_BAD_REQUEST); - sendError(); - } - - } - -} + * @author Simon Willnauer + * + */ +public class DefaultDeleteHandler extends AbstractGdataRequestHandler { + private static final Log LOG = LogFactory + .getLog(DefaultDeleteHandler.class); + + /** + * @throws ServletException + * @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + @Override + public void processRequest(HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + try { + initializeRequestHandler(request, response,GDataRequestType.DELETE); + } catch (GDataRequestException e) { + sendError(); + return; + } + if(!authenticateAccount(request,AccountRole.ENTRYAMINISTRATOR)){ + setError(HttpServletResponse.SC_UNAUTHORIZED); + sendError(); + return; + } + + try { + this.service.deleteEntry(this.feedRequest, this.feedResponse); + + } catch (ServiceException e) { + LOG.error("Could not process DeleteFeed request - " + + e.getMessage(), e); + sendError(); + } + closeService(); + + } + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultGetHandler.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultGetHandler.java index a600d45652b..f549ab8806b 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultGetHandler.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultGetHandler.java @@ -1,104 +1,138 @@ -/** - * 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.servlet.handler; + +import java.io.IOException; +import java.util.Date; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.lucene.gdata.server.GDataRequestException; +import org.apache.lucene.gdata.server.Service; +import org.apache.lucene.gdata.server.ServiceException; +import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; +import org.apache.lucene.gdata.utils.DateFormater; + +import com.google.gdata.data.BaseEntry; +import com.google.gdata.data.BaseFeed; + +/** + * Default Handler implementation. This handler processes the incoming + * {@link org.apache.lucene.gdata.server.GDataRequest} and retrieves the + * requested feed from the underlaying storage. + *

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

+ *

+ * The DefaultGetHandler supports HTTP Conditional GET. It set the Last-Modified + * response header based upon the value of the element in the + * returned feed or entry. A client can send this value back as the value of the + * 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.

* - * 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.servlet.handler; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.lucene.gdata.server.GDataRequestException; -import org.apache.lucene.gdata.server.Service; -import org.apache.lucene.gdata.server.ServiceException; -import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; - -import com.google.gdata.data.BaseEntry; -import com.google.gdata.data.BaseFeed; - -/** - * Default Handler implementation. This handler processes the incoming - * {@link org.apache.lucene.gdata.server.GDataRequest} and retrieves the - * requested feed from the underlaying storage. - *

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

- * - * - * @author Simon Willnauer - * - */ -public class DefaultGetHandler extends AbstractGdataRequestHandler { - private static final Log LOG = LogFactory.getLog(DefaultGetHandler.class); - - /** - * @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, - * javax.servlet.http.HttpServletResponse) - */ - @Override - public void processRequest(HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { - try { - initializeRequestHandler(request, response, GDataRequestType.GET); - } catch (GDataRequestException e) { - sendError(); - return; - } - Service service = getService(); - try { - if (LOG.isInfoEnabled()) - LOG.info("Requested output formate: " - + this.feedRequest.getRequestedResponseFormat()); - this.feedResponse.setOutputFormat(this.feedRequest - .getRequestedResponseFormat()); - if(this.feedRequest.isFeedRequested()){ - BaseFeed feed = service - .getFeed(this.feedRequest, this.feedResponse); - - this.feedResponse.sendResponse(feed, this.feedRequest.getExtensionProfile()); - }else{ - BaseEntry entry = service.getSingleEntry(this.feedRequest,this.feedResponse); - if(entry == null){ - this.feedResponse.setError(HttpServletResponse.SC_NOT_FOUND); - sendError(); - } - this.feedResponse.sendResponse(entry, this.feedRequest.getExtensionProfile()); - } - - - } catch (ServiceException e) { // TODO handle exceptions to send exact - // response - LOG.error("Could not process GetFeed request - " + e.getMessage(), - e); - this.feedResponse.setError(HttpServletResponse.SC_BAD_REQUEST); // TODO - // change - // this - sendError(); - } - - - - } - - - -} + */ +public class DefaultGetHandler extends AbstractGdataRequestHandler { + private static final Log LOG = LogFactory.getLog(DefaultGetHandler.class); + + /** + * @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + @Override + public void processRequest(HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + try { + initializeRequestHandler(request, response, GDataRequestType.GET); + } catch (GDataRequestException e) { + sendError(); + return; + } + + try { + String modifiedSince = this.feedRequest.getModifiedSince(); + if (!checkIsModified(modifiedSince)) { + this.feedResponse + .setStatus(HttpServletResponse.SC_NOT_MODIFIED); + return; + } + if (LOG.isInfoEnabled()) + LOG.info("Requested output formate: " + + this.feedRequest.getRequestedResponseFormat()); + this.feedResponse.setOutputFormat(this.feedRequest + .getRequestedResponseFormat()); + if (this.feedRequest.isFeedRequested()) { + BaseFeed feed = this.service.getFeed(this.feedRequest, + this.feedResponse); + + this.feedResponse.sendResponse(feed, this.feedRequest + .getConfigurator().getExtensionProfile()); + } else { + BaseEntry entry = this.service.getSingleEntry(this.feedRequest, + this.feedResponse); + this.feedResponse.sendResponse(entry, this.feedRequest + .getConfigurator().getExtensionProfile()); + } + + } catch (ServiceException e) { + LOG.error("Could not process GetFeed request - " + e.getMessage(), + e); + sendError(); + } + closeService(); + + } + + /** + * + * returns true if the resource has been modified since the specified + * reqeust header value + */ + private boolean checkIsModified(String lastModified) + throws ServiceException { + if (lastModified == null) + return true; + try { + Date clientDate = DateFormater.parseDate(lastModified,DateFormater.HTTP_HEADER_DATE_FORMAT,DateFormater.HTTP_HEADER_DATE_FORMAT_TIME_OFFSET); + Date entityDate; + if (this.feedRequest.isFeedRequested()) + entityDate = this.service.getFeedLastModified(this.feedRequest + .getFeedId()); + else + entityDate = this.service.getEntryLastModified(this.feedRequest + .getEntryId(),this.feedRequest.getFeedId()); + if(LOG.isInfoEnabled()) + LOG.info("comparing date clientDate: "+clientDate+"; lastmodified: "+entityDate); + return (entityDate.getTime()-clientDate.getTime() > 1000); + } catch (java.text.ParseException e) { + LOG.info("Couldn't parse Last-Modified header -- "+lastModified,e); + + } + return true; + } + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultInsertHandler.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultInsertHandler.java index 671c19e3fc5..4bc37d266db 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultInsertHandler.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultInsertHandler.java @@ -1,83 +1,86 @@ -/** - * 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.servlet.handler; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.lucene.gdata.data.GDataAccount.AccountRole; +import org.apache.lucene.gdata.server.GDataRequestException; +import org.apache.lucene.gdata.server.ServiceException; +import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; + +import com.google.gdata.data.BaseEntry; + +/** + * Default Handler implementation. This handler processes the incoming + * {@link org.apache.lucene.gdata.server.GDataRequest} and inserts the requested + * feed entry into the storage and the search component. + *

+ * The handler sends following response to the client: + *

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

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

* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.lucene.gdata.servlet.handler; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.lucene.gdata.server.GDataRequestException; -import org.apache.lucene.gdata.server.Service; -import org.apache.lucene.gdata.server.ServiceException; -import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; - -import com.google.gdata.data.BaseEntry; - -/** - * Default Handler implementation. This handler processes the incoming - * {@link org.apache.lucene.gdata.server.GDataRequest} and inserts the requested - * feed entry into the storage and the search component. - *

- * The handler sends following response to the client: - *

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

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

- * - * @author Simon Willnauer - * - */ -public class DefaultInsertHandler extends AbstractGdataRequestHandler { - private static final Log LOG = LogFactory.getLog(DefaultInsertHandler.class); - /** - * @throws ServletException - * @see org.apache.lucene.gdata.servlet.handler.GDataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) - */ - @Override - public void processRequest(HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { - try { - initializeRequestHandler(request,response,GDataRequestType.INSERT); - } catch (GDataRequestException e) { - sendError(); - return; - } - - Service service = getService(); - try{ - BaseEntry entry = service.createEntry(this.feedRequest,this.feedResponse); - setFeedResponseFormat(); - setFeedResponseStatus(HttpServletResponse.SC_CREATED); - this.feedResponse.sendResponse(entry, this.feedRequest.getExtensionProfile()); - - }catch (ServiceException e) { - LOG.error("Could not process GetFeed request - "+e.getMessage(),e); - setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - this.feedResponse.sendError(); - } - - - } - -} + * @author Simon Willnauer + * + */ +public class DefaultInsertHandler extends AbstractGdataRequestHandler { + private static final Log LOG = LogFactory.getLog(DefaultInsertHandler.class); + /** + * @throws ServletException + * @see org.apache.lucene.gdata.servlet.handler.GDataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + public void processRequest(HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + try { + initializeRequestHandler(request,response,GDataRequestType.INSERT); + } catch (GDataRequestException e) { + sendError(); + return; + } + if(!authenticateAccount(this.feedRequest,AccountRole.ENTRYAMINISTRATOR)){ + setError(HttpServletResponse.SC_UNAUTHORIZED); + sendError(); + return; + } + + try{ + BaseEntry entry = this.service.createEntry(this.feedRequest,this.feedResponse); + setFeedResponseFormat(); + setFeedResponseStatus(HttpServletResponse.SC_CREATED); + this.feedResponse.sendResponse(entry, this.feedRequest.getConfigurator().getExtensionProfile()); + + }catch (ServiceException e) { + LOG.error("Could not process GetFeed request - "+e.getMessage(),e); + this.feedResponse.sendError(); + } + closeService(); + + } + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultRequestHandlerFactory.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultRequestHandlerFactory.java index f8e9f606759..1b91deb5070 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultRequestHandlerFactory.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultRequestHandlerFactory.java @@ -1,69 +1,149 @@ -/** - * 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.servlet.handler; + +import org.apache.lucene.gdata.server.registry.Component; +import org.apache.lucene.gdata.server.registry.ComponentType; + +/** + * Default implementation for RequestHandlerFactory Builds the + * {@link org.apache.lucene.gdata.servlet.handler.GDataRequestHandler} + * instances. + * 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.servlet.handler; - -/** - * Default implementation for RequestHandlerFactory Builds the - * {@link org.apache.lucene.gdata.servlet.handler.GDataRequestHandler} - * instances. - * - * @author Simon Willnauer - * - */ -public class DefaultRequestHandlerFactory extends RequestHandlerFactory { - - DefaultRequestHandlerFactory() { - // - } - - /** - * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getUpdateHandler() - */ - @Override - public GDataRequestHandler getUpdateHandler() { - - return new DefaultUpdateHandler(); - } - - /** - * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getDeleteHandler() - */ - @Override - public GDataRequestHandler getDeleteHandler() { - - return new DefaultDeleteHandler(); - } - - /** - * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getQueryHandler() - */ - @Override - public GDataRequestHandler getQueryHandler() { - - return new DefaultGetHandler(); - } - - /** - * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getInsertHandler() - */ - @Override - public GDataRequestHandler getInsertHandler() { - - return new DefaultInsertHandler(); - } - -} + */ +@Component(componentType=ComponentType.REQUESTHANDLERFACTORY) +public class DefaultRequestHandlerFactory extends RequestHandlerFactory { + + + /** + * 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 DefaultRequestHandlerFactory() { + // + } + + /** + * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getEntryUpdateHandler() + */ + @Override + public GDataRequestHandler getEntryUpdateHandler() { + + return new DefaultUpdateHandler(); + } + + /** + * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getEntryDeleteHandler() + */ + @Override + public GDataRequestHandler getEntryDeleteHandler() { + + return new DefaultDeleteHandler(); + } + + /** + * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getFeedQueryHandler() + */ + @Override + public GDataRequestHandler getFeedQueryHandler() { + + return new DefaultGetHandler(); + } + + /** + * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getEntryInsertHandler() + */ + @Override + public GDataRequestHandler getEntryInsertHandler() { + + return new DefaultInsertHandler(); + } + + /** + * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getInsertAccountHandler() + */ + @Override + public GDataRequestHandler getInsertAccountHandler() { + + return new InsertAccountStrategy(); + } + + /** + * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getDeleteAccountHandler() + */ + @Override + public GDataRequestHandler getDeleteAccountHandler() { + + return new DeleteAccountStrategy(); + } + + /** + * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getUpdateAccountHandler() + */ + @Override + public GDataRequestHandler getUpdateAccountHandler() { + + return new UpdataAccountStrategy(); + } + + /** + * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getInsertFeedHandler() + */ + @Override + public GDataRequestHandler getInsertFeedHandler() { + + return new InsertFeedHandler(); + } + + /** + * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getUpdateFeedHandler() + */ + @Override + public GDataRequestHandler getUpdateFeedHandler() { + + return new UpdateFeedHandler(); + } + + /** + * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getDeleteFeedHandler() + */ + @Override + public GDataRequestHandler getDeleteFeedHandler() { + + return new DeleteFeedHandler(); + } + + /** + * @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/servlet/handler/DefaultUpdateHandler.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultUpdateHandler.java index 91454797657..850dced1b38 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultUpdateHandler.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/DefaultUpdateHandler.java @@ -1,94 +1,89 @@ -/** - * 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.servlet.handler; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.lucene.gdata.data.GDataAccount.AccountRole; +import org.apache.lucene.gdata.server.GDataRequestException; +import org.apache.lucene.gdata.server.ServiceException; +import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; + +import com.google.gdata.data.BaseEntry; + +/** + * Default Handler implementation. This handler processes the incoming + * {@link org.apache.lucene.gdata.server.GDataRequest} and updates the requested + * feed entry in the storage and the search component. + *

+ * The handler sends following response to the client: + *

+ *
    + *
  1. if the entry was successfully updated - HTTP status code 200 OK
  2. + *
  3. if an error occures - HTTP status code 500 INTERNAL SERVER ERROR
  4. + *
  5. if the resource could not found - HTTP status code 404 NOT FOUND
  6. + *
* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.lucene.gdata.servlet.handler; - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.lucene.gdata.server.FeedNotFoundException; -import org.apache.lucene.gdata.server.GDataRequestException; -import org.apache.lucene.gdata.server.Service; -import org.apache.lucene.gdata.server.ServiceException; -import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; - -import com.google.gdata.data.BaseEntry; - -/** - * Default Handler implementation. This handler processes the incoming - * {@link org.apache.lucene.gdata.server.GDataRequest} and updates the requested - * feed entry in the storage and the search component. - *

- * The handler sends following response to the client: - *

- *
    - *
  1. if the entry was successfully updated - HTTP status code 200 OK
  2. - *
  3. if an error occures - HTTP status code 500 INTERNAL SERVER ERROR
  4. - *
  5. if the resource could not found - HTTP status code 404 NOT FOUND
  6. - *
+ * @author Simon Willnauer * - * @author Simon Willnauer - * - */ -public class DefaultUpdateHandler extends AbstractGdataRequestHandler { - private static final Log LOG = LogFactory - .getLog(DefaultUpdateHandler.class); - - /** - * @throws ServletException - * @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, - * javax.servlet.http.HttpServletResponse) - */ - @Override - public void processRequest(HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { - try { - initializeRequestHandler(request, response,GDataRequestType.UPDATE); - } catch (GDataRequestException e) { - sendError(); - return; - } - - Service service = getService(); - try { - BaseEntry entry = service.updateEntry(this.feedRequest, - this.feedResponse); - setFeedResponseFormat(); - setFeedResponseStatus(HttpServletResponse.SC_OK); - this.feedResponse.sendResponse(entry, this.feedRequest.getExtensionProfile()); - }catch (FeedNotFoundException e) { - LOG.error("Could not process UpdateFeed request - " - + e.getMessage(), e); - setError(HttpServletResponse.SC_NOT_FOUND); - - sendError(); - } - catch (ServiceException e) { - - LOG.error("Could not process UpdateFeed request - " - + e.getMessage(), e); - setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - - sendError(); - } - - } - -} + */ +public class DefaultUpdateHandler extends AbstractGdataRequestHandler { + private static final Log LOG = LogFactory + .getLog(DefaultUpdateHandler.class); + + /** + * @throws ServletException + * @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + @Override + public void processRequest(HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + try { + initializeRequestHandler(request, response,GDataRequestType.UPDATE); + } catch (GDataRequestException e) { + setError(HttpServletResponse.SC_UNAUTHORIZED); + sendError(); + return; + } + if(!authenticateAccount(request,AccountRole.ENTRYAMINISTRATOR)){ + sendError(); + return; + } + + try { + BaseEntry entry = this.service.updateEntry(this.feedRequest, + this.feedResponse); + setFeedResponseFormat(); + setFeedResponseStatus(HttpServletResponse.SC_OK); + this.feedResponse.sendResponse(entry, this.feedRequest.getConfigurator().getExtensionProfile()); + + } + catch (ServiceException e) { + LOG.error("Could not process UpdateFeed request - " + + e.getMessage(), e); + sendError(); + } + closeService(); + } + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/RequestHandlerFactory.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/RequestHandlerFactory.java index 20ac7e0113b..d7115339395 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/RequestHandlerFactory.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/servlet/handler/RequestHandlerFactory.java @@ -1,122 +1,98 @@ -/** - * 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.servlet.handler; + +import org.apache.lucene.gdata.server.registry.ServerComponent; + +/** + * Abstract Superclass for RequestHandlerFactories + * @author Simon Willnauer * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.lucene.gdata.servlet.handler; - -/** - * @author Simon Willnauer - * - */ -public abstract class RequestHandlerFactory { - - private static RequestHandlerFactory INSTANCE = null; - - /** - * This method creates a singleton instance of the given type. The fist call - * will create an instance of the given class which will be returned in - * every subsequent call. Any subsequent call to this method will ignore the - * given class object. - * - * @param factoryImplementation - - * the factory implementation (must be a subtype of this Class) - * - * @return - a singleton instance of the given type - * - */ - public static synchronized RequestHandlerFactory getInstance( - Class factoryImplementation) { - if (INSTANCE == null) { - - INSTANCE = createInstance(factoryImplementation); - } - return INSTANCE; - } - - /** - * Singleton - Pattern using private constructor - * - */ - RequestHandlerFactory() { - super(); - - } - - private static RequestHandlerFactory createInstance( - final Class qualifiedClass) { - if (qualifiedClass == null) - throw new IllegalArgumentException( - "Factory class is null -- must be a implementation of org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory"); - try { - return (RequestHandlerFactory) qualifiedClass.newInstance(); - } catch (Exception e) { - FactoryImplementationException ex = new FactoryImplementationException( - "Factory implementation could not be created", e.getCause()); - ex.setStackTrace(e.getStackTrace()); - throw ex; - } - } - - /** - * Creates a UpdateHandler which processes a GDATA UPDATE request. - * @return - an RequestHandlerInstance - */ - public abstract GDataRequestHandler getUpdateHandler(); - - /** - * Creates a DeleteHandler which processes a GDATA DELETE request. - * @return - an RequestHandlerInstance - */ - public abstract GDataRequestHandler getDeleteHandler(); - - /** - * Creates a QueryHandler which processes a GDATA Query / Get request. - * @return - an RequestHandlerInstance - */ - public abstract GDataRequestHandler getQueryHandler(); - - /** - * Creates a InsertHandler which processes a GDATA Insert request. - * @return - an RequestHandlerInstance - */ - public abstract GDataRequestHandler getInsertHandler(); - - - - private static class FactoryImplementationException extends - RuntimeException { - - /** - * - */ - private static final long serialVersionUID = 3166033278825112569L; - - /** - * Constructs a new FactoryImplementationException with the specified - * cause and message - * - * @param arg0 - - * the detail message - * @param arg1 - - * the throw cause - */ - public FactoryImplementationException(String arg0, Throwable arg1) { - super(arg0, arg1); - - } - - } - -} + */ +public abstract class RequestHandlerFactory implements ServerComponent { + + + + + /** + * 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 RequestHandlerFactory() { + super(); + + } + + + /** + * Creates a EntryUpdateHandler which processes a GDATA UPDATE request. + * @return - a RequestHandlerInstance + */ + public abstract GDataRequestHandler getEntryUpdateHandler(); + + /** + * Creates a EntryDeleteHandler which processes a GDATA DELETE request. + * @return - a RequestHandlerInstance + */ + public abstract GDataRequestHandler getEntryDeleteHandler(); + + /** + * Creates a FeedQueryHandler which processes a GDATA Query / Get request. + * @return - a RequestHandlerInstance + */ + public abstract GDataRequestHandler getFeedQueryHandler(); + + /** + * Creates a EntryInsertHandler which processes a GDATA Insert request. + * @return - a RequestHandlerInstance + */ + public abstract GDataRequestHandler getEntryInsertHandler(); + /** + * Creates a InsertAccountHandler which processes a Account Insert request. + * @return - a RequestHandlerInstance + */ + public abstract GDataRequestHandler getInsertAccountHandler(); + /** + * Creates a DeleteAccountHandler which processes a Account Delete request. + * @return - a RequestHandlerInstance + */ + public abstract GDataRequestHandler getDeleteAccountHandler(); + /** + * Creates a UpdateAccountHandler which processes a Account Update request. + * @return - a RequestHandlerInstance + */ + public abstract GDataRequestHandler getUpdateAccountHandler(); + /** + * Creates a InsertFeedHandler which processes a Feed Insert request. + * @return - a RequestHandlerInstance + */ + public abstract GDataRequestHandler getInsertFeedHandler(); + /** + * Creates a UpdateFeedHandler which processes a Feed Insert request. + * @return - a RequestHandlerInstance + */ + public abstract GDataRequestHandler getUpdateFeedHandler(); + /** + * Creates a DeleteFeedHandler which processes a Feed Insert request. + * @return - a RequestHandlerInstance + */ + public abstract GDataRequestHandler getDeleteFeedHandler(); + + + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/IDGenerator.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/IDGenerator.java index 9b5396a74e2..760c5cda43a 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/IDGenerator.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/IDGenerator.java @@ -51,7 +51,9 @@ public class IDGenerator { private static final int DEFAULT_CAPACITY = 10; - protected static final Log LOGGER = LogFactory.getLog(IDGenerator.class); + protected static final Log LOGGER = LogFactory.getLog(IDGenerator.class); + + private static final String RUNNER_THREAD_NAME = "GDATA-ID Generator"; /** * Constructs a new ID generator. with a fixed capacity of prebuild ids. The @@ -91,7 +93,9 @@ public class IDGenerator { if (this.runner == null) { UIDProducer producer = new UIDProducer(this.blockingQueue, this.secureRandom, this.mdigest); - this.runner = new Thread(producer); + this.runner = new Thread(producer); + this.runner.setDaemon(true); + this.runner.setName(RUNNER_THREAD_NAME); this.runner.start(); } } diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/Storage.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/Storage.java index 5eec70c1ac7..a604c89e4c1 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/Storage.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/Storage.java @@ -12,89 +12,263 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ -package org.apache.lucene.gdata.storage; - -import java.util.List; - -import com.google.gdata.data.BaseEntry; -import com.google.gdata.data.BaseFeed; -import com.google.gdata.data.ExtensionProfile; - -/** - * This is the main storage interface. The Storage represents the internal - * server storage. It acts as a Database to persist the feed data. - * This inferface is not public yet!! - * - * @author Simon Willnauer - * - */ -public interface Storage { - - /** - * This stores an incoming entry for a later retrival. - * The Entry will be associated with the feedid. - * @param entry - the entry - * @param feedId - the feedID - * @return - the stored Entry - * @throws StorageException - */ - public abstract BaseEntry storeEntry(BaseEntry entry, String feedId) - throws StorageException; - - /** - * @param entryId - * @param feedId - * @throws StorageException - */ - public abstract void deleteEntry(String entryId, String feedId) - throws StorageException; - - /** - * @param entry - * @param feedId - * @return - * @throws StorageException - */ - public abstract BaseEntry updateEntry(BaseEntry entry, String feedId) - throws StorageException; - - /** - * @param feedId - * @param startIndex - * @param resultCount - * @return - * @throws StorageException - */ - public abstract BaseFeed getFeed(String feedId, int startIndex, - int resultCount) throws StorageException; - - /** - * @param entryId - * @param feedId - * @return - * @throws StorageException - */ - public abstract BaseEntry getEntry(String entryId, String feedId) - throws StorageException; - - /** - * @param entryIdList - * @param feedId - * @return - * @throws StorageException - */ - public abstract List getEntries(List entryIdList, - String feedId) throws StorageException; - - /** - * @param profile - */ - public abstract void setExtensionProfile(final ExtensionProfile profile); - - /** - * close this storage instance - */ - public abstract void close(); - -} + */ +package org.apache.lucene.gdata.storage; + +import org.apache.lucene.gdata.data.GDataAccount; +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.apache.lucene.gdata.data.ServerBaseFeed; + +import com.google.gdata.data.BaseEntry; +import com.google.gdata.data.BaseFeed; + +/** + * A interface every storage implementation must provide to access the + * Storage. It describes all access methodes needed to store, + * retrieve and look up data stored in the Storage component. This + * interface acts as a Facade to hide the storage implementation from + * the user. + *

+ * This could also act as a proxy for a remote storage. It also removes any + * restrictions from custom storage implementations. + *

+ * + * + * @author Simon Willnauer + * + */ +/* + * not final yet + */ +public interface Storage { + + /** + * + * Stores the given entry. The ServerBaseEntry must provide a feed id and + * the service type. configuration for the entry. + * + * @param entry - + * the entry to store + * + * @return - the stored Entry for the server response + * @throws StorageException - + * if the entry can not be stored or required field are not set. + */ + public abstract BaseEntry storeEntry(ServerBaseEntry entry) + throws StorageException; + + /** + * Deletes the given entry. The ServerBaseEntry just hase to provide the + * entry id to be deleted. + * + * @param entry - + * the entry to delete from the storage + * @throws StorageException - + * if the entry can not be deleted or the entry does not exist + * or required field are not set. + */ + public abstract void deleteEntry(ServerBaseEntry entry) + throws StorageException; + + /** + * Updates the given entry. The ServerBaseEntry must provide a feed id, + * service id and the + * {@link org.apache.lucene.gdata.server.registry.ProvidedService} + * + * @param entry - + * the entry to update + * + * @return - the updated entry for server response. + * @throws StorageException - + * if the entry can not be updated or does not exist or required + * field are not set. + */ + public abstract BaseEntry updateEntry(ServerBaseEntry entry) + throws StorageException; + + /** + * Retrieves the requested feed from the storage. The given ServerBaseFeed + * must provide information about the feed id, max-result count and the + * start index. To create feeds and entries also the service type must be + * provided. + * + * @param feed - + * the to retieve from the storage + * @return the requested feed + * @throws StorageException - + * the feed does not exist or can not be retrieved or required + * field are not set. + */ + public abstract BaseFeed getFeed(ServerBaseFeed feed) + throws StorageException; + + /** + * Retrieves the requested entry from the storage. The given entry must + * provide information about the entry id and service type. + * + * @param entry - + * the entry to retrieve + * @return - the requested entry + * @throws StorageException - + * if the entry does not exist or can not be created or required + * field are not set. + */ + public abstract BaseEntry getEntry(ServerBaseEntry entry) + throws StorageException; + + /** + * Saves a new account. Required attributes to set are password + * and accountname + * + * @param account - + * the account to save + * @throws StorageException - + * if the account can not be stored or the account already + * exists or required field are not set. + */ + public abstract void storeAccount(final GDataAccount account) + throws StorageException; + + /** + * Updates an existing account. Required attributes to set are + * password and accountname + * + * @param account - + * the account to update + * @throws StorageException - + * if the account does not exist or required field are not set. + */ + public abstract void updateAccount(final GDataAccount account) + throws StorageException; + + /** + * Deletes the account for the given account name. All feeds and entries + * referencing this account will be deleted as well! + * + * @param accountname - + * the name of the account to delete + * @throws StorageException - + * if the account does not exist + */ + public abstract void deleteAccount(final String accountname) + throws StorageException; + + /** + * Stores a new feed for a existing account. The Feed must provide + * information about the service type to store the feed for and the feed id + * used for accessing and retrieving the feed from the storage. Each feed is + * associated with a provided service. This method does check wheather a + * feed with the same feed id as the given feed does already exists. + * + * @see org.apache.lucene.gdata.server.registry.ProvidedService + * @param feed - + * the feed to create + * @param accountname - + * the account name belongs to the feed + * @throws StorageException - + * if the feed already exists or the feed can not be stored + */ + public abstract void storeFeed(final ServerBaseFeed feed, String accountname) + throws StorageException; + + /** + * Deletes the feed for the given feed id. All Entries referencing the given + * feed id will be deleted as well. + * + * @param feedId - + * the feed id for the feed to delete. + * @throws StorageException - + * if the feed for the feed id does not exist or the feed can + * not be deleted + */ + public abstract void deleteFeed(final String feedId) + throws StorageException; + + /** + * Updates a stored feed. The Feed must provide information about the + * service type to store the feed for and the feed id used for accessing and + * retrieving the feed from the storage. + * + * @param feed - + * the feed to update + * @param accountname - + * the account name belongs to the feed + * @throws StorageException - + * if the feed does not exist or the feed can not be updated + */ + public abstract void updateFeed(final ServerBaseFeed feed, + String accountname) throws StorageException; + + /** + * Retrieves the service name for a stored feed + * + * @param feedId - + * the feed id + * @return - the name of the service + * @throws StorageException - + * if no feed for the provided id is stored + */ + public abstract String getServiceForFeed(String feedId) + throws StorageException; + + /** + * @param accountName - + * the name of the requested account + * @return - a {@link GDataAccount} instance for the requested account name + * @throws StorageException - + * if no account for the account name is stored + * + */ + public abstract GDataAccount getAccount(String accountName) + throws StorageException; + + /** + * close this storage instance. This method will be called by clients after + * use. + */ + public abstract void close(); + + /** + * Each feed belongs to one specific account. This method retrieves the + * account name for + * + * @param feedId - + * the id of the feed to retrieve the accountname + * @return - the name / id of the account associated with the feed for the + * given feed id + * @throws StorageException - + * if the feed is not stored or the storage can not be accessed + */ + public String getAccountNameForFeedId(String feedId) + throws StorageException; + + /** + * Retrieves the date of the last modification for the given id + * + * @param entryId - + * the entry Id + * @param feedId - + * the feed which contains the entry + * @return - The date of the last modifiaction in milliseconds or + * new Long(0) if the resource can not be found eg. + * the time can not be accessed + * @throws StorageException - + * if the storage can not be accessed + */ + public Long getEntryLastModified(String entryId, String feedId) + throws StorageException; + + /** + * Retrieves the date of the last modification for the given id + * + * @param feedId - + * the feed Id + * @return - The date of the last modifiaction in milliseconds or + * new Long(0) if the resource can not be found eg. + * the time can not be accessed + * @throws StorageException - + * if the storage can not be accessed + */ + public Long getFeedLastModified(String feedId) throws StorageException; + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageController.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageController.java index 312cacba010..d73d43f60c4 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageController.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageController.java @@ -1,27 +1,61 @@ -/** - * 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.storage; + +import org.apache.lucene.gdata.server.registry.ServerComponent; + +/** + * An interface to define a central storage controller acting as a + * Stroage Factory. The StroageController manages the + * storage logic. Subclasses of {@link StorageController} can be registered as + * {@link org.apache.lucene.gdata.server.registry.Component} in the + * {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry}. A + * single instance of the contorller will be loaded and passed to clients via + * the lookup service. + *

+ * This instances, registered in the registry must be thread save as they are + * shared between several clients + *

+ *

+ * Each StroageController implementation must provide a super user + * {@link org.apache.lucene.gdata.data.GDataAccount} with all + * {@link org.apache.lucene.gdata.data.GDataAccount.AccountRole} set. This + * account must have the defined name administrator and a default + * password password. The password has to be updated by the server + * administrator before production use. + * To get the predefinded GDataAccount use {@link org.apache.lucene.gdata.data.GDataAccount#createAdminAccount()} + *

+ * * - * 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.storage; - -/** - * @author Simon Willnauer - * - */ -public interface StorageController { -/** - * Destroys the controller - */ -public abstract void destroy(); -} + */ +public interface StorageController extends ServerComponent { + /** + * Destroys the controller - this method is called by the registry when the + * context will be destroyed + */ + public abstract void destroy(); + + /** + * Creates Storage instances to access the underlaying storage component + * + * @return a storage instance + * @throws StorageException - + * if the storage instance can not be created + */ + public abstract Storage getStorage() throws StorageException; +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageFactory.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageFactory.java index 1151899a895..e69de29bb2d 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageFactory.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/StorageFactory.java @@ -1,44 +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.storage; - -import java.io.IOException; - -import org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation; - -/** - *TODO document me - * @author Simon Willnauer - * - */ -public class StorageFactory { - /** - * Creates a {@link Storage} instance - * @return - a storage instance - * @throws StorageException - if the storage can not be created - */ - public static Storage getStorage()throws StorageException{ - try { - return new StorageImplementation(); - } catch (IOException e) { - StorageException ex = new StorageException("Can't create Storage instance -- " - + e.getMessage(), e); - ex.setStackTrace(e.getStackTrace()); - throw ex; - - } - } -} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageBuffer.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageBuffer.java index 589289bf869..22370d854f0 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageBuffer.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageBuffer.java @@ -16,19 +16,26 @@ package org.apache.lucene.gdata.storage.lucenestorage; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation; + +import com.google.gdata.data.BaseEntry; +import com.google.gdata.data.ExtensionProfile; +import com.google.gdata.data.Link; /** * The StorageBuffer is used to buffer incoming updates, deletes and inserts to @@ -55,7 +62,9 @@ import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.Storage public class StorageBuffer { private static final Log LOG = LogFactory.getLog(StorageBuffer.class); - private final Map> bufferMap; + private final Map> bufferMap; + + private final Map modifiyMap; private final List excludeList; @@ -86,6 +95,9 @@ public class StorageBuffer { this.excludeList = new ArrayList( expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT : expectedBufferCount); + this.modifiyMap = new HashMap( + expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT + : expectedBufferCount); } /** @@ -114,7 +126,9 @@ public class StorageBuffer { 20); newFeedMap.put(wrapper.getEntryId(), wrapper); this.bufferMap.put(feedId, newFeedMap); + } + addLastModified(wrapper.getFeedId(),wrapper.getTimestamp()); } finally { /* * add all to exclude from searches doc will be available via the @@ -124,6 +138,22 @@ public class StorageBuffer { this.writeLock.unlock(); } } + + private void addLastModified(final String feedId,Long timestamp){ + if(this.modifiyMap.containsKey(feedId)) + this.modifiyMap.remove(feedId); + this.modifiyMap.put(feedId,timestamp); + + } + + protected Long getFeedLastModified(final String feedId){ + return this.modifiyMap.get(feedId); + } + protected Set> getLastModified(){ + return this.modifiyMap.entrySet(); + } + + /** * Returns all entries for the given feed id sorted by the update timestamp @@ -173,6 +203,7 @@ public class StorageBuffer { if (tempMap == null) return; tempMap.remove(entryId); + this.addLastModified(feedId,new Long(System.currentTimeMillis())); } finally { this.writeLock.unlock(); @@ -230,6 +261,7 @@ public class StorageBuffer { private void clearBuffer() { this.bufferMap.clear(); this.excludeList.clear(); + this.modifiyMap.clear(); } @@ -245,5 +277,36 @@ public class StorageBuffer { } } + + + static class BufferableEntry extends BaseEntry{ + + /** + * + */ + @SuppressWarnings("unchecked") + public BufferableEntry() { + super(); + this.links = new LinkedList(); + } + + /** + * @param arg0 + */ + @SuppressWarnings("unchecked") + public BufferableEntry(BaseEntry arg0) { + super(arg0); + this.links = new LinkedList(); + } + + /** + * @see com.google.gdata.data.BaseEntry#declareExtensions(com.google.gdata.data.ExtensionProfile) + */ + @Override + public void declareExtensions(ExtensionProfile arg0) { + // + } + + } } diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java index 78e01881bb5..f168d3c288c 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java @@ -1,286 +1,398 @@ -package org.apache.lucene.gdata.storage.lucenestorage; - -import java.io.File; -import java.io.IOException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.lucene.analysis.standard.StandardAnalyzer; -import org.apache.lucene.gdata.server.registry.GDataServerRegistry; -import org.apache.lucene.gdata.storage.IDGenerator; -import org.apache.lucene.gdata.storage.StorageController; -import org.apache.lucene.gdata.storage.StorageException; -import org.apache.lucene.gdata.storage.lucenestorage.configuration.StorageConfigurator; -import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter; -import org.apache.lucene.index.IndexModifier; -import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.store.Directory; -import org.apache.lucene.store.FSDirectory; - -/** - * TODO document this - * @author Simon Willnauer +package org.apache.lucene.gdata.storage.lucenestorage; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.gdata.data.GDataAccount; +import org.apache.lucene.gdata.server.registry.Component; +import org.apache.lucene.gdata.server.registry.ComponentType; +import org.apache.lucene.gdata.storage.IDGenerator; +import org.apache.lucene.gdata.storage.Storage; +import org.apache.lucene.gdata.storage.StorageController; +import org.apache.lucene.gdata.storage.StorageException; +import org.apache.lucene.gdata.storage.lucenestorage.configuration.StorageConfigurator; +import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter; +import org.apache.lucene.index.IndexModifier; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.FSDirectory; +import org.apache.lucene.store.RAMDirectory; + +/** + * * - */ -public class StorageCoreController implements StorageController{ - protected static final Log LOG = LogFactory.getLog(StorageCoreController.class); - private IndexSearcher searcher; - private static StorageCoreController coreController; - private final Directory storageDir; - private final StorageModifier modifier; - private ReferenceCounter storageQuery; - private StorageBuffer currentBuffer; - private Object storageControllerLock = new Object(); - private static final int DEFAULT_STORAGE_BUFFER_SIZE = 10; - private static final int DEFAULT_STORAGE_PERSIST_FACTOR = 10; - private static final String STORAGELOG = ".lucenestorage"; - private int storageBufferSize; - private int storagePersistFactor; - private StorageConfigurator configurator; - private IDGenerator idGenerator; - private int indexOptimizeInterval; - - private StorageCoreController()throws IOException, StorageException{ - this(null); - } + * @author Simon Willnauer + * + */ +@Component(componentType = ComponentType.STORAGECONTROLLER) +public class StorageCoreController implements StorageController { + protected static final Log LOG = LogFactory + .getLog(StorageCoreController.class); + + private IndexSearcher searcher; + + private final Directory storageDir; + + private final StorageModifier modifier; + + private ReferenceCounter storageQuery; + + private StorageBuffer currentBuffer; + + private Object storageControllerLock = new Object(); + + private static final int DEFAULT_STORAGE_BUFFER_SIZE = 10; + + private static final int DEFAULT_STORAGE_PERSIST_FACTOR = 10; + + private static final String STORAGELOG = ".lucenestorage"; + + private int storageBufferSize; + + private int storagePersistFactor; + + private StorageConfigurator configurator; + + private IDGenerator idGenerator; + + private int indexOptimizeInterval; +// private RecoverController recoverController; + + /** + * Creates a new StoragCoreController and sets up the storage + * environment reading the configuration file. + * + * + * + * @throws IOException - + * if an IOException occures + * @throws StorageException - + * if the storage lock can not be created or the + * {@link IDGenerator} can not be loaded + */ + public StorageCoreController() throws IOException, StorageException { + synchronized (StorageCoreController.class) { + try { + this.idGenerator = new IDGenerator(10); + } catch (Exception e) { + throw new StorageException("Can't create ID Generator", e); + } + + boolean createNewStorage = false; + this.configurator = StorageConfigurator.getStorageConfigurator(); + if (!this.configurator.isRamDirectory()) { + + String storageDirPath = this.configurator.getStorageDirectory(); + File storeDir = new File(storageDirPath); + File storageLog = new File(storeDir.getAbsolutePath() + + System.getProperty("file.separator") + STORAGELOG); + try { + if (storeDir.isDirectory() && !storageLog.exists()) { + + if (createLuceneStorageLog(storeDir)) { + this.storageDir = FSDirectory.getDirectory( + storeDir, true); + createNewStorage = true; + } else + throw new StorageException( + "could not create storage lock file in " + + storageDirPath); + + } else + this.storageDir = FSDirectory.getDirectory(storeDir, + false); + } catch (IOException e) { + storageLog.delete(); + throw e; + } + this.indexOptimizeInterval = this.configurator + .getIndexOptimizeInterval(); + this.storageBufferSize = this.configurator + .getStorageBufferSize() < DEFAULT_STORAGE_BUFFER_SIZE ? DEFAULT_STORAGE_BUFFER_SIZE + : this.configurator.getStorageBufferSize(); + this.storagePersistFactor = this.configurator + .getStoragepersistFactor() < DEFAULT_STORAGE_PERSIST_FACTOR ? DEFAULT_STORAGE_PERSIST_FACTOR + : this.configurator.getStoragepersistFactor(); + + } else + this.storageDir = getRamDirectory(); + + this.currentBuffer = new StorageBuffer(this.storageBufferSize); + this.modifier = createStorageModifier(createNewStorage); + this.searcher = new IndexSearcher(this.storageDir); +// this.recoverController = new RecoverController(null,this.configurator.isRecover(),this.configurator.isKeepRecoveredFiles()); + if(createNewStorage) + createAdminAccount(); + + } + + } + + private StorageModifier createStorageModifier(boolean create) + throws IOException { + IndexModifier indexModifier = new IndexModifier(this.storageDir, + new StandardAnalyzer(), create); + return new StorageModifier(this, indexModifier, this.currentBuffer, + this.storagePersistFactor, this.indexOptimizeInterval); + } + + /** + * returns the current storage modifier + * + * @return - the current storage modifier + */ + protected StorageModifier getStorageModifier() { + return this.modifier; + } + + /** + * returns a StorageQuery to query the storage index. The + * returned object is a reference counter to keep track of the references to + * the StorageQuery. The reference is already incremented before + * returned from this method. + *

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

+ * + * @return a {@link ReferenceCounter} instance holding the StorageQuery as a + * resource. + * + */ + protected ReferenceCounter getStorageQuery() { + synchronized (this.storageControllerLock) { + + if (this.storageQuery == null) { + this.storageQuery = getNewStorageQueryHolder(new StorageQuery( + this.currentBuffer, this.searcher)); + if (LOG.isInfoEnabled()) + LOG.info("Relese new StorageQuery"); + } + this.storageQuery.increamentReference(); + return this.storageQuery; + } + } + + private ReferenceCounter getNewStorageQueryHolder( + final StorageQuery query) { + ReferenceCounter holder = new ReferenceCounter( + query) { + public void close() { + try { + if (LOG.isInfoEnabled()) + LOG + .info("close StorageQuery -- zero references remaining"); + this.resource.close(); + } catch (IOException e) { + LOG.warn("Error during close call on StorageQuery" + + e.getMessage(), e); + } + } + }; + holder.increamentReference(); + return holder; + } + + /** + * Forces the controller to register a new StorageQuery instance. + * This method will be called after an index has been modified to make the + * changes available for searching. + * + * @throws IOException - + * if an IO exception occures + */ + protected void registerNewStorageQuery() throws IOException { + if (LOG.isInfoEnabled()) + LOG.info("new StorageQuery requested -- create new storage buffer"); + synchronized (this.storageControllerLock) { + if (this.storageQuery != null) + this.storageQuery.decrementRef(); + this.searcher = new IndexSearcher(this.storageDir); + this.storageQuery = null; + this.currentBuffer = new StorageBuffer(this.storageBufferSize); + + } + + } + + /** + * Creates a new StorageBuffer + * + * @return the new StorageBuffer + */ + protected StorageBuffer releaseNewStorageBuffer() { + synchronized (this.storageControllerLock) { + return this.currentBuffer; + } + } + + /** + * Creates a new IndexModifier on the storage index + * + * @return - a new modifier + * @throws IOException - + * if an IO exception occures + */ + protected IndexModifier createIndexModifier() throws IOException { + if (LOG.isInfoEnabled()) + LOG.info("new IndexModifier created - release to StorageModifier"); + synchronized (this.storageControllerLock) { + return new IndexModifier(this.storageDir, new StandardAnalyzer(), + false); + } + } + + private void close() throws IOException { + synchronized (this.storageControllerLock) { + if (LOG.isInfoEnabled()) + LOG + .info("StorageController has been closed -- server is shutting down -- release all resources"); + if (this.storageQuery != null) + this.storageQuery.decrementRef(); + this.modifier.close(); + // TODO make sure all resources will be released + } + } + + /** + * The size of the StorageBuffer. + * + * @return - storage buffer size + */ + public int getStorageBufferSize() { + return this.storageBufferSize; + } + + /** + * The size of the StorageBuffer. This size should be at least + * as big as the persist factor to prevent the StorageBuffer from + * resizing + * + * @param storageBufferSize + */ + public void setStorageBufferSize(int storageBufferSize) { + this.storageBufferSize = storageBufferSize; + } + + /** + * An integer value after how many changes to the StorageModifier the + * buffered changes will be persisted / wirtten to the index + * + * @return - the persist factor + */ + public int getStoragePersistFactor() { + return this.storagePersistFactor; + } + + /** + * @param storagePersistFactor + */ + public void setStoragePersistFactor(int storagePersistFactor) { + this.storagePersistFactor = storagePersistFactor; + } + + /** + * Forces the StorageModifier to write all buffered changes. + * + * @throws IOException - + * if an IO exception occures + * + */ + public void forceWrite() throws IOException { + this.modifier.forceWrite(); + } + + private boolean createLuceneStorageLog(File storageDirectory) + throws IOException { + if (storageDirectory.isDirectory() && !storageDirectory.exists()) { + storageDirectory.createNewFile(); + } + File file = new File(storageDirectory.getAbsolutePath() + + System.getProperty("file.separator") + STORAGELOG); + return file.createNewFile(); + + } + + /** + * Creates a unique ID to store as an id for + * {@link org.apache.lucene.gdata.data.ServerBaseEntry} instances + * + * @return - a unique id + * @throws StorageException - + * if no id can be released + */ + public synchronized String releaseID() throws StorageException { + try { + return this.idGenerator.getUID(); + } catch (InterruptedException e) { + throw new StorageException("Can't release new ID", e); + } + + } + + /** + * @see org.apache.lucene.gdata.storage.StorageController#destroy() + */ + public void destroy() { + try { + close(); + } catch (Exception e) { + LOG.error("Closing StorageCoreController failed -- " + + e.getMessage(), e); + } + } + + /** + * + * @return - the lucene directory used as a storage + */ + protected Directory getDirectory() { + return this.storageDir; + } + + /** + * @see org.apache.lucene.gdata.storage.StorageController#getStorage() + */ + public Storage getStorage() throws StorageException { + try { + return new StorageImplementation(); + } catch (StorageException e) { + StorageException ex = new StorageException( + "Can't create Storage instance -- " + e.getMessage(), e); + ex.setStackTrace(e.getStackTrace()); + throw ex; + + } + } + + // TODO Try to remove this --> testcases + private RAMDirectory getRamDirectory() throws IOException { + IndexWriter writer; + RAMDirectory retVal = new RAMDirectory(); + writer = new IndexWriter(retVal, new StandardAnalyzer(), true); + writer.close(); + return retVal; + } + + /** + * @see org.apache.lucene.gdata.server.registry.ServerComponent#initialize() + */ + public void initialize() { + // + } - - - private StorageCoreController(final Directory dir) throws IOException, StorageException { - synchronized (StorageCoreController.class) { - try{ - this.idGenerator = new IDGenerator(10); - }catch (Exception e) { - throw new StorageException("Can't create ID Generator",e); - } - - boolean createNewStorage = false; - - if(dir == null){ - this.configurator = StorageConfigurator.getStorageConfigurator(); - String storageDirPath = this.configurator.getStorageDirectory(); - File storeDir = new File(storageDirPath); - File storageLog = new File(storeDir.getAbsolutePath()+System.getProperty("file.separator")+STORAGELOG); - try{ - if(storeDir.isDirectory() && !storageLog.exists()){ - - if(createLuceneStorageLog(storeDir)){ - this.storageDir = FSDirectory.getDirectory(storeDir,true); - createNewStorage = true; - } - else - throw new StorageException("could not create storage log file in "+storageDirPath); - - }else - this.storageDir = FSDirectory.getDirectory(storeDir,false); - }catch (IOException e) { - storageLog.delete(); - throw e; - } - this.indexOptimizeInterval = this.configurator.getIndexOptimizeInterval(); - this.storageBufferSize = this.configurator.getStorageBufferSize() < DEFAULT_STORAGE_BUFFER_SIZE?DEFAULT_STORAGE_BUFFER_SIZE:this.configurator.getStorageBufferSize(); - this.storagePersistFactor = this.configurator.getStoragepersistFactor() < DEFAULT_STORAGE_PERSIST_FACTOR? DEFAULT_STORAGE_PERSIST_FACTOR:this.configurator.getStoragepersistFactor(); - - } - else - this.storageDir = dir; - - this.currentBuffer = new StorageBuffer(this.storageBufferSize); - this.modifier = createStorageModifier(createNewStorage); - this.searcher = new IndexSearcher(this.storageDir); - - - GDataServerRegistry.getRegistry().registerStorage(this);// TODO reverse dependency here - - - - } - - } - private StorageModifier createStorageModifier(boolean create) throws IOException{ - IndexModifier indexModifier = new IndexModifier(this.storageDir,new StandardAnalyzer(),create); - return new StorageModifier(indexModifier,this.currentBuffer,this.storagePersistFactor,this.indexOptimizeInterval); - } - /**TODO document this - * @return - */ - public StorageModifier getStorageModifier(){ - return this.modifier; - } - - /**TODO document this - * @return - * @throws IOException - * @throws StorageException - */ - public static StorageCoreController getStorageCoreController() throws IOException, StorageException{ - synchronized (StorageCoreController.class) { - if(coreController == null) - coreController = new StorageCoreController(); - return coreController; - } - } - /**TODO document this - * @param dir - * @return - * @throws IOException - * @throws StorageException - */ - protected static StorageCoreController getStorageCoreController(final Directory dir) throws IOException, StorageException{ - synchronized (StorageCoreController.class) { - if(coreController == null) - coreController = new StorageCoreController(dir); - return coreController; - } - } - - /**TODO document this - * @return - * @throws IOException - */ - public ReferenceCounter getStorageQuery() throws IOException { - synchronized (this.storageControllerLock) { - - if(this.storageQuery == null){ - this.storageQuery = getNewStorageQueryHolder(new StorageQuery(this.currentBuffer,this.searcher)); - if(LOG.isInfoEnabled()) - LOG.info("Relese new StorageQuery"); - } - this.storageQuery.increamentReference(); - return this.storageQuery; - } - } - - private ReferenceCounter getNewStorageQueryHolder(final StorageQuery query){ - ReferenceCounter holder = new ReferenceCounter(query){ - public void close(){ - try{ - if(LOG.isInfoEnabled()) - LOG.info("close StorageQuery -- zero references remaining"); - this.resource.close(); - }catch (IOException e) { - LOG.warn("Error during close call on StorageQuery"+e.getMessage(),e); - } - } - }; - holder.increamentReference(); - return holder; - } - - - - protected void registerNewStorageQuery() throws IOException{ - if(LOG.isInfoEnabled()) - LOG.info("new StorageQuery requested -- create new storage buffer"); - synchronized (this.storageControllerLock) { - if(this.storageQuery != null) - this.storageQuery.decrementRef(); - this.searcher = new IndexSearcher(this.storageDir); - this.storageQuery = null; - this.currentBuffer = new StorageBuffer(this.storageBufferSize); - - } - - } - - - protected StorageBuffer releaseNewStorageBuffer() { - synchronized (this.storageControllerLock) { - return this.currentBuffer; - } - } - - /**TODO document this - * @return - * @throws IOException - */ - public IndexModifier createIndexModifier() throws IOException { - if(LOG.isInfoEnabled()) - LOG.info("new IndexModifier created - release to StorageModifier"); - synchronized (this.storageControllerLock) { - return new IndexModifier(this.storageDir,new StandardAnalyzer(),false); - } - } - - private void close() throws IOException{ - synchronized (this.storageControllerLock) { - if(LOG.isInfoEnabled()) - LOG.info("StorageController has been closed -- server is shutting down -- release all resources"); - if(this.storageQuery != null) - this.storageQuery.decrementRef(); - coreController = null; - this.modifier.close(); - //TODO make sure all resources will be released - } - } - /**TODO document this - * @return - */ - public int getStorageBufferSize() { - return this.storageBufferSize; - } - /** - * @param storageBufferSize - */ - public void setStorageBufferSize(int storageBufferSize) { - this.storageBufferSize = storageBufferSize; - } - /**TODO document this - * @return - */ - public int getStoragePersistFactor() { - return this.storagePersistFactor; - } - /** - * @param storagePersistFactor - */ - public void setStoragePersistFactor(int storagePersistFactor) { - this.storagePersistFactor = storagePersistFactor; - } - /** - * @throws IOException - * @throws StorageException - */ - public void forceWrite()throws IOException, StorageException{ - this.modifier.forceWrite(); - } - - - private boolean createLuceneStorageLog(File storageDirectory) throws IOException{ - if(storageDirectory.isDirectory() && !storageDirectory.exists()){ - storageDirectory.createNewFile(); - } - File file = new File(storageDirectory.getAbsolutePath()+System.getProperty("file.separator")+STORAGELOG); - return file.createNewFile(); - - - } - - - /**TODO document this - * @return - * @throws StorageException - */ - public synchronized String releaseID() throws StorageException{ - try{ - return this.idGenerator.getUID(); - }catch (InterruptedException e) { - throw new StorageException("Can't release new ID",e); - } - - } - - - - /** - * @see org.apache.lucene.gdata.storage.StorageController#destroy() - */ - public void destroy() { - try{ - close(); - }catch (Exception e) { - LOG.error("Closing StorageCoreController failed -- "+e.getMessage(),e); - } - } -} + private void createAdminAccount() throws StorageException{ + GDataAccount adminAccount = GDataAccount.createAdminAccount(); + StorageAccountWrapper wrapper = new StorageAccountWrapper(adminAccount); + this.getStorageModifier().createAccount(wrapper); + } + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageEntryWrapper.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageEntryWrapper.java index bd3ebda73c7..76d4911f326 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageEntryWrapper.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageEntryWrapper.java @@ -12,177 +12,215 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ - -package org.apache.lucene.gdata.storage.lucenestorage; - -import java.io.IOException; -import java.io.StringWriter; - -import org.apache.lucene.document.Document; -import org.apache.lucene.document.Field; - -import com.google.gdata.data.BaseEntry; -import com.google.gdata.data.ExtensionProfile; -import com.google.gdata.util.common.xml.XmlWriter; - -/** - * This immutable class wrapps Entries for an internal Storage representation of - * an entry. This class also acts as a Documentfactory for lucene documents to - * be stored inside the index. - * - * @author Simon Willnauer - * - */ -public class StorageEntryWrapper implements Comparable { - private static final String INTERNAL_ENCODING = "UTF-8"; - - /** - * lucene field name Entry id - */ - public final static String FIELD_ENTRY_ID = "entryId"; - - /** - * lucene field name feed id - */ - public final static String FIELD_FEED_ID = "feedId"; - - /** - * lucene field name entry content - */ - public final static String FIELD_CONTENT = "content"; - - /** - * lucene field name creating timestamp - */ - public final static String FIELD_TIMESTAMP = "timestamp"; - - private final String entryId; - - private final String feedId; - - private final String content; - - private final transient BaseEntry entry; - - private final Long timestamp; - - private transient Document document; - - private StorageOperation operation; - - private final ExtensionProfile profile; - - /** - * Creates a new StorageEntryWrapper. - * - * @param entry - - * the entry to wrap - * @param feedId - - * the feed id - * @param operation - - * the StorageOperation - * @param profile - - * the ExtensionProfil for the given entry - * @throws IOException - - * if the entry content can not be generated - */ - protected StorageEntryWrapper(final BaseEntry entry, final String feedId, - StorageOperation operation, final ExtensionProfile profile) - throws IOException { - this.entry = entry; - this.operation = operation; - this.entryId = entry.getId(); - this.feedId = feedId; - this.profile = profile; - this.content = buildContent(); - this.timestamp = new Long(System.currentTimeMillis()); - - } - - private String buildContent() throws IOException { - StringWriter writer = new StringWriter(); - XmlWriter xmlWriter = new XmlWriter(writer, INTERNAL_ENCODING); - this.entry.generateAtom(xmlWriter, this.profile); - return writer.toString(); - - } - - /** - * @return - the lucene document representing the entry - */ - public Document getLuceneDocument() { - if (this.document != null) - return this.document; - this.document = new Document(); - this.document.add(new Field("entryId", this.entryId, Field.Store.YES, - Field.Index.UN_TOKENIZED)); - this.document.add(new Field("feedId", this.feedId, Field.Store.YES, - Field.Index.UN_TOKENIZED)); - this.document.add(new Field("content", this.content, - Field.Store.COMPRESS, Field.Index.UN_TOKENIZED)); - this.document.add(new Field("timestamp", this.timestamp.toString(), - Field.Store.YES, Field.Index.UN_TOKENIZED)); - - return this.document; - - } - - /** - * @return - the wrapped entry - */ - public BaseEntry getEntry() { - return this.entry; - } - - /** - * @return - the entry id - */ - public String getEntryId() { - return this.entryId; - } - - /** - * @return - the feed id - */ - public String getFeedId() { - return this.feedId; - } - - /** - * Storage operations - * - * @author Simon Willnauer - * - */ - public static enum StorageOperation { - /** - * delete - */ - DELETE, - /** - * update - */ - UPDATE, - /** - * insert - */ - INSERT - } - - /** - * @return the specified storage operation - */ - public StorageOperation getOperation() { - return this.operation; - } - - /** - * @see java.lang.Comparable#compareTo(T) - */ - public int compareTo(StorageEntryWrapper arg0) { - return arg0.timestamp == this.timestamp ? 0 - : (arg0.timestamp > this.timestamp ? 1 : -1); - } - -} + */ + +package org.apache.lucene.gdata.storage.lucenestorage; + +import java.io.IOException; +import java.io.StringWriter; + +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.apache.lucene.gdata.server.registry.ProvidedService; +import org.apache.lucene.gdata.server.registry.ProvidedServiceConfig; +import org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer.BufferableEntry; + +import com.google.gdata.data.BaseEntry; +import com.google.gdata.util.common.xml.XmlWriter; + +/** + * This immutable class wrapps ServerBaseEntry for an internal + * Storage representation of an entry. This class also acts as a Documentfactory + * for lucene documents to be stored inside the index. + * + * @author Simon Willnauer + * + */ +public class StorageEntryWrapper implements Comparable, + StorageWrapper { + + private static final long serialVersionUID = -4619985652059888526L; + + private static final String INTERNAL_ENCODING = "UTF-8"; + + /** + * lucene field name Entry id + */ + public final static String FIELD_ENTRY_ID = "entryId"; + + /** + * lucene field name feed id + */ + public final static String FIELD_FEED_REFERENCE = "feedReference"; + + /** + * lucene field name entry content + */ + public final static String FIELD_CONTENT = "content"; + + /** + * lucene field name creating timestamp + */ + public final static String FIELD_TIMESTAMP = "timestamp"; + + private final String entryId; + + private final String feedId; + + private String content; + + private final ServerBaseEntry entry; + + private Long timestamp; + + private transient Document document; + + private StorageOperation operation; + + private ProvidedService config; + + /** + * Creates a new StorageEntryWrapper. + * + * @param entry - + * the entry to wrap + * + * @param operation - + * the StorageOperation + * + * @throws IOException - + * if the entry content can not be generated + */ + public StorageEntryWrapper(final ServerBaseEntry entry, + StorageOperation operation) throws IOException { + + this.entry = entry; + this.operation = operation; + this.entryId = entry.getId(); + this.feedId = entry.getFeedId(); + if (operation != StorageOperation.DELETE) { + this.config = entry.getServiceConfig(); + this.content = buildContent(); + + } + this.timestamp = new Long( + this.entry.getUpdated() != null ? this.entry.getUpdated() + .getValue() : System.currentTimeMillis()); + + + } + + private String buildContent() throws IOException { + StringWriter writer = new StringWriter(); + XmlWriter xmlWriter = new XmlWriter(writer, INTERNAL_ENCODING); + this.entry.generateAtom(xmlWriter, this.config.getExtensionProfile()); + return writer.toString(); + + } + + /** + * @see org.apache.lucene.gdata.storage.lucenestorage.StorageWrapper#getLuceneDocument() + */ + public Document getLuceneDocument() { + if(this.operation == StorageOperation.DELETE) + return null; + if (this.document != null) + return this.document; + this.document = new Document(); + this.document.add(new Field(FIELD_ENTRY_ID, this.entryId, + Field.Store.YES, Field.Index.UN_TOKENIZED)); + this.document.add(new Field(FIELD_FEED_REFERENCE, this.feedId, + Field.Store.YES, Field.Index.UN_TOKENIZED)); + this.document.add(new Field(FIELD_CONTENT, this.content, + Field.Store.COMPRESS, Field.Index.NO)); + this.document.add(new Field(FIELD_TIMESTAMP, this.timestamp.toString(), + Field.Store.YES, Field.Index.UN_TOKENIZED)); + + return this.document; + + } + + /** + * @return - the wrapped entry + */ + public BaseEntry getEntry() { + /* + * this wrapps the entry again. BufferableEntry creates a new instance + * for the dynamic element like links. + */ + return new BufferableEntry(this.entry.getEntry()); + } + + /** + * @return - the entry id + */ + public String getEntryId() { + return this.entryId; + } + + /** + * @return - the feed id + */ + public String getFeedId() { + return this.feedId; + } + + /** + * Storage operations + * + * @author Simon Willnauer + * + */ + public static enum StorageOperation { + /** + * delete + */ + DELETE, + /** + * update + */ + UPDATE, + /** + * insert + */ + INSERT + } + + /** + * @return the specified storage operation + */ + public StorageOperation getOperation() { + return this.operation; + } + + /** + * This compare method compares the timestamps of the wrapper instances. + * + * @param arg0 - + * the wrapper to compare + * @par + * @return - 0 if the wrappers timestamp are the same, an integer > 0 if the + * given wrapper is after this wrapper + * + */ + public int compareTo(StorageEntryWrapper arg0) { + return arg0.timestamp == this.timestamp ? 0 + : (arg0.timestamp > this.timestamp ? 1 : -1); + } + + /** + * @return - the specified {@link ProvidedServiceConfig} + */ + public ProvidedService getConfigurator() { + return this.config; + } + + /** + * @return Returns the timestamp. + */ + public Long getTimestamp() { + return this.timestamp; + } + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageImplementation.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageImplementation.java index 01ddd745635..91aaad0fcb4 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageImplementation.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageImplementation.java @@ -1,259 +1,526 @@ -/** - * 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.storage.lucenestorage; + +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.lucene.gdata.data.GDataAccount; +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 org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation; +import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter; + +import com.google.gdata.data.BaseEntry; +import com.google.gdata.data.BaseFeed; + +/** + * This is an implementation of the + * {@link org.apache.lucene.gdata.storage.Storage} interface. The + * StorageImplementation provides access to the + * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageQuery} and the + * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageModifier}. This + * class will be instanciated per client request. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.lucene.gdata.storage.lucenestorage; - -import java.io.IOException; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.lucene.gdata.storage.Storage; -import org.apache.lucene.gdata.storage.StorageException; -import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation; -import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter; - -import com.google.gdata.data.BaseEntry; -import com.google.gdata.data.BaseFeed; -import com.google.gdata.data.ExtensionProfile; -import com.google.gdata.data.Feed; - -/** - * This is an implementation of the - * {@link org.apache.lucene.gdata.storage.Storage} interface. The - * StorageImplementation provides access to the - * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageQuery} and the - * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageModifier}. This - * class will be instanciated per client request. - * - * - * - * @author Simon Willnauer - * - */ -public class StorageImplementation implements Storage { - private final StorageCoreController controller; - - private ExtensionProfile profile; - - private static final Log LOG = LogFactory - .getLog(StorageImplementation.class); - - /** - * Creates a new StorageImplementation - * - * @throws StorageException - - * if the - * {@link org.apache.lucene.gdata.storage.StorageController} can - * not be created - * @throws IOException - - * if the - * {@link org.apache.lucene.gdata.storage.StorageController} can - * not be created - * @see StorageCoreController#getStorageCoreController() - * - */ - public StorageImplementation() throws IOException, StorageException { - this.controller = StorageCoreController.getStorageCoreController(); - } - - /** - * @see org.apache.lucene.gdata.storage.Storage#storeEntry(com.google.gdata.data.BaseEntry, - * java.lang.String) - */ - public BaseEntry storeEntry(BaseEntry entry, String feedId) - throws StorageException { - if (this.profile == null) - throw new StorageException( - "Can process ExtensionProfile not set -- is null"); - if (feedId == null) - throw new StorageException("No feed ID specified -- is null"); - StorageModifier modifier = this.controller.getStorageModifier(); - String id = this.controller.releaseID(); - entry.setId(feedId + id); - if (LOG.isInfoEnabled()) - LOG.info("Store entry " + id + " -- feed: " + feedId); - - try { - StorageEntryWrapper wrapper = new StorageEntryWrapper(entry, - feedId, StorageOperation.INSERT, this.profile); - modifier.insertEntry(wrapper); - } catch (IOException e) { - StorageException ex = new StorageException("Can't create Entry -- " - + e.getMessage(), e); - ex.setStackTrace(e.getStackTrace()); - throw ex; - - } - - return entry; - } - - /** - * @see org.apache.lucene.gdata.storage.Storage#deleteEntry(java.lang.String, - * java.lang.String) - */ - public void deleteEntry(String entryId, String feedId) - throws StorageException { - if (this.profile == null) - throw new StorageException( - "Can process ExtensionProfile not set -- is null"); - if (feedId == null) - throw new StorageException("No feed ID specified -- is null"); - if (entryId == null) - throw new StorageException("No entry ID specified -- is null"); - if (LOG.isInfoEnabled()) - LOG.info("delete entry " + entryId + " -- feed: " + feedId); - StorageModifier modifier = this.controller.getStorageModifier(); - modifier.deleteEntry(entryId, feedId); - } - - /** - * @see org.apache.lucene.gdata.storage.Storage#updateEntry(com.google.gdata.data.BaseEntry, - * java.lang.String) - */ - public BaseEntry updateEntry(BaseEntry entry, String feedId) - throws StorageException { - if (this.profile == null) - throw new StorageException( - "Can process ExtensionProfile not set -- is null"); - if (feedId == null) - throw new StorageException("No feed ID specified -- is null"); - if (entry == null) - throw new StorageException("enrty is null"); - if (entry.getId() == null) - throw new StorageException("No entry ID specified -- is null"); - if (LOG.isInfoEnabled()) - LOG.info("update entry " + entry.getId() + " -- feed: " + feedId); - StorageModifier modifier = this.controller.getStorageModifier(); - - try { - StorageEntryWrapper wrapper = new StorageEntryWrapper(entry, - feedId, StorageOperation.UPDATE, this.profile); - modifier.updateEntry(wrapper); - } catch (IOException e) { - LOG.error("Can't update entry for feedID: " + feedId - + "; entryId: " + entry.getId() + " -- " + e.getMessage(), - e); - StorageException ex = new StorageException("Can't create Entry -- " - + e.getMessage(), e); - ex.setStackTrace(e.getStackTrace()); - throw ex; - - } - - return entry; - - } - - /** - * @see org.apache.lucene.gdata.storage.Storage#getFeed(java.lang.String, - * int, int) - */ - @SuppressWarnings("unchecked") - public BaseFeed getFeed(String feedId, int startIndex, int resultCount) - throws StorageException { - if (this.profile == null) - throw new StorageException( - "Can process ExtensionProfile not set -- is null"); - if (feedId == null) - throw new StorageException("No feed ID specified -- is null"); - if (LOG.isInfoEnabled()) - LOG.info("get feed: " + feedId + " startindex: " + startIndex - + " resultCount: " + resultCount); - ReferenceCounter query = null; - try { - query = this.controller.getStorageQuery(); - List resultList = query.get().getLatestFeedQuery(feedId, - resultCount, startIndex, this.profile); - BaseFeed feed = new Feed(); - feed.getEntries().addAll(resultList); - return feed; - } catch (Exception e) { - LOG.error("Can't get latest feed for feedID: " + feedId + " -- " - + e.getMessage(), e); - StorageException ex = new StorageException("Can't create Entry -- " - + e.getMessage(), e); - ex.setStackTrace(e.getStackTrace()); - throw ex; - - } finally { - if (query != null) - query.decrementRef(); - } - - } - - /** - * @see org.apache.lucene.gdata.storage.Storage#getEntry(java.lang.String, - * java.lang.String) - */ - public BaseEntry getEntry(String entryId, String feedId) - throws StorageException { - if (this.profile == null) - throw new StorageException( - "Can process ExtensionProfile not set -- is null"); - if (feedId == null) - throw new StorageException("No feed ID specified -- is null"); - if (entryId == null) - throw new StorageException("No entry ID specified -- is null"); - if (LOG.isInfoEnabled()) - LOG.info("get entry " + entryId + " -- feed: " + feedId); - ReferenceCounter query = null; - try { - query = this.controller.getStorageQuery(); - return query.get().singleEntryQuery(entryId, feedId, this.profile); - } catch (Exception e) { - LOG.error("Can't get entry for feedID: " + feedId + "; entryId: " - + entryId + " -- " + e.getMessage(), e); - StorageException ex = new StorageException("Can't create Entry -- " - + e.getMessage(), e); - ex.setStackTrace(e.getStackTrace()); - throw ex; - - } finally { - if (query != null) - query.decrementRef(); - } - - } - - /** - * @see org.apache.lucene.gdata.storage.Storage#getEntries(java.util.List, - * java.lang.String) - */ - public List getEntries(List entryIdList, String feedId) - throws StorageException { - throw new StorageException("not implemented yet"); - // TODO implement this - - } - - /** - * @see org.apache.lucene.gdata.storage.Storage#close() - */ - public void close() { - // - } - - /** - * @see org.apache.lucene.gdata.storage.Storage#setExtensionProfile(com.google.gdata.data.ExtensionProfile) - */ - public void setExtensionProfile(ExtensionProfile profile) { - this.profile = profile; - } - -} + * @author Simon Willnauer + * + */ +public class StorageImplementation implements Storage { + private final StorageCoreController controller; + + private static final Log LOG = LogFactory + .getLog(StorageImplementation.class); + + /** + * Creates a new StorageImplementation + * + * @throws StorageException - + * if the storage controller can not be obtained + * + * + * + */ + public StorageImplementation() throws StorageException { + this.controller = (StorageCoreController) GDataServerRegistry + .getRegistry().lookup(StorageController.class, + ComponentType.STORAGECONTROLLER); + if (this.controller == null) + throw new StorageException("Can't get registered StorageController"); + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#storeEntry(org.apache.lucene.gdata.data.ServerBaseEntry) + */ + public BaseEntry storeEntry(final ServerBaseEntry entry) + throws StorageException { + + if (entry == null) + throw new StorageException("entry is null"); + StorageModifier modifier = this.controller.getStorageModifier(); + String id = this.controller.releaseID(); + entry.setId(entry.getFeedId() + id); + if (LOG.isInfoEnabled()) + LOG.info("Store entry " + id + " -- feed: " + entry.getFeedId()); + + try { + StorageEntryWrapper wrapper = new StorageEntryWrapper(entry, + StorageOperation.INSERT); + modifier.insertEntry(wrapper); + } catch (IOException e) { + StorageException ex = new StorageException("Can't create Entry -- " + + e.getMessage(), e); + ex.setStackTrace(e.getStackTrace()); + throw ex; + + } + + return entry.getEntry(); + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#deleteEntry(org.apache.lucene.gdata.data.ServerBaseEntry) + */ + public void deleteEntry(final ServerBaseEntry entry) + throws StorageException { + + if (entry == null) + throw new StorageException("Entry is null"); + + if (LOG.isInfoEnabled()) + LOG.info("delete entry " + entry.getId() + " -- feed: " + + entry.getFeedId()); + StorageModifier modifier = this.controller.getStorageModifier(); + ReferenceCounter query = this.controller.getStorageQuery(); + try{ + if(query.get().isEntryStored(entry.getId(),entry.getFeedId())){ + + modifier.deleteEntry(new StorageEntryWrapper(entry,StorageOperation.DELETE)); + } + else + throw new ResourceNotFoundException("Entry for entry id: "+entry.getId()+" is not stored"); + }catch (IOException e) { + throw new StorageException("Can not access storage"); + }finally{ + query.decrementRef(); + } + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#updateEntry(org.apache.lucene.gdata.data.ServerBaseEntry) + */ + public BaseEntry updateEntry(ServerBaseEntry entry) throws StorageException { + + if (entry == null) + throw new StorageException("entry is null"); + if(entry.getId() == null) + throw new StorageException("entry id is null"); + if(entry.getFeedId() == null) + throw new StorageException("feed id is null"); + if (LOG.isInfoEnabled()) + LOG.info("update entry " + entry.getId() + " -- feed: " + + entry.getFeedId()); + StorageModifier modifier = this.controller.getStorageModifier(); + ReferenceCounter query = this.controller.getStorageQuery(); + try { + StorageEntryWrapper wrapper = new StorageEntryWrapper(entry, + StorageOperation.UPDATE); + if(query.get().isEntryStored(entry.getId(),entry.getFeedId())) + modifier.updateEntry(wrapper); + else + throw new ResourceNotFoundException("Entry for entry id: "+entry.getId()+" is not stored"); + + } catch (IOException e) { + LOG.error("Can't update entry for feedID: " + entry.getFeedId() + + "; entryId: " + entry.getId() + " -- " + e.getMessage(), + e); + StorageException ex = new StorageException("Can't create Entry -- " + + e.getMessage(), e); + ex.setStackTrace(e.getStackTrace()); + throw ex; + + } + + return entry.getEntry(); + + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#getFeed(org.apache.lucene.gdata.data.ServerBaseFeed) + */ + @SuppressWarnings("unchecked") + public BaseFeed getFeed(final ServerBaseFeed feed) throws StorageException { + + if (feed == null) + throw new StorageException("feed is null"); + if (LOG.isInfoEnabled()) + LOG.info("get feed: " + feed.getId() + " startindex: " + + feed.getStartIndex() + " resultCount: " + + feed.getItemsPerPage()); + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + BaseFeed retVal = query.get().getLatestFeedQuery(feed.getId(), + feed.getItemsPerPage(), feed.getStartIndex(), + feed.getServiceConfig()); + return retVal; + } catch (Exception e) { + LOG.error("Can't get latest feed for feedID: " + feed.getId() + + " -- " + e.getMessage(), e); + StorageException ex = new StorageException("Can't create Entry -- " + + e.getMessage(), e); + ex.setStackTrace(e.getStackTrace()); + throw ex; + + } finally { + if (query != null) + query.decrementRef(); + } + + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#getEntry(org.apache.lucene.gdata.data.ServerBaseEntry) + */ + public BaseEntry getEntry(final ServerBaseEntry entry) + throws StorageException { + + if (entry == null) + throw new StorageException("No entry specified -- is null"); + if (LOG.isInfoEnabled()) + LOG.info("get entry " + entry.getId() + " -- feed: " + + entry.getFeedId()); + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + BaseEntry retVal = query.get().singleEntryQuery(entry.getId(), + entry.getFeedId(), entry.getServiceConfig()); + if(retVal == null) + throw new ResourceNotFoundException("can not get entry for entry ID "+entry.getId()); + return retVal; + } catch (Exception e) { + LOG.error("Can't get entry for feedID: " + entry.getFeedId() + + "; entryId: " + entry.getId() + " -- " + e.getMessage(), + e); + StorageException ex = new StorageException("Can't create Entry -- " + + e.getMessage(), e); + ex.setStackTrace(e.getStackTrace()); + throw ex; + + } finally { + if (query != null) + query.decrementRef(); + } + + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#close() + */ + public void close() { + // + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#storeAccount(org.apache.lucene.gdata.data.GDataAccount) + */ + public void storeAccount(GDataAccount Account) throws StorageException { + if (Account == null) + throw new StorageException("Can not save null Account"); + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + if (query.get().getUser(Account.getName()) != null) + throw new StorageException("Account already exists"); + StorageModifier modifier = this.controller.getStorageModifier(); + StorageAccountWrapper wrapper = new StorageAccountWrapper(Account); + modifier.createAccount(wrapper); + } catch (Exception e) { + LOG.error("Can't save Account -- " + e.getMessage(), e); + StorageException ex = new StorageException("Can't save Account -- " + + e.getMessage(), e); + ex.setStackTrace(e.getStackTrace()); + throw ex; + + } finally { + if (query != null) + query.decrementRef(); + } + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#updateAccount(org.apache.lucene.gdata.data.GDataAccount) + */ + public void updateAccount(GDataAccount Account) throws StorageException { + if (Account == null) + throw new StorageException("Can not update null Account"); + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + if (query.get().getUser(Account.getName()) == null) + throw new StorageException("Account does not exist"); + StorageModifier modifier = this.controller.getStorageModifier(); + StorageAccountWrapper wrapper = new StorageAccountWrapper(Account); + modifier.updateAccount(wrapper); + } catch (Exception e) { + LOG.error("Can't update Account -- " + e.getMessage(), e); + StorageException ex = new StorageException( + "Can't update Account -- " + e.getMessage(), e); + ex.setStackTrace(e.getStackTrace()); + throw ex; + + } finally { + if (query != null) + query.decrementRef(); + } + + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#deleteAccount(java.lang.String) + */ + public void deleteAccount(String Accountname) throws StorageException { + if (Accountname == null) + throw new StorageException("can not delete null Account"); + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + if (query.get().getUser(Accountname) == null) + throw new StorageException("Account does not exist"); + StorageModifier modifier = this.controller.getStorageModifier(); + modifier.deleteAccount(Accountname); + } catch (Exception e) { + LOG.error("Can't update Account -- " + e.getMessage(), e); + StorageException ex = new StorageException( + "Can't update Account -- " + e.getMessage(), e); + ex.setStackTrace(e.getStackTrace()); + throw ex; + + } finally { + if (query != null) + query.decrementRef(); + } + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#storeFeed(org.apache.lucene.gdata.data.ServerBaseFeed, + * java.lang.String) + */ + public void storeFeed(ServerBaseFeed feed, String accountName) + throws StorageException { + if (feed == null) + throw new StorageException("can not insert null feed"); + if (accountName == null) + throw new StorageException("accountName must not be null"); + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + if (query.get().isFeedStored(feed.getId())) + throw new StorageException("feed with feedID " + feed.getId() + + " is already stored"); + StorageModifier modifier = this.controller.getStorageModifier(); + StorageFeedWrapper wrapper = new StorageFeedWrapper(feed, + accountName); + modifier.createFeed(wrapper); + + } catch (Exception e) { + LOG.error("Can't create feed -- " + e.getMessage(), e); + StorageException ex = new StorageException("Can't create feed -- " + + e.getMessage(), e); + ex.setStackTrace(e.getStackTrace()); + throw ex; + + } finally { + if (query != null) + query.decrementRef(); + } + + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#deleteFeed(java.lang.String) + */ + public void deleteFeed(String feedId) throws StorageException { + if (feedId == null) + throw new StorageException("can not delete feed id is null "); + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + if (!query.get().isFeedStored(feedId)) + throw new StorageException("Account does not exist"); + StorageModifier modifier = this.controller.getStorageModifier(); + + modifier.deleteFeed(feedId); + + } catch (Exception e) { + LOG.error("Can't delete feed -- " + e.getMessage(), e); + StorageException ex = new StorageException("Can't create feed -- " + + e.getMessage(), e); + ex.setStackTrace(e.getStackTrace()); + throw ex; + + } finally { + if (query == null) + query.decrementRef(); + } + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#updateFeed(org.apache.lucene.gdata.data.ServerBaseFeed, + * java.lang.String) + */ + public void updateFeed(ServerBaseFeed feed, String accountName) + throws StorageException { + if (feed == null) + throw new StorageException("can not update null feed"); + if (accountName == null) + throw new StorageException("accountName must not be null"); + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + if (!query.get().isFeedStored(feed.getId())) + throw new StorageException("Account does not exist"); + StorageModifier modifier = this.controller.getStorageModifier(); + StorageFeedWrapper wrapper = new StorageFeedWrapper(feed, + accountName); + modifier.updateFeed(wrapper); + + } catch (Exception e) { + LOG.error("Can't create feed -- " + e.getMessage(), e); + StorageException ex = new StorageException("Can't create feed -- " + + e.getMessage(), e); + ex.setStackTrace(e.getStackTrace()); + throw ex; + + } finally { + if (query == null) + query.decrementRef(); + } + + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#getServiceForFeed(java.lang.String) + */ + public String getServiceForFeed(String feedId) throws StorageException { + if (feedId == null) + throw new StorageException("no feed for the feedID == null"); + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + String type = query.get().getService(feedId); + if (type == null) + throw new StorageException("no feed for the feedID == " + + feedId + " found"); + return type; + } catch (Exception e) { + throw new StorageException("Can not access storage", e); + } finally { + if (query != null) + query.decrementRef(); + } + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#getAccount(java.lang.String) + */ + public GDataAccount getAccount(String accountName) throws StorageException { + if (accountName == null) + throw new StorageException("account name must not be null"); + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + return query.get().getUser(accountName); + } catch (Exception e) { + throw new StorageException("Can not access storage", e); + } finally { + if (query != null) + query.decrementRef(); + } + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#getAccountNameForFeedId(java.lang.String) + */ + public String getAccountNameForFeedId(String feedId) + throws StorageException { + if (feedId == null) + throw new StorageException("feedid must not be null"); + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + String accountName = query.get().getAccountNameForFeedId(feedId); + if (accountName == null) + throw new StorageException("no feed for feedId " + feedId + + " found"); + return accountName; + } catch (IOException e) { + throw new StorageException("Can not access storage - " + + e.getMessage(), e); + } finally { + if (query != null) + query.decrementRef(); + } + + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#getEntryLastModified(java.lang.String, java.lang.String) + */ + public Long getEntryLastModified(String entryId,String feedId) throws StorageException { + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + return new Long(query.get().getEntryLastModified(entryId,feedId)); + } catch (IOException e) { + throw new StorageException("Can not access storage - " + + e.getMessage(), e); + } finally { + if (query != null) + query.decrementRef(); + } + + + } + + /** + * @see org.apache.lucene.gdata.storage.Storage#getFeedLastModified(java.lang.String) + */ + public Long getFeedLastModified(String feedId) throws StorageException { + ReferenceCounter query = null; + try { + query = this.controller.getStorageQuery(); + return new Long(query.get().getFeedLastModified(feedId)); + } catch (IOException e) { + throw new StorageException("Can not access storage - " + + e.getMessage(), e); + } finally { + if (query != null) + query.decrementRef(); + } + + } + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageModifier.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageModifier.java index e447da1502a..d9aa68f4d00 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageModifier.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageModifier.java @@ -1,236 +1,445 @@ -package org.apache.lucene.gdata.storage.lucenestorage; - -import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.lucene.document.Document; -import org.apache.lucene.gdata.storage.StorageException; -import org.apache.lucene.index.IndexModifier; -import org.apache.lucene.index.Term; - -/** - * TODO document this - * @author Simon Willnauer +package org.apache.lucene.gdata.storage.lucenestorage; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.lucene.document.Document; +import org.apache.lucene.gdata.storage.StorageException; +import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation; +import org.apache.lucene.index.IndexModifier; +import org.apache.lucene.index.Term; + +/** + * The StorageModifier is the a Singleton component of the LuceneStorage. There + * is one single instance of this class modifying the index used to store all + * the gdata Entities as Entries, Feeds and Users. This class contains an + * instance of {@link org.apache.lucene.index.IndexModifier} used to manage all + * delete and add actions to the storage. + *

+ * To prevent the storage component from opening and closing the + * {@link org.apache.lucene.index.IndexModifier} for every modifying operation + * the incoming entry actions (DELETE, UPDATE, INSERT) will be buffered in a + * registered instance of + * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer}. When a + * certain amout (specified as the persistfactor in the configuration file) of + * modifications have been executed the StorageModifier will persist the + * buffered entries. + *

+ *

+ * Feed and User operations won't be buffered. These actions occure not very + * often compared to entry actions. Every call of an user / feed modifying + * operation forces all changes to be written to the storage index. + *

* - */ -public class StorageModifier { - protected static final Log LOG = LogFactory.getLog(StorageModifier.class); - - private final List deletedDocumentQueue; - private final List deletedForUpdateDocumentQueue; - - private final Map documentMap; - - - private volatile int persistFactor; - - private volatile int modifiedCounter = 0; - - private static int DEFAULT_PERSIST_FACTOR = 10; - - private StorageBuffer buffer; - - private IndexModifier modifier; - - private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false); - - private Lock readLock = this.lock.readLock(); - - private Lock writeLock = this.lock.writeLock(); - private final static int DEFAULT_OPTIMIZE_INTERVAL = 10; - private final int optimizeInterval; - private int optimizeCounter = 0; - - /** - * TODO document this - * @param modifier - * @param buffer - * @param persitsFactor - * @param optimizeInterval - */ - public StorageModifier(final IndexModifier modifier, - final StorageBuffer buffer, int persitsFactor,int optimizeInterval) { - this.deletedDocumentQueue = new LinkedList(); - this.deletedForUpdateDocumentQueue = new LinkedList(); - this.documentMap = new HashMap(persitsFactor); - this.buffer = buffer; - - this.persistFactor = persitsFactor > 0 ? persitsFactor - : DEFAULT_PERSIST_FACTOR; - this.modifier = modifier; - this.optimizeInterval = optimizeInterval < DEFAULT_OPTIMIZE_INTERVAL?DEFAULT_OPTIMIZE_INTERVAL:optimizeInterval; - - } - - /** - * TODO document this - * @param wrapper - * @throws StorageException - */ - public void updateEntry(StorageEntryWrapper wrapper) - throws StorageException { - try { - this.readLock.lock(); - Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID, wrapper.getEntryId()); - this.buffer.addEntry(wrapper); - this.deletedForUpdateDocumentQueue.add(tempTerm); - this.documentMap.put(wrapper.getEntryId(),wrapper.getLuceneDocument()); - storageModified(); - } finally { - this.readLock.unlock(); - } - } - - /** - * TODO document this - * @param wrapper - * @throws StorageException - */ - public void insertEntry(StorageEntryWrapper wrapper) throws StorageException { - this.readLock.lock(); - try { - - this.buffer.addEntry(wrapper); - this.documentMap.put(wrapper.getEntryId(),wrapper.getLuceneDocument()); - storageModified(); - } finally { - this.readLock.unlock(); - } - } - - /** - *TODO document this - * @param entryId - * @param feedId - * @throws StorageException + * @author Simon Willnauer + * + */ +public class StorageModifier { + protected static final Log LOG = LogFactory.getLog(StorageModifier.class); + + private final List deletedDocumentQueue; + + private final List deletedForUpdateDocumentQueue; + + private final Map documentMap; + + private final List forceWriteDocuments; + + private final List forceWriteTerms; + + private volatile int persistFactor; + + private volatile int modifiedCounter = 0; + + private static int DEFAULT_PERSIST_FACTOR = 10; + + private StorageBuffer buffer; + + private IndexModifier modifier; + + private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false); + + private Lock readLock = this.lock.readLock(); + + private Lock writeLock = this.lock.writeLock(); + + private final static int DEFAULT_OPTIMIZE_INTERVAL = 10; + + private final int optimizeInterval; + + private volatile int optimizeCounter = 0; + + private final StorageCoreController controller; + + /** + * Creates a new StorageModifier * - */ - public void deleteEntry(final String entryId, final String feedId) throws StorageException { - try { - this.readLock.lock(); - Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID, entryId); - this.buffer.addDeleted(entryId, feedId); - this.deletedDocumentQueue.add(tempTerm); - storageModified(); - } finally { - this.readLock.unlock(); - } - } - - private void storageModified() throws StorageException { - this.readLock.unlock(); - this.writeLock.lock(); - - try { - incrementCounter(); - if (this.persistFactor > this.modifiedCounter) - return; - - if (LOG.isInfoEnabled()) - LOG.info("Storage modified for " + this.modifiedCounter - + " times. Write Persistent index"); - writePersistentIndex((this.optimizeCounter >= this.optimizeInterval)); - requestNewIndexModifier(); - - this.modifiedCounter = 0; - } catch (IOException e) { - LOG.error("Writing persistent index failed - Recovering", e); - } finally { - this.readLock.lock(); - this.writeLock.unlock(); - } - - } - - protected void forceWrite() throws IOException, StorageException { - this.writeLock.lock(); - try { - if (LOG.isInfoEnabled()) - LOG.info("ForceWrite called -- current modifiedCounter: " - + this.modifiedCounter + " - persisting changes"); - writePersistentIndex(true); - requestNewIndexModifier(); - this.modifiedCounter = 0; - } finally { - this.writeLock.unlock(); - } - } - - private void requestNewIndexModifier() throws IOException, StorageException { - StorageCoreController controller = StorageCoreController - .getStorageCoreController(); - controller.registerNewStorageQuery(); - this.buffer = controller.releaseNewStorageBuffer(); - this.modifier = controller.createIndexModifier(); - } - - private void writePersistentIndex(final boolean optimize) throws IOException { - try { - /* - * first delete all updated documents - */ - for(Term entryIdTerm : this.deletedForUpdateDocumentQueue) { - this.modifier.deleteDocuments(entryIdTerm); - } - /* - * add all documents - */ - Collection documents = this.documentMap.values(); - for (Document doc : documents) { - this.modifier.addDocument(doc); - } - /* - * delete all documents marked as deleted. As the DocumentIDs are - * unique the document marked as deleted must not persist after the - * index has been written. - * In the case of an update of a document and a previous delete the concurrency component will not allow an update. - * new inserted entries can not be deleted accidently- - */ - for (Term entryIdTerm : this.deletedDocumentQueue) { - this.modifier.deleteDocuments(entryIdTerm); - } - this.modifier.flush(); - if(optimize){ - if(LOG.isInfoEnabled()) - LOG.info("Optimizing index -- optimize interval "+this.optimizeInterval); - this.modifier.optimize(); - } - - } finally { - if(optimize) - this.optimizeCounter = 0; - this.modifier.close(); - this.deletedForUpdateDocumentQueue.clear(); - this.deletedDocumentQueue.clear(); - this.documentMap.clear(); - } - } - - protected void close()throws IOException{ - this.writeLock.lock(); - try { - if (LOG.isInfoEnabled()) - LOG.info("ForceWrite called -- current modifiedCounter: " - + this.modifiedCounter + " - persisting changes"); - - writePersistentIndex(true); - this.modifiedCounter = 0; - } finally { - this.writeLock.unlock(); - } - } - - private void incrementCounter(){ - this.optimizeCounter++; - this.modifiedCounter++; - } - -} + * @param controller - + * the registered StorageController + * @param modifier - + * the IndexModifier + * @param buffer - + * the StorageBuffer + * @param persitsFactor - + * the factor when the changes will be persisted to the storage + * index + * @param optimizeInterval - + * after how many storage operations the index will be optimized + */ + protected StorageModifier(final StorageCoreController controller, + final IndexModifier modifier, final StorageBuffer buffer, + int persitsFactor, int optimizeInterval) { + this.deletedDocumentQueue = new LinkedList(); + this.deletedForUpdateDocumentQueue = new LinkedList(); + this.documentMap = new HashMap(persitsFactor); + this.forceWriteDocuments = new ArrayList(5); + this.forceWriteTerms = new ArrayList(5); + this.buffer = buffer; + this.controller = controller; + + this.persistFactor = persitsFactor > 0 ? persitsFactor + : DEFAULT_PERSIST_FACTOR; + this.modifier = modifier; + this.optimizeInterval = optimizeInterval < DEFAULT_OPTIMIZE_INTERVAL ? DEFAULT_OPTIMIZE_INTERVAL + : optimizeInterval; + + } + + /** + * Updates the given entry. First the alredy persisted entry will be + * removed, after marking as deleted the new Entry will be written. + * + * @param wrapper - + * the wrapper containing the entry + * @throws StorageException - + * if the entry can not be stored + */ + public void updateEntry(StorageEntryWrapper wrapper) + throws StorageException { + if(wrapper.getOperation() != StorageOperation.UPDATE) + throw new StorageException("Illegal method call -- updateEntry does not accept other storageOperations than update"); + this.readLock.lock(); + try { + Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID, + wrapper.getEntryId()); + this.documentMap.put(wrapper.getEntryId(), wrapper + .getLuceneDocument()); + this.deletedForUpdateDocumentQueue.add(tempTerm); + this.buffer.addEntry(wrapper); + storageModified(); + } finally { + this.readLock.unlock(); + } + } + + /** + * Inserts a new Entry to the Lucene index storage + * + * @param wrapper - + * the wrapper containing the entry + * @throws StorageException - + * if the entry can not be stored + */ + public void insertEntry(StorageEntryWrapper wrapper) + throws StorageException { + if(wrapper.getOperation() != StorageOperation.INSERT) + throw new StorageException("Illegal method call -- insertEntry does not accept other storage operations than insert"); + this.readLock.lock(); + try { + this.documentMap.put(wrapper.getEntryId(), wrapper + .getLuceneDocument()); + this.buffer.addEntry(wrapper); + storageModified(); + } finally { + this.readLock.unlock(); + } + } + + /** + * Deletes the entry for the given entry id. + * @param wrapper - the wrapper containing the information to delete + * + * @throws StorageException - + * if the entry can not be deleted + * + */ + public void deleteEntry(final StorageEntryWrapper wrapper) + throws StorageException { + if(wrapper.getOperation() != StorageOperation.DELETE) + throw new StorageException("Illegal method call -- insertEntry does not accept other storage operations than delete"); + this.readLock.lock(); + try { + Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID, + wrapper.getEntryId()); + this.deletedDocumentQueue.add(tempTerm); + this.buffer.addDeleted(wrapper.getEntryId(), wrapper.getFeedId()); + storageModified(); + } finally { + this.readLock.unlock(); + } + } + + /** + * Adds a new Feed to the storage. Feed action will be not buffered. Call to + * this method forces the index to be written. + * + * @param wrapper - + * the wrapper containing the feed; + * @throws StorageException - + * if the feed can not be written + */ + public void createFeed(StorageFeedWrapper wrapper) throws StorageException { + this.readLock.lock(); + try { + this.forceWriteDocuments.add(wrapper.getLuceneDocument()); + storageModified(); + } finally { + this.readLock.unlock(); + } + } + + /** + * Adds a new accountr to the storage. User action will be not buffered. Call to + * this method forces the index to be written. + * + * @param account + * -the wrapper containig the user to be persisted + * @throws StorageException - + * if the user can not be persisted. + */ + public void createAccount(StorageAccountWrapper account) throws StorageException { + this.readLock.lock(); + try { + this.forceWriteDocuments.add(account.getLuceneDocument()); + storageModified(); + } finally { + this.readLock.unlock(); + } + } + + /** + * Deletes the user with the given username. User action will be not + * buffered. Call to this method forces the index to be written. + * + * @param accountName - + * the user to be deleted + * @throws StorageException - + * If the user could not be deleted + */ + public void deleteAccount(String accountName) throws StorageException { + this.readLock.lock(); + try { + //TODO delete all feeds and entries of this account + this.forceWriteTerms.add(new Term( + StorageAccountWrapper.FIELD_ACCOUNTNAME, accountName)); + storageModified(); + } finally { + this.readLock.unlock(); + } + } + + /** + * User action will be not buffered. Call to this method forces the index to + * be written. + * + * @param user + * -the wrapper containig the user to be persisted + * @throws StorageException - + * if the user can not be persisted. + */ + public void updateAccount(final StorageAccountWrapper user) + throws StorageException { + this.readLock.lock(); + try { + this.forceWriteTerms.add(new Term( + StorageAccountWrapper.FIELD_ACCOUNTNAME, user.getUser() + .getName())); + this.forceWriteDocuments.add(user.getLuceneDocument()); + storageModified(); + } finally { + this.readLock.unlock(); + } + } + + /** + * Feed action will be not buffered. Call to this method forces the index to + * be written. + * + * @param wrapper - + * the wrapper containig the feed + * @throws StorageException - + * if the feed can not be persisted + */ + public void updateFeed(final StorageFeedWrapper wrapper) + throws StorageException { + this.readLock.lock(); + try { + this.forceWriteTerms.add(new Term(StorageFeedWrapper.FIELD_FEED_ID, + wrapper.getFeed().getId())); + this.forceWriteDocuments.add(wrapper.getLuceneDocument()); + storageModified(); + } finally { + this.readLock.unlock(); + } + } + + /** + * Deletes the feed with the given feed id Feed action will be not buffered. + * Call to this method forces the index to be written. + * All entries referencing the given feed id will be deleted as well! + * @param feedId - + * the id of the feed to delete + * @throws StorageException - + * if the feed can not be deleted + */ + public void deleteFeed(final String feedId) throws StorageException { + this.readLock.lock(); + try { + this.deletedDocumentQueue.add(new Term(StorageEntryWrapper.FIELD_FEED_REFERENCE,feedId)); + this.forceWriteTerms.add(new Term(StorageFeedWrapper.FIELD_FEED_ID, + feedId)); + + storageModified(); + } finally { + this.readLock.unlock(); + } + } + + private void storageModified() throws StorageException { + this.readLock.unlock(); + this.writeLock.lock(); + + try { + incrementCounter(); + if (this.persistFactor > this.modifiedCounter + && this.forceWriteDocuments.size() <= 0 + && this.forceWriteTerms.size() <= 0) + return; + + if (LOG.isInfoEnabled()) + LOG.info("Storage modified for " + this.modifiedCounter + + " times. Write Persistent index"); + writePersistentIndex((this.optimizeCounter >= this.optimizeInterval)); + requestNewIndexModifier(); + + this.modifiedCounter = 0; + } catch (IOException e) { + + LOG.error("Writing persistent index failed - Recovering", e); + throw new StorageException("could not write to storage index -- "+e.getMessage(),e); + + } finally { + this.readLock.lock(); + this.writeLock.unlock(); + } + + } + + protected void forceWrite() throws IOException { + this.writeLock.lock(); + try { + if (LOG.isInfoEnabled()) + LOG.info("ForceWrite called -- current modifiedCounter: " + + this.modifiedCounter + " - persisting changes"); + writePersistentIndex(true); + requestNewIndexModifier(); + this.modifiedCounter = 0; + } finally { + this.writeLock.unlock(); + } + } + + private void requestNewIndexModifier() throws IOException { + + this.controller.registerNewStorageQuery(); + this.buffer = this.controller.releaseNewStorageBuffer(); + this.modifier = this.controller.createIndexModifier(); + } + + private void writePersistentIndex(final boolean optimize) + throws IOException { + try { + + /* + * first delete all updated documents + */ + for (Term entryIdTerm : this.deletedForUpdateDocumentQueue) { + this.modifier.deleteDocuments(entryIdTerm); + } + + for (Term term : this.forceWriteTerms) { + this.modifier.deleteDocuments(term); + } + /* + * add all documents + */ + Collection documents = this.documentMap.values(); + for (Document doc : documents) { + this.modifier.addDocument(doc); + } + /* + * write all users or feeds + */ + for (Document docs : this.forceWriteDocuments) { + this.modifier.addDocument(docs); + } + + /* + * delete all documents marked as deleted. As the DocumentIDs are + * unique the document marked as deleted must not persist after the + * index has been written. In the case of an update of a document + * and a previous delete the concurrency component will not allow an + * update. new inserted entries can not be deleted accidently- + */ + for (Term entryIdTerm : this.deletedDocumentQueue) { + this.modifier.deleteDocuments(entryIdTerm); + } + this.modifier.flush(); + if (optimize) { + if (LOG.isInfoEnabled()) + LOG.info("Optimizing index -- optimize interval " + + this.optimizeInterval); + this.modifier.optimize(); + } + + } finally { + if (optimize) + this.optimizeCounter = 0; + this.modifier.close(); + this.deletedForUpdateDocumentQueue.clear(); + this.deletedDocumentQueue.clear(); + this.documentMap.clear(); + this.forceWriteDocuments.clear(); + this.forceWriteTerms.clear(); + } + } + + protected void close() throws IOException { + this.writeLock.lock(); + try { + if (LOG.isInfoEnabled()) + LOG.info("ForceWrite called -- current modifiedCounter: " + + this.modifiedCounter + " - persisting changes"); + + writePersistentIndex(true); + this.modifiedCounter = 0; + } finally { + this.writeLock.unlock(); + } + } + + private void incrementCounter() { + this.optimizeCounter++; + this.modifiedCounter++; + } + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageQuery.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageQuery.java index 6dbad349b38..1774c544464 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageQuery.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageQuery.java @@ -12,331 +12,481 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ - -package org.apache.lucene.gdata.storage.lucenestorage; - -import java.io.IOException; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.apache.lucene.document.Document; -import org.apache.lucene.gdata.server.FeedNotFoundException; -import org.apache.lucene.gdata.server.GDataEntityBuilder; -import org.apache.lucene.index.Term; -import org.apache.lucene.search.BooleanClause; -import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.Hit; -import org.apache.lucene.search.Hits; -import org.apache.lucene.search.Searcher; -import org.apache.lucene.search.Sort; -import org.apache.lucene.search.SortField; -import org.apache.lucene.search.TermQuery; -import org.apache.lucene.search.BooleanClause.Occur; - -import com.google.gdata.data.BaseEntry; -import com.google.gdata.data.ExtensionProfile; -import com.google.gdata.util.ParseException; - -/** - * StorageQuery wrapps a Lucene {@link org.apache.lucene.search.IndexSearcher} - * and a {@link org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer} to - * perform all request on the lucene storage. - * The wrapped components are thread - safe. - *

- * An instance of this class will serve all client requests. To obtain the - * current instance of the {@link StorageQuery} the method - * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#getStorageQuery()} - * has to be invoked. This method will release the current StorageQuery. - *

- * @see org.apache.lucene.search.IndexSearcher - * @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController - * @see org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer - * - * @author Simon Willnauer - * - */ -public class StorageQuery { - private final StorageBuffer buffer; - - private final Searcher searcher; - - /* - * Sort the result by timestamp desc - */ - private final Sort timeStampSort = new Sort(new SortField(StorageEntryWrapper.FIELD_TIMESTAMP, - SortField.STRING, true)); - - /** - * Creates a new StorageQuery - * - * @param buffer - - * the buffer instance to get the buffered inserts, updates from. - * @param searcher - - * the searcher instance to use to query the storage index. - * - * - */ - protected StorageQuery(final StorageBuffer buffer, final Searcher searcher) { - - this.buffer = buffer; - this.searcher = searcher; - - } - - private Hits storageQuery(List entryId) throws IOException { - BooleanQuery query = new BooleanQuery(); - /* - * query the index using a BooleanQuery - */ - for (String id : entryId) { - TermQuery termQuery = new TermQuery(new Term( - StorageEntryWrapper.FIELD_ENTRY_ID, id)); - // use an OR query - query.add(new BooleanClause(termQuery, Occur.SHOULD)); - } - - return this.searcher.search(query, new ModifiedEntryFilter(this.buffer - .getExculdList())); - } - - /* - * query the storage index for a entire feed. - */ - private Hits storageFeedQuery(final String feedId, final Sort sort) - throws IOException { - TermQuery query = new TermQuery(new Term(StorageEntryWrapper.FIELD_FEED_ID, feedId)); - return this.searcher.search(query, new ModifiedEntryFilter(this.buffer - .getExculdList()), sort); - - } - - /* - * get a single entry - */ - private Hits storageQuery(String entryId) throws IOException { - TermQuery termQuery = new TermQuery(new Term( - StorageEntryWrapper.FIELD_ENTRY_ID, entryId)); - /* - * Filter entries inside the buffer, buffered entries might contain - * deleted entries. These entries must be found!! - */ - return this.searcher.search(termQuery, new ModifiedEntryFilter( - this.buffer.getExculdList())); - - } - - /** - * This method fetches the latest feed entries from the storage. Feed - * ususaly requested via a search query or as a simple query to the REST - * interface. - *

- * The REST interface requestes all the entries from a Storage. The Storage - * retrieves the entries corresponding to the parameters specified. This - * method first requests the latest entries or updated entries from the - * {@link StorageBuffer}. If the buffer already contains enought entries - * for the the specified result count the entires will be returned. If not, - * the underlaying lucene index will be searcher for all documents of the - * specified feed sorted by storing timestamp desc. - *

- *

- * The entries will be searched in a feed context specified by the given - * feed ID - *

- * - * - * @param feedId - - * the requested feed, this id will be used to retrieve the - * entries. - * @param resultCount - - * how many entries are requested - * @param startIndex - - * the offset of the entriy to start from. - * @param profil - - * the extension profile used to create the entriy instances - * @return - an ordered list of {@link BaseEntry} objects, or an empty list - * if no entries could be found - * @throws IOException - - * if the index could not be queries or the entries could not be - * build - * @throws FeedNotFoundException - - * if the requested feed is not registered - * @throws ParseException - - * if an entry could not be parsed while building it from the - * Lucene Document. - */ - // TODO check input parameter - public List getLatestFeedQuery(final String feedId, - final int resultCount, final int startIndex, - final ExtensionProfile profil) throws IOException, - FeedNotFoundException, ParseException { - List returnList = new ArrayList(resultCount); - List bufferedWrapperList = this.buffer - .getSortedEntries(feedId); - int alreadyAdded = 0; - int offset = startIndex - 1; - if (bufferedWrapperList != null - && bufferedWrapperList.size() >= startIndex) { - - for (; alreadyAdded < resultCount; alreadyAdded++) { - if ((bufferedWrapperList.size() - offset) > 0) { - StorageEntryWrapper wrappedEntry = bufferedWrapperList - .get(offset++); - returnList.add(wrappedEntry.getEntry()); - } else - break; - } - // reset offset - offset = startIndex - 1; - if (alreadyAdded == resultCount) - return returnList; - } else { - /* - * if the buffersize is less than the startindex the buffersize must - * be considered. Sublists would not be a repeatable read part of - * the whole list - */ - if (bufferedWrapperList != null) - offset = startIndex - 1 - bufferedWrapperList.size(); - } - - Hits hits = storageFeedQuery(feedId, this.timeStampSort); - if (hits.length() > 0) { - - for (; (offset < hits.length()) && (alreadyAdded < resultCount); offset++, alreadyAdded++) { - Document doc = hits.doc(offset); - BaseEntry entry = buildEntryFromLuceneDocument(doc, profil); - returnList.add(entry); - } - - } - return returnList; - } - - /** - * This method retrieves a single entry from the storage. If the - * {@link StorageBuffer} does not contain the requested entry the - * underlaying storage index will be searched. - *

- * The Entry will be searched in a feed context specified by the given feed - * ID - *

- * - * @param entryId - - * the entry to fetch - * @param feedId - - * the feedid eg. feed context - * @param profil - - * the extension profile used to create the entriy instances - * @return - the requested {@link BaseEntry} or null if the - * entry can not be found - * @throws IOException - - * if the index could not be queries or the entries could not be - * build - * @throws FeedNotFoundException - - * if the requested feed is not registered - * @throws ParseException - - * if an entry could not be parsed while building it from the - * Lucene Document. - */ - public BaseEntry singleEntryQuery(final String entryId, - final String feedId, final ExtensionProfile profil) - throws IOException, FeedNotFoundException, ParseException { - StorageEntryWrapper wrapper = this.buffer.getEntry(entryId, feedId); - - if (wrapper == null) { - Hits hits = storageQuery(entryId); - if (hits.length() <= 0) - return null; - Document doc = hits.doc(0); - - return buildEntryFromLuceneDocument(doc, profil); - } - return wrapper.getEntry(); - - } - - /** - * Fetches the requested entries from the storage. The given list contains - * entry ids to be looked up in the storage. First the {@link StorageBuffer} - * will be queried for the entry ids. If not all of the entries remain in - * the buffer the underlaying lucene index will be searched. The entries are - * not guaranteed to be in the same order as they are in the given id list. - * Entry ID's not found in the index or the buffer will be omitted. - *

- * The entries will be searched in a feed context specified by the given - * feed ID - *

- * - * @param entryIds - - * the entriy ids to fetch. - * @param feedId - - * the feed id eg. feed context. - * @param profil - - * the extension profile used to create the entry instances. - * @return - the list of entries corresponding to the given entry id list. - * @throws IOException - - * if the index could not be queries or the entries could not be - * build - * @throws FeedNotFoundException - - * if the requested feed is not registered - * @throws ParseException - - * if an entry could not be parsed while building it from the - * Lucene Document. - */ - public List entryQuery(List entryIds, - final String feedId, final ExtensionProfile profil) - throws IOException, FeedNotFoundException, ParseException { - List resultList = new ArrayList(entryIds.size()); - List searchList = new ArrayList(entryIds.size()); - for (String entry : entryIds) { - - StorageEntryWrapper bufferedEntry = this.buffer.getEntry(entry, - feedId); - if (bufferedEntry != null) { - resultList.add(bufferedEntry.getEntry()); - } else - searchList.add(entry); - } - if (searchList.isEmpty()) - return resultList; - - Hits hits = storageQuery(searchList); - Iterator hitIterator = hits.iterator(); - while (hitIterator.hasNext()) { - Hit hit = (Hit) hitIterator.next(); - Document doc = hit.getDocument(); - BaseEntry entry = buildEntryFromLuceneDocument(doc, profil); - resultList.add(entry); - - } - - return resultList; - - } - - private BaseEntry buildEntryFromLuceneDocument(final Document doc, - final ExtensionProfile profil) throws FeedNotFoundException, - ParseException, IOException { - StringReader reader = new StringReader(doc.getField(StorageEntryWrapper.FIELD_CONTENT) - .stringValue()); - return GDataEntityBuilder.buildEntry(doc.getField(StorageEntryWrapper.FIELD_FEED_ID) - .stringValue(), reader, profil); - - } - - /** - * Closes all resources used in the {@link StorageQuery}. The instance can - * not be reused after invoking this method. - * - * @throws IOException - - * if the resouces can not be closed - */ - public void close() throws IOException { - this.searcher.close(); - this.buffer.close(); - } - -} + */ + +package org.apache.lucene.gdata.storage.lucenestorage; + +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.lucene.document.Document; +import org.apache.lucene.gdata.data.GDataAccount; +import org.apache.lucene.gdata.server.GDataEntityBuilder; +import org.apache.lucene.gdata.server.registry.ProvidedService; +import org.apache.lucene.gdata.storage.StorageException; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Hit; +import org.apache.lucene.search.Hits; +import org.apache.lucene.search.Searcher; +import org.apache.lucene.search.Sort; +import org.apache.lucene.search.SortField; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.BooleanClause.Occur; + +import com.google.gdata.data.BaseEntry; +import com.google.gdata.data.BaseFeed; +import com.google.gdata.data.DateTime; +import com.google.gdata.util.ParseException; + +/** + * StorageQuery wrapps a Lucene {@link org.apache.lucene.search.IndexSearcher} + * and a {@link org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer} to + * perform all request on the lucene storage. The wrapped components are thread - + * safe. + *

+ * An instance of this class will serve all client requests. To obtain the + * current instance of the {@link StorageQuery} the method + * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#getStorageQuery()} + * has to be invoked. This method will release the current StorageQuery. + *

+ * + * @see org.apache.lucene.search.IndexSearcher + * @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController + * @see org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer + * + * @author Simon Willnauer + * + */ +public class StorageQuery { + private static final Log LOG = LogFactory.getLog(StorageQuery.class); + private final StorageBuffer buffer; + + private final Searcher searcher; + + /* + * Sort the result by timestamp desc + */ + private final Sort timeStampSort = new Sort(new SortField( + StorageEntryWrapper.FIELD_TIMESTAMP, SortField.STRING, true)); + + /** + * Creates a new StorageQuery + * + * @param buffer - + * the buffer instance to get the buffered inserts, updates from. + * @param searcher - + * the searcher instance to use to query the storage index. + * + * + */ + protected StorageQuery(final StorageBuffer buffer, final Searcher searcher) { + + this.buffer = buffer; + this.searcher = searcher; + + } + + private Hits storageQuery(List entryId) throws IOException { + BooleanQuery query = new BooleanQuery(); + /* + * query the index using a BooleanQuery + */ + for (String id : entryId) { + TermQuery termQuery = new TermQuery(new Term( + StorageEntryWrapper.FIELD_ENTRY_ID, id)); + // use an OR query + query.add(new BooleanClause(termQuery, Occur.SHOULD)); + } + + return this.searcher.search(query, new ModifiedEntryFilter(this.buffer + .getExculdList())); + } + + /* + * query the storage index for a entire feed. + */ + private Hits storageFeedQuery(final String feedId, final Sort sort) + throws IOException { + TermQuery query = new TermQuery(new Term( + StorageEntryWrapper.FIELD_FEED_REFERENCE, feedId)); + return this.searcher.search(query, new ModifiedEntryFilter(this.buffer + .getExculdList()), sort); + + } + + /* + * get a single entry + */ + private Hits storageQuery(String entryId) throws IOException { + TermQuery termQuery = new TermQuery(new Term( + StorageEntryWrapper.FIELD_ENTRY_ID, entryId)); + /* + * Filter entries inside the buffer, buffered entries might contain + * deleted entries. These entries must be found!! + */ + return this.searcher.search(termQuery, new ModifiedEntryFilter( + this.buffer.getExculdList())); + + } + + /** + * This method fetches the latest feed entries from the storage. Feed + * ususaly requested via a search query or as a simple query to the REST + * interface. + *

+ * The REST interface requestes all the entries from a Storage. The Storage + * retrieves the entries corresponding to the parameters specified. This + * method first requests the latest entries or updated entries from the + * {@link StorageBuffer}. If the buffer already contains enought entries + * for the the specified result count the entires will be returned. If not, + * the underlaying lucene index will be searcher for all documents of the + * specified feed sorted by storing timestamp desc. + *

+ *

+ * The entries will be searched in a feed context specified by the given + * feed ID + *

+ * + * + * @param feedId - + * the requested feed, this id will be used to retrieve the + * entries. + * @param resultCount - + * how many entries are requested + * @param startIndex - + * the offset of the entriy to start from. + * @param config - + * the FeedInstanceConfiguration contaning extension profile used + * to create the entriy instances + * @return - an ordered list of {@link BaseEntry} objects, or an empty list + * if no entries could be found + * @throws IOException - + * if the index could not be queries or the entries could not be + * build + * @throws ParseException - + * if an entry could not be parsed while building it from the + * Lucene Document. + */ + // TODO check input parameter + @SuppressWarnings("unchecked") + public BaseFeed getLatestFeedQuery(final String feedId, + final int resultCount, final int startIndex, + final ProvidedService config) throws IOException, + ParseException { + DateTime updated = null; + Hits feedHits = storageFeedQuery(feedId); + if(feedHits.length() == 0) + return null; + BaseFeed retVal = buildFeedFromLuceneDocument(feedHits.doc(0),config); + + List returnList = new ArrayList(resultCount); + List bufferedWrapperList = this.buffer + .getSortedEntries(feedId); + int alreadyAdded = 0; + int offset = startIndex - 1; + + if (bufferedWrapperList != null + && bufferedWrapperList.size() >= startIndex) { + updated = bufferedWrapperList.get(0).getEntry().getUpdated(); + for (; alreadyAdded < resultCount; alreadyAdded++) { + if ((bufferedWrapperList.size() - offset) > 0) { + StorageEntryWrapper wrappedEntry = bufferedWrapperList + .get(offset++); + returnList + .add(wrappedEntry.getEntry()); + } else + break; + } + // reset offset + offset = startIndex - 1; + if (alreadyAdded == resultCount){ + retVal.getEntries().addAll(returnList); + retVal.setUpdated(updated); + return retVal; + } + } else { + /* + * if the buffersize is less than the startindex the buffersize must + * be considered. Sublists would not be a repeatable read part of + * the whole list + */ + if (bufferedWrapperList != null) + offset = startIndex - 1 - bufferedWrapperList.size(); + } + + Hits hits = storageFeedQuery(feedId, this.timeStampSort); + if (hits.length() > 0) { + + for (; (offset < hits.length()) && (alreadyAdded < resultCount); offset++, alreadyAdded++) { + Document doc = hits.doc(offset); + BaseEntry entry = buildEntryFromLuceneDocument(doc, config); + returnList.add(entry); + } + if(updated == null){ + try{ + long updatedTimeStamp = Long.parseLong(hits.doc(0).get(StorageEntryWrapper.FIELD_TIMESTAMP)); + updated = new DateTime(updatedTimeStamp); + }catch (Exception e) { + LOG.warn("could not create DateTime -- "+e.getMessage(),e); + updated = buildEntryFromLuceneDocument(hits.doc(0),config).getUpdated(); + } + } + } + retVal.setUpdated(updated); + retVal.getEntries().addAll(returnList); + return retVal; + } + + /** + * This method retrieves a single entry from the storage. If the + * {@link StorageBuffer} does not contain the requested entry the + * underlaying storage index will be searched. + *

+ * The Entry will be searched in a feed context specified by the given feed + * ID + *

+ * + * @param entryId - + * the entry to fetch + * @param feedId - + * the feedid eg. feed context + * @param config - + * the FeedInstanceConfiguration contaning extension profile used + * to create the entriy instances + * @return - the requested {@link BaseEntry} or null if the + * entry can not be found + * @throws IOException - + * if the index could not be queries or the entries could not be + * build + * @throws ParseException - + * if an entry could not be parsed while building it from the + * Lucene Document. + */ + public BaseEntry singleEntryQuery(final String entryId, + final String feedId, final ProvidedService config) + throws IOException, ParseException { + StorageEntryWrapper wrapper = this.buffer.getEntry(entryId, feedId); + + if (wrapper == null) { + Hits hits = storageQuery(entryId); + if (hits.length() <= 0) + return null; + Document doc = hits.doc(0); + + return buildEntryFromLuceneDocument(doc, config); + } + /* + * ServerBaseEntry enables the dynamic element of the entry like the + * links to be dynamic. BufferedEntries will be reused until they are + * written. + */ + return wrapper.getEntry(); + + } + + /** + * Fetches the requested entries from the storage. The given list contains + * entry ids to be looked up in the storage. First the {@link StorageBuffer} + * will be queried for the entry ids. If not all of the entries remain in + * the buffer the underlaying lucene index will be searched. The entries are + * not guaranteed to be in the same order as they are in the given id list. + * Entry ID's not found in the index or the buffer will be omitted. + *

+ * The entries will be searched in a feed context specified by the given + * feed ID + *

+ * + * @param entryIds - + * the entriy ids to fetch. + * @param feedId - + * the feed id eg. feed context. + * @param config - + * the FeedInstanceConfiguration contaning extension profile used + * to create the entriy instances + * + * @return - the list of entries corresponding to the given entry id list. + * @throws IOException - + * if the index could not be queries or the entries could not be + * build + * @throws ParseException - + * if an entry could not be parsed while building it from the + * Lucene Document. + */ + public List entryQuery(List entryIds, + final String feedId, final ProvidedService config) + throws IOException, ParseException { + List resultList = new ArrayList(entryIds.size()); + List searchList = new ArrayList(entryIds.size()); + for (String entry : entryIds) { + + StorageEntryWrapper bufferedEntry = this.buffer.getEntry(entry, + feedId); + if (bufferedEntry != null) { + resultList.add(bufferedEntry.getEntry()); + } else + searchList.add(entry); + } + if (searchList.isEmpty()) + return resultList; + + Hits hits = storageQuery(searchList); + Iterator hitIterator = hits.iterator(); + while (hitIterator.hasNext()) { + Hit hit = (Hit) hitIterator.next(); + Document doc = hit.getDocument(); + BaseEntry entry = buildEntryFromLuceneDocument(doc, config); + resultList.add(entry); + + } + + return resultList; + + } + + private BaseEntry buildEntryFromLuceneDocument(final Document doc, + final ProvidedService config) throws ParseException, + IOException { + StringReader reader = new StringReader(doc.getField( + StorageEntryWrapper.FIELD_CONTENT).stringValue()); + return GDataEntityBuilder.buildEntry( reader, config); + + } + + private BaseFeed buildFeedFromLuceneDocument(final Document doc, + final ProvidedService config) throws ParseException, + IOException { + StringReader reader = new StringReader(doc.getField( + StorageFeedWrapper.FIELD_CONTENT).stringValue()); + return GDataEntityBuilder + .buildFeed(reader, config); + + } + + /** + * Queries the storage for an user instance + * + * @param username - + * the username (primary key) + * @return - the user instance if found or null if not exists + * @throws IOException - + * if the storage can not be accessed. + */ + public GDataAccount getUser(final String username) throws IOException { + if (username == null) + return null; + TermQuery query = new TermQuery(new Term( + StorageAccountWrapper.FIELD_ACCOUNTNAME, username)); + Hits h = this.searcher.search(query); + if (h.length() == 0) + return null; + return StorageAccountWrapper.buildEntity(h.doc(0)); + } + + /** + * Closes all resources used in the {@link StorageQuery}. The instance can + * not be reused after invoking this method. + * + * @throws IOException - + * if the resouces can not be closed + */ + public void close() throws IOException { + this.searcher.close(); + this.buffer.close(); + } + + /** + * Checks whether a feed for the given feedID is stored + * @param feedId - the feed ID + * @return true if and only if a feed is stored for the provided feed ID, false if no feed for the given id is stored + * @throws IOException + */ + public boolean isFeedStored(String feedId)throws IOException{ + Hits h = storageFeedQuery(feedId); + return (h.length() > 0); + + } + + /** + * Looks up the feedtype for the given feed ID + * @param feedID - the feed ID + * @return - the feed type + * @throws IOException - if the storage can not be accessed + */ + public String getService(String feedID) throws IOException { + Hits hits = storageFeedQuery(feedID); + if (hits.length() <= 0) + return null; + Document doc = hits.doc(0); + String feedType = doc.get(StorageFeedWrapper.FIELD_SERVICE_ID); + return feedType; + } + private Hits storageFeedQuery(String feedId) throws IOException { + TermQuery query = new TermQuery(new Term( + StorageFeedWrapper.FIELD_FEED_ID, feedId)); + return this.searcher.search(query); + } + + /** + * Looks up the account reference for the given feed id + * @param feedId - id of the feed + * @return - the name of the account associated with the feed for the given feed id, or null if the feed is not stored + * @throws IOException - if the storage can not be accessed + */ + public String getAccountNameForFeedId(String feedId) throws IOException { + Hits h = storageFeedQuery(feedId); + if(h.length() == 0) + return null; + Document doc = h.doc(0); + return doc.get(StorageFeedWrapper.FIELD_ACCOUNTREFERENCE); + + } + protected long getEntryLastModified(final String entryId,final String feedId) throws IOException, StorageException{ + StorageEntryWrapper wrapper = this.buffer.getEntry(entryId,feedId); + if(wrapper != null) + return wrapper.getTimestamp(); + + Hits h = storageQuery(entryId); + if(h.length() > 0) + try{ + return Long.parseLong(h.doc(0).get(StorageEntryWrapper.FIELD_TIMESTAMP)); + }catch (Exception e) { + LOG.warn("Can not parse timestamp from entry -- "+h.doc(0).get(StorageEntryWrapper.FIELD_TIMESTAMP)); + } + else + throw new StorageException("Entry not found"); + return 0; + + } + + protected long getFeedLastModified(final String feedId)throws IOException{ + Long bufferedTime = this.buffer.getFeedLastModified(feedId); + if(bufferedTime != null) + return bufferedTime; + Hits entryHits = storageFeedQuery(feedId,this.timeStampSort); + if(entryHits.length() > 0){ + try{ + return Long.parseLong(entryHits.doc(0).getField(StorageEntryWrapper.FIELD_TIMESTAMP).stringValue()); + }catch (Exception e) { + LOG.warn("Can not parse timestamp from entry -- "+entryHits.doc(0).get(StorageEntryWrapper.FIELD_TIMESTAMP)); + } + } + return 0; + + } + protected boolean isEntryStored(String entryId,String feedId) throws IOException{ + if(this.buffer.getEntry(entryId,feedId)!=null) + return true; + + Hits h = storageQuery(entryId); + if(h.length() > 0) + return true; + return false; + } +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/configuration/StorageConfigurator.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/configuration/StorageConfigurator.java index 4f3bd6d2682..838525fbd42 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/configuration/StorageConfigurator.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/configuration/StorageConfigurator.java @@ -37,7 +37,8 @@ public class StorageConfigurator { private final boolean keepRecoveredFiles; private final boolean recover; - + + private final boolean ramDirectory; private static StorageConfigurator INSTANCE = null; private final int indexOptimizeInterval; @@ -64,7 +65,8 @@ public class StorageConfigurator { .getProperty("gdata.server.storage.lucene.directory"); this.indexOptimizeInterval = Integer.parseInt(properties .getProperty("gdata.server.storage.lucene.optimizeInterval")); - + this.ramDirectory = Boolean.parseBoolean(properties + .getProperty("gdata.server.storage.lucene.directory.ramDirectory")); } /** @@ -139,6 +141,13 @@ public class StorageConfigurator { public int getIndexOptimizeInterval() { return this.indexOptimizeInterval; + } + + /** + * @return Returns the ramDirectory. + */ + public boolean isRamDirectory() { + return this.ramDirectory; } } diff --git a/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataRequest.java b/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataRequest.java index 279abc3ce9f..9503211e203 100644 --- a/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataRequest.java +++ b/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataRequest.java @@ -15,18 +15,18 @@ */ package org.apache.lucene.gdata.server; -import javax.servlet.http.HttpServletRequest; - -import junit.framework.TestCase; - -import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; -import org.apache.lucene.gdata.server.GDataRequest.OutputFormat; -import org.apache.lucene.gdata.server.registry.FeedInstanceConfigurator; -import org.apache.lucene.gdata.server.registry.GDataServerRegistry; -import org.easymock.MockControl; - -import com.google.gdata.data.ExtensionProfile; -import com.google.gdata.data.Feed; +import javax.servlet.http.HttpServletRequest; + +import junit.framework.TestCase; + +import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; +import org.apache.lucene.gdata.server.GDataRequest.OutputFormat; +import org.apache.lucene.gdata.server.registry.GDataServerRegistry; +import org.apache.lucene.gdata.server.registry.ProvidedService; +import org.apache.lucene.gdata.server.registry.RegistryException; +import org.apache.lucene.gdata.utils.ProvidedServiceStub; +import org.apache.lucene.gdata.utils.StorageStub; +import org.easymock.MockControl; /** * @@ -39,14 +39,21 @@ public class TestGDataRequest extends TestCase { private MockControl control; private GDataRequest feedRequest; - + static{ + try { + GDataServerRegistry.getRegistry().registerComponent(StorageStub.class); + } catch (RegistryException e) { + + e.printStackTrace(); + } + } + @Override protected void setUp() throws Exception { - FeedInstanceConfigurator configurator = new FeedInstanceConfigurator(); - configurator.setFeedType(Feed.class); - configurator.setFeedId("feed"); - configurator.setExtensionProfileClass(ExtensionProfile.class); - GDataServerRegistry.getRegistry().registerFeed(configurator); + ProvidedService configurator = new ProvidedServiceStub(); + GDataServerRegistry.getRegistry().registerService(configurator); + + this.control = MockControl.createControl(HttpServletRequest.class); this.request = (HttpServletRequest) this.control.getMock(); this.feedRequest = new GDataRequest(this.request,GDataRequestType.GET); @@ -216,7 +223,7 @@ public class TestGDataRequest extends TestCase { public void testGetSelfId() throws GDataRequestException{ String host = "www.apache.org"; String feedAndEntryID = "/feed/entryid"; - String queryString = "?max-results=25"; + String queryString = "max-results=25"; this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host); this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed/entryId/15"); this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15"); @@ -227,13 +234,13 @@ public class TestGDataRequest extends TestCase { queryString); this.control.replay(); this.feedRequest.initializeRequest(); - String selfID = "http://"+host+"/host/feed/entryId/15"+queryString; + String selfID = "http://"+host+"/host/feed/entryId/15?"+queryString; assertEquals("Self ID",selfID,this.feedRequest.getSelfId()); this.control.reset(); - queryString = "?alt=rss&max-results=25"; + queryString = "alt=rss&max-results=25"; this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host); this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed/entryId/15"); this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15"); @@ -244,7 +251,7 @@ public class TestGDataRequest extends TestCase { queryString); this.control.replay(); this.feedRequest.initializeRequest(); - selfID = "http://"+host+"/host/feed/entryId/15"+queryString; + selfID = "http://"+host+"/host/feed/entryId/15?"+queryString; assertEquals("Self ID",selfID,this.feedRequest.getSelfId()); this.control.reset(); @@ -296,7 +303,7 @@ public class TestGDataRequest extends TestCase { queryString); this.control.replay(); - assertEquals("?"+maxResults,this.feedRequest.getQueryString()); + assertEquals(maxResults,this.feedRequest.getQueryString()); this.control.reset(); } @@ -342,8 +349,12 @@ public class TestGDataRequest extends TestCase { } - public void testIsEntryRequest(){ - + public void testgetAuthToken(){ + this.control.expectAndDefaultReturn(this.request.getHeader("Authentication"),"GoogleLogin auth=bla"); + this.control.replay(); + assertEquals("bla",this.feedRequest.getAuthToken()); + this.control.verify(); + } public void testGetNextId() throws GDataRequestException{ @@ -352,7 +363,8 @@ public class TestGDataRequest extends TestCase { // String queryString = "?max-results=25"; // String startIndex = "&start-index=26"; // this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host); -// this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15"); +// this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/feed/"); +// this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/"); // this.control.expectAndReturn(this.request.getParameter("max-results"),"25",2); // this.control.expectAndReturn(this.request.getParameter("start-index"),null); // this.control.expectAndDefaultReturn(this.request.getParameter("alt"), @@ -361,22 +373,27 @@ public class TestGDataRequest extends TestCase { // queryString); // this.control.replay(); // this.feedRequest.initializeRequest(); -// String nextID = "http://"+host+"/feed"+queryString+startIndex; +// String nextID = "http://"+host+"/feed/"+queryString+startIndex; // // assertEquals("Next ID",nextID,this.feedRequest.getNextId()); // this.control.reset(); -// -// + + // queryString = "?alt=rss&max-results=25"; // // this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host); -// this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15"); +// this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/feed/"); +// this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/"); // this.control.expectAndReturn(this.request.getParameter("max-results"),"25",2); // this.control.expectAndReturn(this.request.getParameter("start-index"),"26",2); // this.control.expectAndDefaultReturn(this.request.getParameter("alt"), // null); // this.control.expectAndDefaultReturn(this.request.getQueryString(), // queryString+startIndex); +// Enumeration e = +// this.control.expectAndDefaultReturn(this.request.getParameterNames(),) +// +// // this.control.replay(); // this.feedRequest.initializeRequest(); // startIndex = "&start-index=51"; @@ -395,7 +412,7 @@ public class TestGDataRequest extends TestCase { // null); // this.control.replay(); // this.feedRequest.initializeRequest(); -// selfID = "http://"+host+"/feed"+"?max-results=25"; +// String selfID = "http://"+host+"/feed"+"?max-results=25"; // // assertEquals("Self ID",selfID,this.feedRequest.getSelfId()); // this.control.reset(); diff --git a/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataResponse.java b/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataResponse.java index 5736ee19a7d..e2450eed305 100644 --- a/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataResponse.java +++ b/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/TestGDataResponse.java @@ -70,12 +70,12 @@ public class TestGDataResponse extends TestCase { StringWriter stringWriter = new StringWriter(); PrintWriter writer = new PrintWriter(stringWriter); - this.control.expectAndReturn(this.httpResponse.getWriter(),writer); + this.control.expectAndReturn(this.httpResponse.getWriter(),writer); + this.httpResponse.setContentType(GDataResponse.XMLMIME_ATOM); this.response.setOutputFormat(OutputFormat.ATOM); this.control.replay(); - this.response.sendResponse(createFeed(),new ExtensionProfile - ()); + this.response.sendResponse(createFeed(),new ExtensionProfile()); assertEquals("Simple XML representation",stringWriter.toString(),generatedFeedAtom); this.control.reset(); @@ -84,6 +84,7 @@ public class TestGDataResponse extends TestCase { this.control.expectAndReturn(this.httpResponse.getWriter(),writer); this.response.setOutputFormat(OutputFormat.RSS); + this.httpResponse.setContentType(GDataResponse.XMLMIME_RSS); this.control.replay(); this.response.sendResponse(createFeed(),new ExtensionProfile diff --git a/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestFeedRegistry.java b/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestFeedRegistry.java index 6f639251583..eba4734de82 100644 --- a/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestFeedRegistry.java +++ b/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestFeedRegistry.java @@ -1,98 +1,132 @@ -/** - * Copyright 2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.lucene.gdata.server.registry; - -import com.google.gdata.data.Feed; - -import junit.framework.TestCase; - -/** - * @author Simon Willnauer - * - */ -public class TestFeedRegistry extends TestCase { - private GDataServerRegistry reg; - private FeedInstanceConfigurator configurator; - @Override - protected void setUp(){ - this.reg = GDataServerRegistry.getRegistry(); - this.configurator = new FeedInstanceConfigurator(); - } - /** - * @see junit.framework.TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception { - this.reg.flushRegistry(); - } - /** - * Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getRegistry()' - */ - public void testGetRegistry() { - - GDataServerRegistry reg1 = GDataServerRegistry.getRegistry(); - assertEquals("test singleton",this.reg,reg1); - } - - /** - * Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.registerFeed(FeedInstanceConfigurator)' - */ - public void testRegisterFeed() { - String feedURL = "myFeed"; - registerFeed(feedURL); - assertEquals("Registered Configurator",this.configurator,this.reg.getFeedConfigurator(feedURL)); - assertNull("not registered Configurator",this.reg.getFeedConfigurator("somethingElse")); - try{ - this.reg.getFeedConfigurator(null); - fail("Exception expected"); - }catch (IllegalArgumentException e) { - // - } - } - - /** - * Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getFeedConfigurator(String)' - */ - public void testFlushRegistry() { - String feedURL = "testFeed"; - registerFeed(feedURL); - assertEquals("Registered Configurator",this.configurator,this.reg.getFeedConfigurator(feedURL)); - this.reg.flushRegistry(); - assertNull("Registry flushed",this.reg.getFeedConfigurator(feedURL)); - - - } - - /** - * - */ - public void testIsFeedRegistered(){ - String myFeed = "myFeed"; - registerFeed(myFeed); - assertTrue("Feed is registerd",this.reg.isFeedRegistered(myFeed)); - assertFalse("null Feed is not registerd",this.reg.isFeedRegistered(null)); - assertFalse("Feed is not registerd",this.reg.isFeedRegistered("someOtherFeed")); - - } - - private void registerFeed(String feedURL){ - - this.configurator.setFeedType(Feed.class); - this.configurator.setFeedId(feedURL); - this.reg.registerFeed(this.configurator); - } - -} +/** + * Copyright 2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.lucene.gdata.server.registry; + +import org.apache.lucene.gdata.server.ServiceFactory; +import org.apache.lucene.gdata.servlet.handler.DefaultRequestHandlerFactory; +import org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory; +import org.apache.lucene.gdata.storage.StorageController; +import org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController; + +import com.google.gdata.data.Entry; +import com.google.gdata.data.Feed; + +import junit.framework.TestCase; + +/** + * @author Simon Willnauer + * + */ +public class TestFeedRegistry extends TestCase { + private GDataServerRegistry reg; + private ProvidedServiceConfig configurator; + @Override + protected void setUp(){ + this.reg = GDataServerRegistry.getRegistry(); + this.configurator = new ProvidedServiceConfig(); + this.configurator.setEntryType(Entry.class); + this.configurator.setFeedType(Feed.class); + } + /** + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + this.reg.flushRegistry(); + } + /** + * Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getRegistry()' + */ + public void testGetRegistry() { + + GDataServerRegistry reg1 = GDataServerRegistry.getRegistry(); + assertEquals("test singleton",this.reg,reg1); + } + + /** + * Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.registerFeed(FeedInstanceConfigurator)' + */ + public void testRegisterService() { + String service = "service"; + registerService(service); + assertEquals("Registered Configurator",this.configurator,this.reg.getProvidedService(service)); + assertNull("not registered Configurator",this.reg.getProvidedService("something")); + try{ + this.reg.getProvidedService(null); + fail("Exception expected"); + }catch (IllegalArgumentException e) { + // + } + } + + /** + * Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getFeedConfigurator(String)' + */ + public void testFlushRegistry() { + String service = "service"; + registerService(service); + + assertEquals("Registered Configurator",this.configurator,this.reg.getProvidedService(service)); + this.reg.flushRegistry(); + assertNull("Registry flushed",this.reg.getProvidedService(service)); + + + } + + /** + * + */ + public void testIsFeedRegistered(){ + String service = "service"; + registerService(service); + assertTrue("Feed is registerd",this.reg.isServiceRegistered(service)); + assertFalse("null Feed is not registerd",this.reg.isServiceRegistered(null)); + assertFalse("Feed is not registerd",this.reg.isServiceRegistered("something")); + + } + + private void registerService(String servicename){ + + this.configurator.setName(servicename); + this.reg.registerService(this.configurator); + } + + public void testRegisterComponent() throws RegistryException{ + try { + this.reg.registerComponent(StorageController.class); + fail("RegistryException expected"); + } catch (RegistryException e) { + // + } + this.reg.registerComponent(StorageCoreController.class); + + this.reg.registerComponent(DefaultRequestHandlerFactory.class); + RequestHandlerFactory factory = this.reg.lookup(RequestHandlerFactory.class,ComponentType.REQUESTHANDLERFACTORY); + try{ + this.reg.registerComponent(DefaultRequestHandlerFactory.class); + fail("RegistryException expected"); + } catch (RegistryException e) { + // + } + this.reg.registerComponent(ServiceFactory.class); + ServiceFactory servicefactory = this.reg.lookup(ServiceFactory.class,ComponentType.SERVICEFACTORY); + assertNotNull(servicefactory); + assertNotNull(factory); + + + } + +} diff --git a/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestGDataEntityBuilder.java b/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestGDataEntityBuilder.java index ca308b25b0b..4556b59a596 100644 --- a/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestGDataEntityBuilder.java +++ b/contrib/gdata-server/src/test/org/apache/lucene/gdata/server/registry/TestGDataEntityBuilder.java @@ -15,22 +15,24 @@ */ package org.apache.lucene.gdata.server.registry; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.Reader; - -import junit.framework.TestCase; - -import org.apache.lucene.gdata.server.FeedNotFoundException; -import org.apache.lucene.gdata.server.GDataEntityBuilder; - -import com.google.gdata.data.BaseEntry; -import com.google.gdata.data.BaseFeed; -import com.google.gdata.data.Entry; -import com.google.gdata.data.ExtensionProfile; -import com.google.gdata.data.Feed; -import com.google.gdata.util.ParseException; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; + +import junit.framework.TestCase; + +import org.apache.lucene.gdata.data.ServerBaseEntry; +import org.apache.lucene.gdata.data.ServerBaseFeed; +import org.apache.lucene.gdata.server.GDataEntityBuilder; + +import com.google.gdata.data.BaseEntry; +import com.google.gdata.data.BaseFeed; +import com.google.gdata.data.Entry; +import com.google.gdata.data.ExtensionProfile; +import com.google.gdata.data.Feed; +import com.google.gdata.data.Source; +import com.google.gdata.util.ParseException; /** * @author Simon Willnauer @@ -44,8 +46,9 @@ public class TestGDataEntityBuilder extends TestCase { private static GDataServerRegistry reg = GDataServerRegistry.getRegistry(); private Reader reader; private static String feedID = "myFeed"; - private ExtensionProfile profile; + private ProvidedServiceConfig config; private static Class feedType = Feed.class; + private static Class entryType = Entry.class; /** @@ -53,11 +56,12 @@ public class TestGDataEntityBuilder extends TestCase { */ @Override protected void setUp() throws Exception { - FeedInstanceConfigurator config = new FeedInstanceConfigurator(); - config.setFeedId(feedID); - config.setFeedType(feedType); - this.profile = new ExtensionProfile(); - reg.registerFeed(config); + this.config = new ProvidedServiceConfig(); + + this.config.setFeedType(feedType); + this.config.setEntryType(entryType); + this.config.setExtensionProfile(new ExtensionProfile()); + reg.registerService(this.config); } /** @@ -72,24 +76,27 @@ public class TestGDataEntityBuilder extends TestCase { /** * Test method for 'org.apache.lucene.gdata.data.GDataEntityBuilder.buildFeed(String, Reader)' */ - public void testBuildFeedStringReader() throws FeedNotFoundException, ParseException, IOException { + public void testBuildFeedStringReader() throws ParseException, IOException { this.reader = new FileReader(incomingFeed); - BaseFeed feed = GDataEntityBuilder.buildFeed(feedID,this.reader,this.profile); + BaseFeed feed = GDataEntityBuilder.buildFeed(this.reader,this.config); assertNotNull(feed); - assertEquals("feed title",feed.getTitle().getPlainText(), feedTitleFromXML); - assertTrue( feed instanceof Feed); + assertEquals("feed title",feed.getTitle().getPlainText(), feedTitleFromXML); + + } - /* + /** * Test method for 'org.apache.lucene.gdata.data.GDataEntityBuilder.buildEntry(String, Reader)' */ - public void testBuildEntryStringReader() throws FeedNotFoundException, ParseException, IOException { + public void testBuildEntryStringReader() throws ParseException, IOException { this.reader = new FileReader(incomingEntry); - BaseEntry entry = GDataEntityBuilder.buildEntry(feedID,this.reader,this.profile); + BaseEntry entry = GDataEntityBuilder.buildEntry(this.reader,this.config); assertNotNull(entry); assertEquals("entry summary",entry.getSummary().getPlainText(),entrySummaryFromXML); - assertTrue(entry instanceof Entry); + + + } diff --git a/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageModifier.java b/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageModifier.java index 455d8e11d44..eff4d6146f5 100644 --- a/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageModifier.java +++ b/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageModifier.java @@ -1,247 +1,387 @@ -package org.apache.lucene.gdata.storage.lucenestorage; - -import java.io.IOException; -import java.util.Date; - -import junit.framework.TestCase; - -import org.apache.lucene.analysis.standard.StandardAnalyzer; -import org.apache.lucene.gdata.server.FeedNotFoundException; -import org.apache.lucene.gdata.server.registry.FeedInstanceConfigurator; -import org.apache.lucene.gdata.server.registry.GDataServerRegistry; -import org.apache.lucene.gdata.server.registry.RegistryBuilder; -import org.apache.lucene.gdata.storage.StorageException; -import org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController; -import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper; -import org.apache.lucene.gdata.storage.lucenestorage.StorageModifier; -import org.apache.lucene.gdata.storage.lucenestorage.StorageQuery; -import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation; -import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter; -import org.apache.lucene.index.IndexWriter; -import org.apache.lucene.index.Term; -import org.apache.lucene.search.Hits; -import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.TermQuery; -import org.apache.lucene.store.Directory; -import org.apache.lucene.store.RAMDirectory; - -import com.google.gdata.data.BaseEntry; -import com.google.gdata.data.DateTime; -import com.google.gdata.data.Entry; -import com.google.gdata.data.ExtensionProfile; -import com.google.gdata.data.Feed; -import com.google.gdata.data.PlainTextConstruct; -import com.google.gdata.data.TextConstruct; -import com.google.gdata.data.TextContent; -import com.google.gdata.util.ParseException; - -public class TestStorageModifier extends TestCase { - private StorageModifier modifier; - private int count = 1; +package org.apache.lucene.gdata.storage.lucenestorage; + +import java.io.IOException; + +import junit.framework.TestCase; + +import org.apache.lucene.gdata.data.GDataAccount; +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.server.registry.ProvidedService; +import org.apache.lucene.gdata.storage.StorageController; +import org.apache.lucene.gdata.storage.StorageException; +import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation; +import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter; +import org.apache.lucene.gdata.utils.ProvidedServiceStub; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Hits; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.store.Directory; + +import com.google.gdata.data.BaseEntry; +import com.google.gdata.data.DateTime; +import com.google.gdata.data.Entry; +import com.google.gdata.data.PlainTextConstruct; +import com.google.gdata.data.TextContent; +import com.google.gdata.util.ParseException; + +public class TestStorageModifier extends TestCase { + private StorageModifier modifier; + + private int count = 1; + + private ProvidedService configurator; + + private Directory dir; + + private StorageCoreController controller; + + private static String feedId = "myFeed"; + + private static String username = "simon"; + + private static String password = "test"; + private static String service = "myService"; + + protected void setUp() throws Exception { + GDataServerRegistry.getRegistry().registerComponent( + StorageCoreController.class); + this.configurator = new ProvidedServiceStub(); + GDataServerRegistry.getRegistry().registerService(this.configurator); + this.controller = (StorageCoreController) GDataServerRegistry + .getRegistry().lookup(StorageController.class, + ComponentType.STORAGECONTROLLER); + this.modifier = this.controller.getStorageModifier(); + this.dir = this.controller.getDirectory(); + + } + + protected void tearDown() throws Exception { + this.count = 1; + // destroy all resources + GDataServerRegistry.getRegistry().destroy();// TODO remove dependency + // here + + } + + /* + * Test method for + * 'org.apache.lucene.storage.lucenestorage.StorageModifier.updateEntry(StroageEntryWrapper)' + */ + public void testUpdateEntry() throws IOException, InterruptedException, + ParseException, StorageException { + testInsertEntry(); + for (int i = 1; i < this.count; i++) { + Entry e = new Entry(); + e.setId("" + i); + String insertString = "Hello world" + i; + e.setTitle(new PlainTextConstruct(insertString)); + ServerBaseEntry en = getServerEntry(e); + StorageEntryWrapper wrapper = new StorageEntryWrapper(en, + StorageOperation.UPDATE); + this.modifier.updateEntry(wrapper); + ReferenceCounter innerQuery = this.controller + .getStorageQuery(); + BaseEntry fetchedEntry = innerQuery.get().singleEntryQuery("" + i, + feedId, this.configurator); + assertEquals("updated Title:", insertString, fetchedEntry + .getTitle().getPlainText()); + } + // double updates + for (int i = 1; i < this.count; i++) { + Entry e = new Entry(); + e.setId("" + i); + String insertString = "Hello world" + i; + e.setTitle(new PlainTextConstruct(insertString)); + ServerBaseEntry en = getServerEntry(e); + StorageEntryWrapper wrapper = new StorageEntryWrapper(en, + StorageOperation.UPDATE); + this.modifier.updateEntry(wrapper); + + e = new Entry(); + e.setId("" + i); + insertString = "Foo Bar" + i; + e.setTitle(new PlainTextConstruct(insertString)); + en = getServerEntry(e); + wrapper = new StorageEntryWrapper(en, + StorageOperation.UPDATE); + this.modifier.updateEntry(wrapper); + + ReferenceCounter innerQuery = this.controller + .getStorageQuery(); + + BaseEntry fetchedEntry = innerQuery.get().singleEntryQuery("" + i, + feedId, this.configurator); + assertEquals("updated Title:", insertString, fetchedEntry + .getTitle().getPlainText()); + } + + } + + /* + * Test method for + * 'org.apache.lucene.storage.lucenestorage.StorageModifier.insertEntry(StroageEntryWrapper)' + */ + public void testInsertEntry() throws IOException, InterruptedException, + ParseException, StorageException { + + Thread a = getRunnerThread(this.count); + a.start(); + + Thread b = getRunnerThread((this.count += 10)); + b.start(); + a.join(); + for (int i = 1; i < this.count; i++) { + ReferenceCounter innerQuery = this.controller + .getStorageQuery(); + BaseEntry e = innerQuery.get().singleEntryQuery("" + i, feedId, + this.configurator); + assertEquals("get entry for id" + i, "" + i, e.getId()); + + } + b.join(); + ReferenceCounter query = this.controller + .getStorageQuery(); + + this.count += 10; + for (int i = 1; i < this.count; i++) { + BaseEntry e = query.get().singleEntryQuery("" + i, feedId, + this.configurator); + assertEquals("get entry for id" + i, "" + i, e.getId()); + } + + BaseEntry e = query.get().singleEntryQuery("" + this.count, feedId, + this.configurator); + assertNull("not entry for ID", e); + query.decrementRef(); + + } + + /* + * Test method for + * 'org.apache.lucene.storage.lucenestorage.StorageModifier.deleteEntry(String)' + */ + public void testDeleteEntry() throws IOException, InterruptedException, + ParseException, StorageException { + testInsertEntry(); + for (int i = 1; i < this.count; i++) { + if (i % 2 == 0 || i < 10) { + ServerBaseEntry entry = new ServerBaseEntry(); + entry.setId("" + i); + entry.setFeedId(feedId); + this.modifier.deleteEntry(new StorageEntryWrapper(entry,StorageOperation.DELETE)); + } + ReferenceCounter query = this.controller + .getStorageQuery(); + if (i % 2 == 0 || i < 10) { + assertNull(query.get().singleEntryQuery("" + i, feedId, + this.configurator)); + } else + assertEquals("" + i, query.get().singleEntryQuery("" + i, + feedId, this.configurator).getId()); + query.decrementRef(); + } + + this.controller.forceWrite(); + IndexSearcher searcher = new IndexSearcher(this.dir); + + for (int i = 1; i < this.count; i++) { + Query luceneQuery = new TermQuery(new Term( + StorageEntryWrapper.FIELD_ENTRY_ID, "" + i)); + Hits hits = searcher.search(luceneQuery); + if (i % 2 == 0 || i < 10) { + + assertEquals(0, hits.length()); + } else + assertEquals(1, hits.length()); + } + searcher.close(); + + } + + public void testSaveUser() throws StorageException, IOException { + + GDataAccount user = new GDataAccount(); + user.setName(username); + user.setPassword(password); + StorageAccountWrapper wrapper = new StorageAccountWrapper(user); + this.modifier.createAccount(wrapper); + IndexSearcher searcher = new IndexSearcher(this.dir); + Query q = new TermQuery(new Term(StorageAccountWrapper.FIELD_ACCOUNTNAME, + username)); + Hits h = searcher.search(q); + assertEquals("length == 1", 1, h.length()); + GDataAccount storedUser = StorageAccountWrapper.buildEntity(h.doc(0)); + assertTrue(storedUser.equals(user)); + searcher.close(); + } + + public void testDeleteUser() throws StorageException, IOException { + testSaveUser(); + this.modifier.deleteAccount(username); + IndexSearcher searcher = new IndexSearcher(this.dir); + Query q = new TermQuery(new Term(StorageAccountWrapper.FIELD_ACCOUNTNAME, + username)); + Hits h = searcher.search(q); + assertEquals("length == 0", 0, h.length()); + searcher.close(); + } + + public void testUpdateUser() throws StorageException, IOException { + testSaveUser(); + GDataAccount user = new GDataAccount(); + user.setName(username); + user.setPassword("newPass"); + StorageAccountWrapper wrapper = new StorageAccountWrapper(user); + this.modifier.updateAccount(wrapper); + IndexSearcher searcher = new IndexSearcher(this.dir); + Query q = new TermQuery(new Term(StorageAccountWrapper.FIELD_ACCOUNTNAME, + username)); + Hits h = searcher.search(q); + assertEquals("length == 1", 1, h.length()); + GDataAccount storedUser = StorageAccountWrapper.buildEntity(h.doc(0)); + assertTrue(storedUser.equals(user)); + + assertFalse(storedUser.getPassword().equals(password)); + searcher.close(); + } + + public void testSaveFeed() throws IOException, StorageException { + String title = "myTitle"; + ServerBaseFeed feed = new ServerBaseFeed(); + feed.setId(feedId); + feed.setTitle(new PlainTextConstruct(title)); + feed.setServiceType(service); + feed.setServiceConfig(this.configurator); + StorageFeedWrapper wrapper = new StorageFeedWrapper(feed,username); + this.modifier.createFeed(wrapper); + + IndexSearcher searcher = new IndexSearcher(this.dir); + Query q = new TermQuery(new Term(StorageFeedWrapper.FIELD_FEED_ID, + feedId)); + Hits h = searcher.search(q); + assertEquals("length == 1", 1, h.length()); + searcher.close(); + + } + + public void testDeleteFeed() throws IOException, StorageException { + testSaveFeed(); + Entry e = new Entry(); + e.setTitle(new PlainTextConstruct("hello world")); + ServerBaseEntry entry = new ServerBaseEntry(e); + entry.setFeedId(feedId); + entry.setId("testme"); + entry.setServiceConfig(this.configurator); + StorageEntryWrapper entryWrapper = new StorageEntryWrapper(entry,StorageOperation.INSERT); + this.modifier.insertEntry(entryWrapper); + this.modifier.forceWrite(); + this.modifier.deleteFeed(feedId); + IndexSearcher searcher = new IndexSearcher(this.dir); + Query q = new TermQuery(new Term(StorageFeedWrapper.FIELD_FEED_ID, + feedId)); + Query q1 = new TermQuery(new Term(StorageEntryWrapper.FIELD_FEED_REFERENCE, + feedId)); + BooleanQuery boolQuery = new BooleanQuery(); + boolQuery.add(q,BooleanClause.Occur.SHOULD); + boolQuery.add(q1,BooleanClause.Occur.SHOULD); + Hits h = searcher.search(boolQuery); + assertEquals("length == 0", 0, h.length()); + searcher.close(); + + + + } + + /** + * @throws IOException + * @throws StorageException + */ + public void testUpdateFeed() throws IOException, StorageException { + testSaveFeed(); + ServerBaseFeed feed = new ServerBaseFeed(); + String title = "myTitle"; + String newusername = "doug"; + feed.setTitle(new PlainTextConstruct(title)); + feed.setId(feedId); + feed.setServiceType(service); + feed.setServiceConfig(this.configurator); + StorageFeedWrapper wrapper = new StorageFeedWrapper(feed,newusername); + this.modifier.updateFeed(wrapper); + IndexSearcher searcher = new IndexSearcher(this.dir); + Query q = new TermQuery(new Term(StorageFeedWrapper.FIELD_FEED_ID, + feedId)); + Hits h = searcher.search(q); + assertEquals("length == 1", 1, h.length()); + assertTrue(h.doc(0).get(StorageFeedWrapper.FIELD_ACCOUNTREFERENCE).equals(newusername)); + searcher.close(); + + } + + private Thread getRunnerThread(int idIndex) { + Thread t = new Thread(new Runner(idIndex)); + return t; + } + + private class Runner implements Runnable { + private int idIndex; + + public Runner(int idIndex) { + this.idIndex = idIndex; + } + + public void run() { + for (int i = idIndex; i < idIndex + 10; i++) { + + BaseEntry e = buildEntry("" + i); + try { + ServerBaseEntry en = new ServerBaseEntry(e); + en.setFeedId(feedId); + en.setServiceConfig(configurator); + StorageEntryWrapper wrapper = new StorageEntryWrapper(en, + StorageOperation.INSERT); + modifier.insertEntry(wrapper); + } catch (Exception e1) { + + e1.printStackTrace(); + } + + } + + }// end run + + private BaseEntry buildEntry(String id) { + Entry e = new Entry(); + e.setId(id); + e.setTitle(new PlainTextConstruct("Monty Python")); + + e.setPublished(DateTime.now()); + + e.setUpdated(DateTime.now()); + String content = "1st soldier with a keen interest in birds: Who goes there?" + + "King Arthur: It is I, Arthur, son of Uther Pendragon, from the castle of Camelot. King of the Britons, defeater of the Saxons, Sovereign of all England!" + + "1st soldier with a keen interest in birds: Pull the other one!" + + "King Arthur: I am, and this is my trusty servant Patsy. We have ridden the length and breadth of the land in search of knights who will join me in my court at Camelot. I must speak with your lord and master." + + "1st soldier with a keen interest in birds: What? Ridden on a horse?" + + "King Arthur: Yes!"; + e.setContent(new TextContent(new PlainTextConstruct(content))); + e.setSummary(new PlainTextConstruct("The Holy Grail")); + return e; + } + + } - private ExtensionProfile profile; - private Directory dir; - - - private static String feedId = "myFeed"; - - protected void setUp() throws Exception { - FeedInstanceConfigurator configurator = new FeedInstanceConfigurator(); - configurator.setFeedType(Feed.class); - configurator.setFeedId(feedId); - configurator.setExtensionProfileClass(ExtensionProfile.class); - GDataServerRegistry.getRegistry().registerFeed(configurator); - dir = new RAMDirectory(); - this.profile = new ExtensionProfile(); - IndexWriter writer; - - writer = new IndexWriter(dir,new StandardAnalyzer(),true); - writer.close(); - modifier = StorageCoreController.getStorageCoreController(dir).getStorageModifier(); - - - } - - protected void tearDown() throws Exception { - this.count = 1; - // destroy all resources - GDataServerRegistry.getRegistry().destroy();//TODO remove dependency here - - } - - /* - * Test method for - * 'org.apache.lucene.storage.lucenestorage.StorageModifier.StorageModifier(Directory, - * int)' - */ - public void testStorageModifier() { - - } - - /* - * Test method for - * 'org.apache.lucene.storage.lucenestorage.StorageModifier.updateEntry(StroageEntryWrapper)' - */ - public void testUpdateEntry() throws IOException, InterruptedException, FeedNotFoundException, ParseException, StorageException { - testInsertEntry(); - for(int i = 1; i < this.count; i++){ - Entry e = new Entry(); - e.setId(""+i); - String insertString = "Hello world"+i; - e.setTitle(new PlainTextConstruct(insertString)); - StorageEntryWrapper wrapper = new StorageEntryWrapper(e,feedId,StorageOperation.UPDATE,this.profile); - this.modifier.updateEntry(wrapper); - ReferenceCounter innerQuery = StorageCoreController.getStorageCoreController().getStorageQuery(); - BaseEntry fetchedEntry = innerQuery.get().singleEntryQuery(""+i,feedId,this.profile); - assertEquals("updated Title:",insertString,fetchedEntry.getTitle().getPlainText()); - } - // double updates - for(int i = 1; i < this.count; i++){ - Entry e = new Entry(); - e.setId(""+i); - String insertString = "Hello world"+i; - e.setTitle(new PlainTextConstruct(insertString)); - StorageEntryWrapper wrapper = new StorageEntryWrapper(e,feedId,StorageOperation.UPDATE,this.profile); - this.modifier.updateEntry(wrapper); - - e = new Entry(); - e.setId(""+i); - insertString = "Foo Bar"+i; - e.setTitle(new PlainTextConstruct(insertString)); - wrapper = new StorageEntryWrapper(e,feedId,StorageOperation.UPDATE,this.profile); - this.modifier.updateEntry(wrapper); - - ReferenceCounter innerQuery = StorageCoreController.getStorageCoreController().getStorageQuery(); - - BaseEntry fetchedEntry = innerQuery.get().singleEntryQuery(""+i,feedId,this.profile); - assertEquals("updated Title:",insertString,fetchedEntry.getTitle().getPlainText()); - } - - - - } - - /* - * Test method for - * 'org.apache.lucene.storage.lucenestorage.StorageModifier.insertEntry(StroageEntryWrapper)' - */ - public void testInsertEntry() throws IOException, InterruptedException, FeedNotFoundException, ParseException, StorageException { - - Thread a = getRunnerThread(this.count); - a.start(); - - Thread b = getRunnerThread((this.count+=10)); - b.start(); - a.join(); - for (int i = 1; i < this.count ; i++) { - ReferenceCounter innerQuery = StorageCoreController.getStorageCoreController().getStorageQuery(); - BaseEntry e = innerQuery.get().singleEntryQuery(""+i,feedId,this.profile); - assertEquals("get entry for id"+i,""+i,e.getId()); - - - } - b.join(); - ReferenceCounter query = StorageCoreController.getStorageCoreController().getStorageQuery(); - - this.count+=10; - for (int i = 1; i < this.count ; i++) { - BaseEntry e = query.get().singleEntryQuery(""+i,feedId,this.profile); - assertEquals("get entry for id"+i,""+i,e.getId()); - } - - BaseEntry e = query.get().singleEntryQuery(""+this.count,feedId,this.profile); - assertNull("not entry for ID",e); - query.decrementRef(); - - } - - /* - * Test method for - * 'org.apache.lucene.storage.lucenestorage.StorageModifier.deleteEntry(String)' - */ - public void testDeleteEntry() throws IOException, InterruptedException, FeedNotFoundException, ParseException, StorageException { - testInsertEntry(); - for (int i = 1; i < this.count ; i++) { - if(i%2 == 0 || i< 10){ - this.modifier.deleteEntry(""+i,feedId); - } - ReferenceCounter query = StorageCoreController.getStorageCoreController().getStorageQuery(); - if(i%2 == 0 || i< 10){ - assertNull(query.get().singleEntryQuery(""+i,feedId,this.profile)); - } - else - assertEquals(""+i,query.get().singleEntryQuery(""+i,feedId,this.profile).getId()); - query.decrementRef(); - } - - StorageCoreController.getStorageCoreController().forceWrite(); - IndexSearcher searcher = new IndexSearcher(this.dir); - - for (int i = 1; i < this.count ; i++) { - Query luceneQuery = new TermQuery(new Term(StorageEntryWrapper.FIELD_ENTRY_ID,""+i)); - Hits hits = searcher.search(luceneQuery); - if(i%2 == 0 || i< 10){ - - assertEquals(0,hits.length()); - } - else - assertEquals(1,hits.length()); - } - searcher.close(); - - } - - - private Thread getRunnerThread(int idIndex){ - Thread t = new Thread(new Runner(idIndex)); - return t; - } - - private class Runner implements Runnable{ - private int idIndex; - public Runner(int idIndex){ - this.idIndex = idIndex; - } - public void run() { - for (int i = idIndex; i < idIndex+10; i++) { - - BaseEntry e = buildEntry(""+i); - try { - StorageEntryWrapper wrapper = new StorageEntryWrapper(e,feedId,StorageOperation.INSERT,new ExtensionProfile()); - modifier.insertEntry(wrapper); - } catch (Exception e1) { - - e1.printStackTrace(); - } - - - - - } - - - }//end run - - private BaseEntry buildEntry(String id){ - Entry e = new Entry(); - e.setId(id); - e.setTitle(new PlainTextConstruct("Monty Python")); - - e.setPublished(DateTime.now()); - - e.setUpdated(DateTime.now()); - String content = "1st soldier with a keen interest in birds: Who goes there?" + - "King Arthur: It is I, Arthur, son of Uther Pendragon, from the castle of Camelot. King of the Britons, defeater of the Saxons, Sovereign of all England!" + - "1st soldier with a keen interest in birds: Pull the other one!" + - "King Arthur: I am, and this is my trusty servant Patsy. We have ridden the length and breadth of the land in search of knights who will join me in my court at Camelot. I must speak with your lord and master." + - "1st soldier with a keen interest in birds: What? Ridden on a horse?" + - "King Arthur: Yes!"; - e.setContent(new TextContent(new PlainTextConstruct(content))); - e.setSummary(new PlainTextConstruct("The Holy Grail")); - return e; - } - - } - -} + private ServerBaseEntry getServerEntry(BaseEntry e){ + ServerBaseEntry en = new ServerBaseEntry(e); + en.setFeedId(feedId); + en.setServiceConfig(this.configurator); + return en; + } + +} diff --git a/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageQuery.java b/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageQuery.java index cdc4d8594ce..fbf9f447a13 100644 --- a/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageQuery.java +++ b/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageQuery.java @@ -1,175 +1,266 @@ -package org.apache.lucene.gdata.storage.lucenestorage; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import junit.framework.TestCase; - -import org.apache.lucene.analysis.standard.StandardAnalyzer; -import org.apache.lucene.gdata.server.FeedNotFoundException; -import org.apache.lucene.gdata.server.registry.FeedInstanceConfigurator; -import org.apache.lucene.gdata.server.registry.GDataServerRegistry; -import org.apache.lucene.gdata.server.registry.RegistryBuilder; -import org.apache.lucene.gdata.storage.StorageException; -import org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController; -import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper; -import org.apache.lucene.gdata.storage.lucenestorage.StorageModifier; -import org.apache.lucene.gdata.storage.lucenestorage.StorageQuery; -import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation; -import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter; -import org.apache.lucene.index.IndexWriter; -import org.apache.lucene.store.Directory; -import org.apache.lucene.store.RAMDirectory; - -import com.google.gdata.data.BaseEntry; -import com.google.gdata.data.DateTime; -import com.google.gdata.data.Entry; -import com.google.gdata.data.ExtensionProfile; -import com.google.gdata.data.Feed; -import com.google.gdata.util.ParseException; - -public class TestStorageQuery extends TestCase { - private StorageModifier modifier; - private int count = 30; - private ReferenceCounter query; - private ExtensionProfile profile; - - private Directory dir; - private static String feedId = "myFeed"; - protected void setUp() throws Exception { - FeedInstanceConfigurator configurator = new FeedInstanceConfigurator(); - configurator.setFeedType(Feed.class); - configurator.setFeedId(feedId); - configurator.setExtensionProfileClass(ExtensionProfile.class); - GDataServerRegistry.getRegistry().registerFeed(configurator); - this.profile = new ExtensionProfile(); - this.dir = new RAMDirectory(); - IndexWriter writer; - writer = new IndexWriter(this.dir,new StandardAnalyzer(),true); - writer.close(); - this.modifier = StorageCoreController.getStorageCoreController(this.dir).getStorageModifier(); - insertEntries(this.count); - this.query = StorageCoreController.getStorageCoreController().getStorageQuery(); +package org.apache.lucene.gdata.storage.lucenestorage; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.lucene.gdata.data.GDataAccount; +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.server.registry.ProvidedService; +import org.apache.lucene.gdata.storage.StorageController; +import org.apache.lucene.gdata.storage.StorageException; +import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation; +import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter; +import org.apache.lucene.gdata.utils.ProvidedServiceStub; +import org.apache.lucene.store.Directory; + +import com.google.gdata.data.BaseEntry; +import com.google.gdata.data.BaseFeed; +import com.google.gdata.data.DateTime; +import com.google.gdata.data.Entry; +import com.google.gdata.util.ParseException; + +public class TestStorageQuery extends TestCase { + private StorageModifier modifier; + private int count = 30; + private ReferenceCounter query; + private ProvidedService configurator; + private StorageCoreController controller; + private Directory dir; + private static String feedId = "myFeed"; + private static String accountName = "simon"; + private static String service = ProvidedServiceStub.SERVICE_NAME; + protected void setUp() throws Exception { + GDataServerRegistry.getRegistry().registerComponent(StorageCoreController.class); + this.configurator = new ProvidedServiceStub(); + + + GDataServerRegistry.getRegistry().registerService(this.configurator); + this.controller = (StorageCoreController)GDataServerRegistry.getRegistry().lookup(StorageController.class,ComponentType.STORAGECONTROLLER); + this.modifier = this.controller.getStorageModifier(); + this.dir = this.controller.getDirectory(); + ServerBaseFeed feed = new ServerBaseFeed(); + feed.setId(feedId); + feed.setServiceType(service); + feed.setServiceConfig(this.configurator); + + StorageFeedWrapper wrapper = new StorageFeedWrapper(feed,accountName); + this.modifier.createFeed(wrapper); + insertEntries(this.count); + this.query = this.controller.getStorageQuery(); + - - - } - - - public void insertEntries(int count) throws IOException,InterruptedException, StorageException{ - List tempList = new ArrayList(); - for (int i = 0; i <= count ; i++) { - Entry entry = new Entry(); - entry.setId(""+i); - - entry.setUpdated(new DateTime(System.currentTimeMillis(),0)); - StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,feedId,StorageOperation.INSERT,this.profile); - tempList.add(i,wrapper); + + + } + + + /** + * @param entrycount + * @throws IOException + * @throws InterruptedException + * @throws StorageException + */ + public void insertEntries(int entrycount) throws IOException,InterruptedException, StorageException{ + List tempList = new ArrayList(); + for (int i = 0; i <= entrycount ; i++) { + ServerBaseEntry entry = new ServerBaseEntry(new Entry()); + entry.setId(""+i); + entry.setServiceConfig(this.configurator); + entry.setUpdated(new DateTime(System.currentTimeMillis(),0)); + entry.setFeedId(feedId); + StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,StorageOperation.INSERT); + tempList.add(i,wrapper); + + // force different timestamps --> DateTime 2006-06-05T13:37:55.724Z + Thread.sleep(10); + + } + for (StorageEntryWrapper entry : tempList) { + this.modifier.insertEntry(entry); + } + + + + + } + + protected void tearDown() throws Exception { + this.query.decrementRef(); + GDataServerRegistry.getRegistry().destroy(); + } + + /* + * + */ + public void testAccountNameQuery() throws IOException, StorageException{ + ReferenceCounter query = this.controller.getStorageQuery(); + assertEquals(accountName,query.get().getAccountNameForFeedId(feedId)); + assertNull(query.get().getAccountNameForFeedId("someId")); + } + + /* + * Test method for 'org.apache.lucene.storage.lucenestorage.StorageQuery.feedQuery(String, int, int)' + */ + public void testFeedQuery() throws IOException, ParseException, StorageException { + feedQueryHelper(this.query); + this.controller.forceWrite(); + ReferenceCounter queryAssureWritten = this.controller.getStorageQuery(); + + assertNotSame(queryAssureWritten,this.query); + feedQueryHelper(queryAssureWritten); + queryAssureWritten.decrementRef(); + } + private void feedQueryHelper(ReferenceCounter currentQuery) throws IOException, ParseException{ + BaseFeed feed = currentQuery.get().getLatestFeedQuery(feedId,25,1,this.configurator); + List entryList = feed.getEntries(); + assertTrue("listSize: "+entryList.size(),entryList.size() == 25); + + BaseEntry tempEntry = null; + for (BaseEntry entry : entryList) { + + assertNotNull("entry",entry); + if(tempEntry != null){ + assertTrue(tempEntry.getUpdated().compareTo(entry.getUpdated())>=0) ; + tempEntry = entry; + }else + tempEntry = entry; - // force different timestamps --> DateTime 2006-06-05T13:37:55.724Z - Thread.sleep(50); - - } - for (StorageEntryWrapper entry : tempList) { - this.modifier.insertEntry(entry); - } - - - - - } - - protected void tearDown() throws Exception { - this.query.decrementRef(); - GDataServerRegistry.getRegistry().destroy();//TODO remove dependency here - } - - /* - * Test method for 'org.apache.lucene.storage.lucenestorage.StorageQuery.feedQuery(String, int, int)' - */ - public void testFeedQuery() throws IOException, FeedNotFoundException, ParseException, StorageException { - FeedQueryHelper(this.query); - StorageCoreController.getStorageCoreController().forceWrite(); - ReferenceCounter queryAssureWritten = StorageCoreController.getStorageCoreController().getStorageQuery(); + } + // test sub retrieve sublist + int offset = 15; + int resultCount = 5; + feed = currentQuery.get().getLatestFeedQuery(feedId,resultCount,offset,this.configurator); + List entrySubList = feed.getEntries(); - assertNotSame(queryAssureWritten,this.query); - FeedQueryHelper(queryAssureWritten); - queryAssureWritten.decrementRef(); - } - private void FeedQueryHelper(ReferenceCounter currentQuery) throws IOException, FeedNotFoundException, ParseException{ - List entryList = currentQuery.get().getLatestFeedQuery(feedId,25,1,this.profile); - - assertTrue("listSize: "+entryList.size(),entryList.size() == 25); - - BaseEntry tempEntry = null; - for (BaseEntry entry : entryList) { - - assertNotNull("entry",entry); - if(tempEntry != null){ - assertTrue(tempEntry.getUpdated().compareTo(entry.getUpdated())>=0) ; - tempEntry = entry; - }else - tempEntry = entry; - - } - // test sub retrieve sublist - int offset = 15; - int resultCount = 5; - List entrySubList = currentQuery.get().getLatestFeedQuery(feedId,resultCount,offset,this.profile); - - assertTrue("listSize: "+entrySubList.size(),entrySubList.size() == resultCount); - offset--; - for (BaseEntry entry : entrySubList) { - - assertEquals(entry.getId(),entryList.get(offset).getId()); - offset++; - - } - - - - } - - /* - * Test method for 'org.apache.lucene.storage.lucenestorage.StorageQuery.singleEntryQuery(String, String)' - */ - public void testSingleEntryQuery() throws FeedNotFoundException, ParseException, IOException { - for (int i = 1; i <= this.count; i++) { - BaseEntry entry = this.query.get().singleEntryQuery(""+i,feedId,this.profile); - assertEquals(""+i,entry.getId()); - } - - } - - /* - * Test method for 'org.apache.lucene.storage.lucenestorage.StorageQuery.entryQuery(List, String)' - */ - public void testEntryQuery() throws FeedNotFoundException, ParseException, IOException, StorageException { - entryQueryHelper(this.query); - StorageCoreController.getStorageCoreController().forceWrite(); - ReferenceCounter queryAssureWritten = StorageCoreController.getStorageCoreController().getStorageQuery(); + assertTrue("listSize: "+entrySubList.size(),entrySubList.size() == resultCount); + offset--; + for (BaseEntry entry : entrySubList) { + + assertEquals(entry.getId(),entryList.get(offset).getId()); + offset++; + + } - assertNotSame(queryAssureWritten,query); - entryQueryHelper(queryAssureWritten); - queryAssureWritten.decrementRef(); - } + + + } + + /* + * Test method for 'org.apache.lucene.storage.lucenestorage.StorageQuery.singleEntryQuery(String, String)' + */ + public void testSingleEntryQuery() throws ParseException, IOException { + for (int i = 1; i <= this.count; i++) { + BaseEntry entry = this.query.get().singleEntryQuery(""+i,feedId,this.configurator); + assertEquals(""+i,entry.getId()); + } + + } + + /* + * Test method for 'org.apache.lucene.storage.lucenestorage.StorageQuery.entryQuery(List, String)' + */ + public void testEntryQuery() throws ParseException, IOException, StorageException { + entryQueryHelper(this.query); + this.controller.forceWrite(); + ReferenceCounter queryAssureWritten = this.controller.getStorageQuery(); + + assertNotSame(queryAssureWritten,query); + entryQueryHelper(queryAssureWritten); + queryAssureWritten.decrementRef(); + } + public void testGetUser() throws StorageException, IOException{ + this.modifier.forceWrite(); + GDataAccount user = new GDataAccount(); + user.setName("simon"); + user.setPassword("pass"); + user.setAuthorname("simon willnauer"); + user.setAuthorMail("simon@apache.org"); + user.setAuthorLink(new URL("http://www.apache.org")); + + - - private void entryQueryHelper(ReferenceCounter currentQuery) throws IOException, FeedNotFoundException, ParseException{ - - List entryIdList = new ArrayList(); - for (int i = 1; i <= this.count; i++) { - entryIdList.add(""+i); - } - List entryList = currentQuery.get().entryQuery(entryIdList,feedId,this.profile); - assertEquals(entryIdList.size(),entryList.size()); - List entryIdCompare = new ArrayList(); - for (BaseEntry entry : entryList) { - entryIdCompare.add(entry.getId()); - } - assertTrue(entryIdList.containsAll(entryIdCompare)); - - } - -} + this.modifier.createAccount(new StorageAccountWrapper(user)); + GDataAccount queriedUser = this.query.get().getUser("simon"); + assertNull(queriedUser); + ReferenceCounter tempQuery = this.controller.getStorageQuery(); + queriedUser = tempQuery.get().getUser("simon"); + assertTrue(queriedUser.equals(user)); + assertTrue(queriedUser.getAuthorMail().equals(user.getAuthorMail())); + assertTrue(queriedUser.getAuthorLink().equals(user.getAuthorLink())); + assertTrue(queriedUser.getAuthorname().equals(user.getAuthorname())); + assertTrue(queriedUser.getPassword().equals(user.getPassword())); + } + + public void testIsEntryStored() throws IOException{ + + assertTrue(this.query.get().isEntryStored(""+(this.count-1),feedId)); + assertFalse(this.query.get().isEntryStored("someOther",feedId)); + this.modifier.forceWrite(); + assertTrue(this.query.get().isEntryStored(""+(this.count-1),feedId)); + this.query = this.controller.getStorageQuery(); + assertTrue(this.query.get().isEntryStored(""+(this.count-1),feedId)); + assertFalse(this.query.get().isEntryStored("someOther",feedId)); + } + + public void testGetEntryLastModied() throws IOException, StorageException{ + ServerBaseEntry entry = new ServerBaseEntry(new Entry()); + entry.setId("test"); + entry.setServiceConfig(this.configurator); + entry.setUpdated(new DateTime(System.currentTimeMillis(),0)); + entry.setFeedId(feedId); + StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,StorageOperation.INSERT); + + this.modifier.insertEntry(wrapper); + assertEquals(entry.getUpdated().getValue(),this.query.get().getEntryLastModified("test",feedId)); + this.modifier.forceWrite(); + assertEquals(entry.getUpdated().getValue(),this.query.get().getEntryLastModified("test",feedId)); + this.query = this.controller.getStorageQuery(); + assertEquals(entry.getUpdated().getValue(),this.query.get().getEntryLastModified("test",feedId)); + try{ + this.query.get().getEntryLastModified("some",feedId); + fail("exception expected"); + }catch (Exception e) { + e.printStackTrace(); + } + } + + public void testGetFeedLastModified() throws StorageException, IOException{ + ServerBaseEntry entry = new ServerBaseEntry(new Entry()); + entry.setId("test"); + entry.setServiceConfig(this.configurator); + entry.setUpdated(new DateTime(System.currentTimeMillis(),0)); + entry.setFeedId(feedId); + StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,StorageOperation.INSERT); + this.modifier.insertEntry(wrapper); + assertEquals(entry.getUpdated().getValue(),this.query.get().getFeedLastModified(feedId)); + this.modifier.forceWrite(); + assertEquals(entry.getUpdated().getValue(),this.query.get().getFeedLastModified(feedId)); + this.query = this.controller.getStorageQuery(); + assertEquals(entry.getUpdated().getValue(),this.query.get().getFeedLastModified(feedId)); + } + private void entryQueryHelper(ReferenceCounter currentQuery) throws IOException, ParseException{ + + List entryIdList = new ArrayList(); + for (int i = 1; i <= this.count; i++) { + entryIdList.add(""+i); + } + List entryList = currentQuery.get().entryQuery(entryIdList,feedId,this.configurator); + assertEquals(entryIdList.size(),entryList.size()); + List entryIdCompare = new ArrayList(); + for (BaseEntry entry : entryList) { + entryIdCompare.add(entry.getId()); + } + assertTrue(entryIdList.containsAll(entryIdCompare)); + + } + + + +} diff --git a/contrib/gdata-server/webroot/WEB-INF/web.xml b/contrib/gdata-server/webroot/WEB-INF/web.xml index cb9f5fbe0ee..f5282f52ac0 100644 --- a/contrib/gdata-server/webroot/WEB-INF/web.xml +++ b/contrib/gdata-server/webroot/WEB-INF/web.xml @@ -1,24 +1,57 @@ - - - Lucene GData - Server - - Server-side implementation of the GData protocol based on Apache - - Lucene - - - org.apache.lucene.gdata.server.registry.RegistryContextListener - - - ControllerServlet - - org.apache.lucene.gdata.servlet.RequestControllerServlet - - - - ControllerServlet - /* - - \ No newline at end of file + + + Lucene GData - Server + + Server-side implementation of the GData protocol based on Apache + - Lucene + + + + org.apache.lucene.gdata.server.registry.RegistryContextListener + + + + ControllerServlet + + org.apache.lucene.gdata.servlet.RequestControllerServlet + + + + ControllerServlet + /* + + + AuthenticationServlet + + org.apache.lucene.gdata.servlet.AuthenticationServlet + + + + AuthenticationServlet + /accounts/ClientLogin + + + FeedAdminServlet + + org.apache.lucene.gdata.servlet.FeedAdministrationServlet + + + + FeedAdminServlet + /admin/feed + + + AccountAdminServlet + + org.apache.lucene.gdata.servlet.AccountAdministrationServlet + + + + AccountAdminServlet + /admin/account + + + \ No newline at end of file