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
This commit is contained in:
Yonik Seeley 2006-06-26 18:14:53 +00:00
parent 6e86efb527
commit 4707eea96c
45 changed files with 6168 additions and 4386 deletions

View File

@ -16,7 +16,11 @@
<pathelement location="lib/gdata-client-1.0.jar" /> <pathelement location="lib/gdata-client-1.0.jar" />
<pathelement location="lib/commons-logging-1.1.jar" /> <pathelement location="lib/commons-logging-1.1.jar" />
<pathelement location="lib/commons-jxpath-1.2.jar" /> <pathelement location="lib/commons-jxpath-1.2.jar" />
<pathelement location="lib/je.jar" /> <pathelement location="lib/commons-digester-1.7.jar" />
<pathelement location="lib/commons-beanutils.jar" />
<pathelement location="lib/commons-collections-3.2.jar" />
</path> </path>
@ -36,15 +40,19 @@
<target name="war-gdata" depends="prepare-dist"> <target name="war-gdata" depends="prepare-dist">
<echo>Distributing GData War </echo> <echo>Distributing GData War </echo>
<war destfile="${dist.dir}/${gdata.war.name}.war" <war destfile="${dist.dir}/${gdata.war.name}.war"
webxml="webroot/WEB-INF/web.xml"> webxml="webroot/WEB-INF/web.xml" >
<metainf dir="webroot/meta-inf"/>
<fileset dir="webroot" excludes="WEB-INF/web.xml"/> <fileset dir="webroot" excludes="WEB-INF/web.xml"/>
<lib dir="${gdata.lib.dir}" includes="commons-logging-1.1.jar"/> <lib dir="${gdata.lib.dir}" includes="commons-logging-1.1.jar"/>
<lib dir="${gdata.lib.dir}" includes="gdata-client-1.0.jar"/> <lib dir="${gdata.lib.dir}" includes="gdata-client-1.0.jar"/>
<lib dir="${gdata.lib.dir}" includes="commons-digester-1.7.jar" />
<lib dir="${gdata.lib.dir}" includes="commons-beanutils.jar" />
<lib dir="${gdata.lib.dir}" includes="commons-collections-3.2.jar" />
<lib dir="${build.dir}" includes="${final.name}.jar"/> <lib dir="${build.dir}" includes="${final.name}.jar"/>
<lib file="${lucene.jar}" /> <lib file="${lucene.jar}" />
</war> </war>
</target> </target>
</project> </project>

View File

@ -0,0 +1,2 @@
AnyObjectId[b1b89c9c921f16af22a88db3ff28975a8e40d886] was removed in git history.
Apache SVN contains full history.

View File

@ -0,0 +1,2 @@
AnyObjectId[75580be255065727b20b41c2d338b14792bb35cd] was removed in git history.
Apache SVN contains full history.

View File

@ -0,0 +1,2 @@
AnyObjectId[1783dbea232ced6db122268f8faa5ce773c7ea42] was removed in git history.
Apache SVN contains full history.

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Lucene Storage Properties</comment>
<entry key="gdata.server.storage.lucene.buffersize">20</entry>
<entry key="gdata.server.storage.lucene.optimizeInterval">20</entry>
<entry key="gdata.server.storage.lucene.persistFactor">20</entry>
<entry key="gdata.server.storage.lucene.directory">/tmp/storage/</entry>
<entry key="gdata.server.storage.lucene.recover">true</entry>
<entry key="gdata.server.storage.lucene.recover.keepFiles">false</entry>
</properties>

View File

@ -12,160 +12,160 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.lucene.gdata.server; package org.apache.lucene.gdata.server;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import org.apache.lucene.gdata.server.registry.DataBuilderException; import org.apache.lucene.gdata.server.registry.ProvidedService;
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.BaseEntry; import com.google.gdata.util.ParseException;
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
* {@link com.google.gdata.data.BaseFeed}, * of a storage.
* {@link com.google.gdata.data.BaseEntry} instances have to be build from a * <p>
* {@link java.io.Reader} instance as they come in from a client request or out * To provide a generic builder class the {@link GDataEntityBuilder} requests
* of a storage. * the type of the feed / entry and the corresponding
* <p> * {@link com.google.gdata.data.ExtensionProfile} form the global
* To provide a generic builder class the {@link GDataEntityBuilder} requests * {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry} and
* the type of the feed / entry and the corresponding * builds the instances from the provided reader.
* {@link com.google.gdata.data.ExtensionProfile} form the global * </p>
* {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry} and builds the * <p>
* instances from the provided reader. * This build will not returne the abstract base classes.
* </p> * </p>
* *
* @author Simon Willnauer * @author Simon Willnauer
* *
*/ */
public class GDataEntityBuilder { 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
* Builds a {@link BaseFeed} instance from the {@link Reader} provided by * the {@link GDataRequest}
* the {@link GDataRequest} *
* * @param request -
* @param request - * the request to build the instance from
* the request to build the instance from * @return - a BaseFeed instance
* @return - a BaseFeed instance *
* @throws FeedNotFoundException - * @throws IOException -
* if the feed is not registered * if an I/O Exception occures on the provided reader
* @throws IOException - * @throws ParseException -
* if an I/O Exception occures on the provided reader * if the feed could not be parsed
* @throws ParseException - */
* if the feed could not be parsed public static BaseFeed buildFeed(final GDataRequest request)
*/ throws IOException, ParseException {
public static BaseFeed buildFeed(final GDataRequest request) if (request == null)
throws FeedNotFoundException, IOException, ParseException { throw new IllegalArgumentException("request must not be null");
if (request == null) ProvidedService config = request.getConfigurator();
throw new IllegalArgumentException("request must not be null"); return buildFeed(request.getReader(), config);
return buildFeed(request.getFeedId(), request.getReader(),request.getExtensionProfile()); }
}
/**
/** * Builds a {@link BaseFeed} from the provided {@link Reader}
* Builds a {@link BaseFeed} from the provided {@link Reader} *
* *
* @param feedId - * @param reader -
* the feed ID to request the feed type from the registry * the reader to build the feed from
* @param reader - * @param config -
* the reader to build the feed from * the feed instance config containing the extension profile to
* @param profile - extension profile to parse the resource * parse the resource
* @return - a BaseFeed instance * @return - a BaseFeed instance
* @throws FeedNotFoundException - *
* if the feed is not registered * @throws IOException -
* @throws IOException - * if an I/O Exception occures on the provided reader
* if an I/O Exception occures on the provided reader * @throws ParseException -
* @throws ParseException - * if the feed could not be parsed
* if the feed could not be parsed */
*/ public static BaseFeed buildFeed(final Reader reader,
public static BaseFeed buildFeed(final String feedId, final Reader reader,final ExtensionProfile profile) final ProvidedService config) throws ParseException, IOException {
throws FeedNotFoundException, ParseException, IOException {
BaseFeed retVal = null;
BaseFeed retVal = null; retVal = createEntityInstance(config);
try { retVal.parseAtom(config.getExtensionProfile(), reader);
retVal = (BaseFeed) createEntityInstance(feedId);
} catch (FeedNotFoundException e) { return retVal;
throw e; }
} catch (Exception e) {
DataBuilderException ex = new DataBuilderException( /**
"Could not build Feed for Feed class ", e); * Builds a {@link BaseEntry} instance from the {@link Reader} provided by
ex.setStackTrace(e.getStackTrace()); * the {@link GDataRequest}
throw ex; *
} * @param request -
retVal.parseAtom(profile, reader); * the request to build the instance from
* @return - a BaseEntry instance
return retVal; *
} * @throws IOException -
* if an I/O Exception occures on the provided reader
/** * @throws ParseException -
* Builds a {@link BaseEntry} instance from the {@link Reader} provided by * if the entry could not be parsed
* the {@link GDataRequest} */
* public static BaseEntry buildEntry(final GDataRequest request)
* @param request - throws IOException, ParseException {
* the request to build the instance from if (request == null)
* @return - a BaseEntry instance throw new IllegalArgumentException("request must not be null");
* @throws FeedNotFoundException - ProvidedService config = request.getConfigurator();
* if the feed, requested by the client is not registered return buildEntry(request.getReader(), config);
* @throws IOException - }
* if an I/O Exception occures on the provided reader
* @throws ParseException - /**
* if the entry could not be parsed * Builds a {@link BaseFeed} instance from the {@link Reader} provided by
*/ * the {@link GDataRequest}
public static BaseEntry buildEntry(final GDataRequest request) *
throws FeedNotFoundException, IOException, ParseException { * @param reader -
if (request == null) * the reader to build the feed from
throw new IllegalArgumentException("request must not be null"); * @param config -
return buildEntry(request.getFeedId(), request.getReader(),request.getExtensionProfile()); * the instance config containing the extension profile to parse
} * the resource
* @return - a BaseFeed instance
/** *
* Builds a {@link BaseFeed} instance from the {@link Reader} provided by * @throws IOException -
* the {@link GDataRequest} * if an I/O Exception occures on the provided reader
* @param feedId - * @throws ParseException -
* the feed ID to request the feed type from the registry * if the entry could not be parsed
* @param reader - */
* the reader to build the feed from public static BaseEntry buildEntry(final Reader reader,
* @param profile - extension profile to parse the resource final ProvidedService config) throws ParseException, IOException {
* @return - a BaseFeed instance
* @throws FeedNotFoundException - BaseEntry e = createEntityInstance(config).createEntry();
* if the feed is not registered e.parseAtom(config.getExtensionProfile(), reader);
* @throws IOException - return e;
* if an I/O Exception occures on the provided reader }
* @throws ParseException -
* if the entry could not be parsed private static BaseFeed createEntityInstance(
*/ final ProvidedService config) {
public static BaseEntry buildEntry(final String feedId, final Reader reader,final ExtensionProfile profile) if(config.getFeedType() == null)
throws FeedNotFoundException, ParseException, IOException { throw new IllegalArgumentException("feedtype is null in ProvidedService");
BaseEntry retVal = null; BaseFeed retVal = null;
try { try {
retVal = ((BaseFeed) createEntityInstance(feedId)).createEntry(); retVal = (BaseFeed) config.getFeedType().newInstance();
} catch (FeedNotFoundException e) { } catch (Exception e) {
throw e; throw new EntityBuilderException("Can't instanciate Feed for feedType "+config.getFeedType().getName(),e);
} catch (Exception e) { }
DataBuilderException ex = new DataBuilderException( return retVal;
"Could not build Entry for Entry class ", e); }
ex.setStackTrace(e.getStackTrace()); static class EntityBuilderException extends RuntimeException{
throw ex;
} /**
retVal.parseAtom(new ExtensionProfile(), reader); *
return retVal; */
} private static final long serialVersionUID = 7224011324202237951L;
private static Object createEntityInstance(String feedId) EntityBuilderException(String arg0) {
throws FeedNotFoundException, InstantiationException, super(arg0);
IllegalAccessException {
FeedInstanceConfigurator config = REGISTRY.getFeedConfigurator(feedId); }
if (config == null)
throw new FeedNotFoundException( EntityBuilderException(String arg0, Throwable arg1) {
"No feed for requested feed ID found - " + feedId); super(arg0, arg1);
Class feedClass = config.getFeedType();
return feedClass.newInstance(); }
}
}
} }

View File

@ -12,431 +12,526 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.lucene.gdata.server; package org.apache.lucene.gdata.server;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Map; import java.util.Map;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import javax.servlet.http.HttpServletRequest; 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.commons.logging.Log;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry; import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.server.authentication.AuthenticationController;
import com.google.gdata.data.ExtensionProfile; import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.ProvidedService;
/** import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
* The GDataRequest Class wraps the incoming HttpServletRequest. Needed import org.apache.lucene.gdata.storage.Storage;
* information coming with the HttpServletRequest can be accessed directly. It import org.apache.lucene.gdata.storage.StorageController;
* 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. * The GDataRequest Class wraps the incoming HttpServletRequest. Needed
* <p> * information coming with the HttpServletRequest can be accessed directly. It
* GDataRequest instances will be passed to any action requested by the client. * represents an abstraction on the plain HttpServletRequest. Every GData
* This class also holds the logic to retrieve important information like * specific data coming from the client will be availiable and can be accessed
* response format, the reqeusted feed instance and query parameters. * via the GDataRequest.
* * <p>
* </p> * GDataRequest instances will be passed to any action requested by the client.
* * This class also holds the logic to retrieve important information like
* @author Simon Willnauer * response format, the reqeusted feed instance and query parameters.
* *
*/ * </p>
/* this class might be extracted as an interface in later development */ *
public class GDataRequest { * @author Simon Willnauer
*
private static final Log LOG = LogFactory.getLog(GDataRequest.class); */
/* this class might be extracted as an interface in later development */
private static final String RESPONSE_FORMAT_PARAMETER = "alt"; public class GDataRequest {
private static final String RESPONSE_FORMAT_PARAMETER_RSS = "rss"; private static final Log LOG = LogFactory.getLog(GDataRequest.class);
private static final int DEFAULT_ITEMS_PER_PAGE = 25; private static final String RESPONSE_FORMAT_PARAMETER = "alt";
private static final int DEFAULT_START_INDEX = 1; private static final String RESPONSE_FORMAT_PARAMETER_RSS = "rss";
private static final String START_INDEX_NEXT_PAGE_PARAMETER = "start-index"; private static final int DEFAULT_ITEMS_PER_PAGE = 25;
private static final String ITEMS_PER_PAGE_PARAMETER = "max-results"; private static final int DEFAULT_START_INDEX = 1;
private String contextPath; private static final String START_INDEX_NEXT_PAGE_PARAMETER = "start-index";
@SuppressWarnings("unused") private static final String ITEMS_PER_PAGE_PARAMETER = "max-results";
private static final String RESPONSE_FORMAT_PARAMETER_ATOM = "atom";
private String contextPath;
// Atom is the default resopnse format
private OutputFormat responseFormat = OutputFormat.ATOM; @SuppressWarnings("unused")
private static final String RESPONSE_FORMAT_PARAMETER_ATOM = "atom";
private final HttpServletRequest request;
private static final String HTTP_HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
private String feedId = null;
private static final String HTTP_HEADER_AUTH = "Authorization";
private String entryId = null;
// Atom is the default resopnse format
private ExtensionProfile extensionProfile= null; private OutputFormat responseFormat = OutputFormat.ATOM;
private String entryVersion = null; private final HttpServletRequest request;
private GDataRequestType type; private String feedId = null;
/** private String entryId = null;
* Creates a new FeedRequest
* private ProvidedService configurator = null;
* @param requst -
* the incoming HttpServletReqeust private String entryVersion = null;
* @param type -
* the request type private GDataRequestType type;
*
*/ /**
public GDataRequest(final HttpServletRequest requst, * Creates a new FeedRequest
final GDataRequestType type) { *
if (requst == null) * @param requst -
throw new IllegalArgumentException("request must not be null "); * the incoming HttpServletReqeust
if (type == null) * @param type -
throw new IllegalArgumentException("request type must not be null "); * the request type
this.request = requst; *
this.type = type; */
public GDataRequest(final HttpServletRequest requst,
} final GDataRequestType type) {
if (requst == null)
/** throw new IllegalArgumentException("request must not be null ");
* Initialize the GDataRequest. This will initialize all needed values / if (type == null)
* attributes in this request. throw new IllegalArgumentException("request type must not be null ");
* this.request = requst;
* @throws GDataRequestException this.type = type;
*/
public void initializeRequest() throws GDataRequestException { }
generateIdentificationProperties();
setOutputFormat(); /**
/* * Initialize the GDataRequest. This will initialize all needed values /
* ExtensionProfile is used for building the Entry / Feed Instances from an inputstream or reader * attributes in this request.
*/ *
this.extensionProfile = GDataServerRegistry.getRegistry().getExtensionProfile(this.feedId); * @throws GDataRequestException
if(this.extensionProfile == null) */
throw new GDataRequestException("feed is not registered or extension profile could not be created"); public void initializeRequest() throws GDataRequestException {
} generateIdentificationProperties();
setOutputFormat();
/** // TODO remove this dependency
* @return - the id of the requested feed StorageController controller = GDataServerRegistry.getRegistry()
*/ .lookup(StorageController.class,
public String getFeedId() { ComponentType.STORAGECONTROLLER);
try {
return this.feedId;
} Storage storage = controller.getStorage();
/** String service = storage.getServiceForFeed(this.feedId);
* @return - the entry id of the requested Entry if specified, otherwise /*
* <code>null</code> * ExtensionProfile and the type is used for building the Entry /
*/ * Feed Instances from an inputstream or reader
public String getEntryId() { *
*/
return this.entryId; this.configurator = GDataServerRegistry.getRegistry()
} .getProvidedService(service);
if (this.configurator == null)
/** throw new GDataRequestException(
* @return the version Id of the requested Entry if specified, otherwise "feed is not registered or extension profile could not be created");
* <code>null</code>
*/ } catch (Exception e) {
public String getEntryVersion() { throw new GDataRequestException(
return this.entryVersion; "feed is not registered or extension profile could not be created");
} }
/** }
* A Reader instance to read form the client input stream
* /**
* @return - the HttpServletRequest {@link Reader} * @return - the id of the requested feed
* @throws IOException - */
* if an I/O Exception occures public String getFeedId() {
*/
public Reader getReader() throws IOException { return this.feedId;
return this.request.getReader(); }
}
/**
/** * @return - the entry id of the requested Entry if specified, otherwise
* Returns the {@link HttpServletRequest} parameter map containig all <i>GET</i> * <code>null</code>
* request parameters. */
* public String getEntryId() {
* @return the parameter map
*/ return this.entryId;
@SuppressWarnings("unchecked") }
public Map<String, String[]> getQueryParameter() {
return this.request.getParameterMap(); /**
} * @return the version Id of the requested Entry if specified, otherwise
* <code>null</code>
/** */
* The {@link HttpServletRequest} request parameter names public String getEntryVersion() {
* return this.entryVersion;
* @return parameter names enumeration }
*/
@SuppressWarnings("unchecked") /**
public Enumeration<String> getQueryParameterNames() { * A Reader instance to read form the client input stream
return this.request.getParameterNames(); *
} * @return - the HttpServletRequest {@link Reader}
* @throws IOException -
/** * if an I/O Exception occures
* Either <i>Atom</i> or <i>RSS</i> */
* public Reader getReader() throws IOException {
* @return - The output format requested by the client return this.request.getReader();
*/ }
public OutputFormat getRequestedResponseFormat() {
/**
return this.responseFormat; * Returns the {@link HttpServletRequest} parameter map containig all <i>GET</i>
} * request parameters.
*
private void generateIdentificationProperties() * @return the parameter map
throws GDataRequestException { */
/* generate all needed data to identify the requested feed/entry */ @SuppressWarnings("unchecked")
String pathInfo = this.request.getPathInfo(); public Map<String, String[]> getQueryParameter() {
/* return this.request.getParameterMap();
* TODO this has to be changed to support the category queries. Category }
* queries could also be rewrited in the Servlet.
*/ /**
if (pathInfo.length() <= 1) * The {@link HttpServletRequest} request parameter names
throw new GDataRequestException( *
"No feed or entry specified for this request"); * @return parameter names enumeration
StringTokenizer tokenizer = new StringTokenizer(pathInfo, "/"); */
this.feedId = tokenizer.nextToken(); @SuppressWarnings("unchecked")
this.entryId = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : ""; public Enumeration<String> getQueryParameterNames() {
this.entryVersion = tokenizer.hasMoreTokens() ? tokenizer.nextToken() return this.request.getParameterNames();
: ""; }
} /**
* Either <i>Atom</i> or <i>RSS</i>
private void setOutputFormat() { *
String formatParameter = this.request * @return - The output format requested by the client
.getParameter(RESPONSE_FORMAT_PARAMETER); */
if (formatParameter == null) public OutputFormat getRequestedResponseFormat() {
return;
if (formatParameter.equalsIgnoreCase(RESPONSE_FORMAT_PARAMETER_RSS)) return this.responseFormat;
this.responseFormat = OutputFormat.RSS; }
} private void generateIdentificationProperties()
throws GDataRequestException {
/** /* generate all needed data to identify the requested feed/entry */
* @return - the number of returned items per page String pathInfo = this.request.getPathInfo();
*/ /*
public int getItemsPerPage() { * TODO this has to be changed to support the category queries. Category
* queries could also be rewrited in the Servlet.
if (this.request.getParameter(ITEMS_PER_PAGE_PARAMETER) == null) */
return DEFAULT_ITEMS_PER_PAGE; if (pathInfo.length() <= 1)
int retval = -1; throw new GDataRequestException(
try { "No feed or entry specified for this request");
retval = new Integer(this.request StringTokenizer tokenizer = new StringTokenizer(pathInfo, "/");
.getParameter(ITEMS_PER_PAGE_PARAMETER)).intValue(); this.feedId = tokenizer.nextToken();
} catch (Exception e) { this.entryId = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : "";
LOG.warn("Intems per page could not be parsed - " + e.getMessage(), this.entryVersion = tokenizer.hasMoreTokens() ? tokenizer.nextToken()
e); : "";
}
return retval < 0 ? DEFAULT_ITEMS_PER_PAGE : retval; }
}
private void setOutputFormat() {
/** String formatParameter = this.request
* Start index represents the number of the first entry of the query - .getParameter(RESPONSE_FORMAT_PARAMETER);
* result. The order depends on the query. Is the query a search query the if (formatParameter == null)
* this value will be assinged to the score in a common feed query the value return;
* will be assigned to the update time of the entries. if (formatParameter.equalsIgnoreCase(RESPONSE_FORMAT_PARAMETER_RSS))
* this.responseFormat = OutputFormat.RSS;
* @return - the requested start index
*/ }
public int getStartIndex() {
if (this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER) == null) /**
return DEFAULT_START_INDEX; * @return - the number of returned items per page
int retval = -1; */
try { public int getItemsPerPage() {
retval = new Integer(this.request
.getParameter(START_INDEX_NEXT_PAGE_PARAMETER)).intValue(); if (this.request.getParameter(ITEMS_PER_PAGE_PARAMETER) == null)
} catch (Exception e) { return DEFAULT_ITEMS_PER_PAGE;
LOG.warn("Start-index could not be parsed - " + e.getMessage(), e); int retval = -1;
} try {
return retval < 0 ? DEFAULT_START_INDEX : retval; 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(),
* The selfid is <i>href</i> pointing to the requested resource e);
* }
* @return - the self id
*/ return retval < 0 ? DEFAULT_ITEMS_PER_PAGE : retval;
public String getSelfId() { }
StringBuilder builder = new StringBuilder();
builder.append(buildRequestIDString(false)); /**
* Start index represents the number of the first entry of the query -
builder.append(getQueryString()); * 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
return builder.toString(); * will be assigned to the update time of the entries.
} *
* @return - the requested start index
/** */
* The <i>href</i> id of the next page of the requested resource. public int getStartIndex() {
* if (this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER) == null)
* @return the id of the next page return DEFAULT_START_INDEX;
*/ int retval = -1;
public String getNextId() { try {
// StringBuilder builder = new StringBuilder(); retval = new Integer(this.request
// builder.append(buildRequestIDString()); .getParameter(START_INDEX_NEXT_PAGE_PARAMETER)).intValue();
// } catch (Exception e) {
// builder.append(getQueryString()); LOG.warn("Start-index could not be parsed - " + e.getMessage(), e);
// }
// if(this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER)== return retval < 0 ? DEFAULT_START_INDEX : retval;
// null){ }
// builder.append("&").append(START_INDEX_NEXT_PAGE_PARAMETER).append("=");
// builder.append(DEFAULT_ITEMS_PER_PAGE+1); /**
// } * The selfid is <i>href</i> pointing to the requested resource
// else{ *
// * @return - the self id
// int next = 0; */
// try{ public String getSelfId() {
// next = StringBuilder builder = new StringBuilder();
// Integer.parseInt(this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER)); builder.append(buildRequestIDString(false));
// }catch (Exception e) { builder.append("?");
// // builder.append(getQueryString());
// }
// return builder.toString();
// if(next < 0) }
// builder.append(DEFAULT_ITEMS_PER_PAGE+1);
// else /**
// builder.append(next+DEFAULT_ITEMS_PER_PAGE); * The <i>href</i> id of the next page of the requested resource.
// int pos = builder.indexOf(START_INDEX_NEXT_PAGE_PARAMETER); *
// boolean end = builder.lastIndexOf("&",pos) < pos; * @return the id of the next page
// builder.replace(pos+START_INDEX_NEXT_PAGE_PARAMETER.length()+1,pos+START_INDEX_NEXT_PAGE_PARAMETER.length()+3,""+next); */
// public String getNextId() {
// StringBuilder builder = new StringBuilder();
// System.out.println(end); builder.append(buildRequestIDString(false));
// } builder.append("?");
//
// Enumeration parameters = this.request.getParameterNames();
// while (parameters.hasMoreElements()) {
// return builder.toString(); String element = (String) parameters.nextElement();
return buildRequestIDString(false); String[] values = this.request.getParameterValues(element);
for (int i = 0; i < values.length; i++) {
}
builder.append(element).append("=");
private String buildRequestIDString(boolean endingSlash) { if (element.equals(START_INDEX_NEXT_PAGE_PARAMETER)) {
StringBuilder builder = new StringBuilder("http://"); int tempVal = DEFAULT_START_INDEX;
builder.append(this.request.getHeader("Host")); try {
builder.append(this.request.getRequestURI()); tempVal = Integer.parseInt(values[i]);
if (endingSlash && !this.request.getRequestURI().endsWith("/")) } catch (Exception e) {
builder.append("/"); LOG.info("Can not parse StartIndex -- use defaut");
}
return builder.toString(); builder.append(tempVal + getItemsPerPage());
} break;
}
/**
* This will return the current query string including all parameters. builder.append(values[i]);
* Additionaly the <code>max-resul</code> parameter will be added if not
* specified. }
* <p> if (parameters.hasMoreElements())
* <code>max-resul</code> indicates the number of results returned to the builder.append("&");
* client. The default value is 25.
* </p> }
* if (this.request.getParameter(ITEMS_PER_PAGE_PARAMETER) == null) {
* @return - the query string incluing all parameters if (builder.charAt(builder.length() - 1) != '?')
*/ builder.append('&');
public String getQueryString() { builder.append(ITEMS_PER_PAGE_PARAMETER).append("=").append(
String retVal = this.request.getQueryString(); DEFAULT_ITEMS_PER_PAGE);
}
if (this.request.getParameter(ITEMS_PER_PAGE_PARAMETER) != null) if (this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER) == null) {
return retVal; builder.append('&');
String tempString = (retVal == null ? "?" + ITEMS_PER_PAGE_PARAMETER builder.append(START_INDEX_NEXT_PAGE_PARAMETER).append("=");
+ "=" + DEFAULT_ITEMS_PER_PAGE : "&" + ITEMS_PER_PAGE_PARAMETER builder.append(DEFAULT_ITEMS_PER_PAGE + 1);
+ "=" + DEFAULT_ITEMS_PER_PAGE); }
return retVal == null ? tempString : retVal + tempString; return builder.toString();
} }
/** private String buildRequestIDString(boolean endingSlash) {
* This enum represents the OutputFormat of the GDATA Server StringBuilder builder = new StringBuilder("http://");
* builder.append(this.request.getHeader("Host"));
* @author Simon Willnauer builder.append(this.request.getRequestURI());
* if (endingSlash && !this.request.getRequestURI().endsWith("/"))
*/ builder.append("/");
public static enum OutputFormat {
/** return builder.toString();
* Output format ATOM. ATOM is the default response format. }
*/
ATOM, /**
/** * This will return the current query string including all parameters.
* Output format RSS * Additionaly the <code>max-resul</code> parameter will be added if not
*/ * specified.
RSS * <p>
} * <code>max-resul</code> indicates the number of results returned to the
* client. The default value is 25.
/** * </p>
* Returns the requested path including the domain name and the requested *
* resource <i>http://www.apache.org/path/resource/</i> * @return - the query string incluing all parameters
* */
* @return the context path public String getQueryString() {
*/ String retVal = this.request.getQueryString();
public String getContextPath() {
if (this.contextPath == null) if (this.request.getParameter(ITEMS_PER_PAGE_PARAMETER) != null)
this.contextPath = buildRequestIDString(true); return retVal;
return this.contextPath; String tempString = (retVal == null ? ITEMS_PER_PAGE_PARAMETER + "="
} + DEFAULT_ITEMS_PER_PAGE : "&" + ITEMS_PER_PAGE_PARAMETER + "="
+ DEFAULT_ITEMS_PER_PAGE);
/**
* Indicates the request type return retVal == null ? tempString : retVal + tempString;
*
* @author Simon Willnauer }
*
*/ /**
public enum GDataRequestType { * This enum represents the OutputFormat of the GDATA Server
/** *
* Type FeedRequest * @author Simon Willnauer
*/ *
GET, */
/** public static enum OutputFormat {
* Type UpdateRequest /**
*/ * Output format ATOM. ATOM is the default response format.
UPDATE, */
/** ATOM,
* Type DeleteRequest /**
*/ * Output format RSS
DELETE, */
/** RSS
* Type InsertRequest }
*/
INSERT /**
} * Returns the requested path including the domain name and the requested
* resource <i>http://www.apache.org/path/resource/</i>
/** *
* {@link GDataRequestType} * @return the context path
* */
* @return the current request type public String getContextPath() {
*/ if (this.contextPath == null)
public GDataRequestType getType() { this.contextPath = buildRequestIDString(true);
return this.type; return this.contextPath;
} }
/** /**
* If the reuquest is a {@link GDataRequestType#GET} request and there is * Indicates the request type
* no entry id specified, the requested resource is a feed. *
* * @author Simon Willnauer
* @return - <code>true</code> if an only if the requested resource is a feed *
*/ */
public boolean isFeedRequested() { public enum GDataRequestType {
/**
return (this.type.equals(GDataRequestType.GET) && (this.entryId == null|| this.entryId.length() == 0|| (this.entryId.equals('/')))); * Type FeedRequest
} */
GET,
/** /**
* * If the reuquest is a {@link GDataRequestType#GET} request and there is * Type UpdateRequest
* an entry id specified, the requested resource is an entry. */
* UPDATE,
* @return - <code>true</code> if an only if the requested resource is an entry /**
*/ * Type DeleteRequest
public boolean isEntryRequested() { */
return !this.isFeedRequested(); DELETE,
} /**
* Type InsertRequest
/** */
* @return - the extensionProfile for the requested resource INSERT
*/ }
public ExtensionProfile getExtensionProfile() {
return this.extensionProfile; /**
} * {@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 - <code>true</code> 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 - <code>true</code> 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 <tt>Authentication</tt> 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
* <code>null</code> 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 <tt>If-Modified-Since</tt> 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;
}
}

View File

@ -12,231 +12,279 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.lucene.gdata.server; package org.apache.lucene.gdata.server;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.Date;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.apache.lucene.gdata.server.GDataRequest.OutputFormat;
import org.apache.lucene.gdata.server.GDataRequest.OutputFormat;
import com.google.gdata.data.BaseEntry; import org.apache.lucene.gdata.utils.DateFormater;
import com.google.gdata.data.BaseFeed;
import com.google.gdata.data.ExtensionProfile; import com.google.gdata.data.BaseEntry;
import com.google.gdata.util.common.xml.XmlWriter; import com.google.gdata.data.BaseFeed;
import com.google.gdata.util.common.xml.XmlWriter.Namespace; import com.google.gdata.data.DateTime;
import com.google.gdata.data.ExtensionProfile;
/** import com.google.gdata.util.common.xml.XmlWriter;
* The FeedRequest Class wraps the curren HttpServletResponse. Any action on the import com.google.gdata.util.common.xml.XmlWriter.Namespace;
* 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 * The FeedRequest Class wraps the curren HttpServletResponse. Any action on the
* executed within this class. * HttpServletRequest will be executed via this class. This represents an
* <p> * abstraction on the plain {@link HttpServletResponse}. Any action which has
* The GData basicly writes two different kinds ouf reponse to the output * to be performed on the underlaying {@link HttpServletResponse} will be
* stream. * executed within this class.
* <ol> * <p>
* <li>update, delete or insert requests will respond with a statuscode and if * The GData basicly writes two different kinds ouf reponse to the output
* successful the feed entry modified or created</li> * stream.
* <li>get requests will respond with a statuscode and if successful the * <ol>
* requested feed</li> * <li>update, delete or insert requests will respond with a statuscode and if
* </ol> * successful the feed entry modified or created</li>
* * <li>get requests will respond with a statuscode and if successful the
* For this purpose the {@link GDataResponse} class provides the overloaded * requested feed</li>
* method * </ol>
* {@link org.apache.lucene.gdata.server.GDataResponse#sendResponse(BaseEntry, ExtensionProfile)} *
* which sends the entry e.g feed to the output stream. * For this purpose the {@link GDataResponse} class provides the overloaded
* </p> * method
* * {@link org.apache.lucene.gdata.server.GDataResponse#sendResponse(BaseEntry, ExtensionProfile)}
* * which sends the entry e.g feed to the output stream.
* * </p>
* * <p>
* @author Simon Willnauer * This class will set the HTTP <tt>Last-Modified</tt> Header to enable
* * clients to send <tt>If-Modified-Since</tt> request header to avoid
*/ * retrieving the content again if it hasn't changed. If the content hasn't
public class GDataResponse { * changed since the If-Modified-Since time, then the GData service returns a
private int error; * 304 (Not Modified) HTTP response.
* </p>
private boolean isError = false; *
*
private String encoding; *
*
private OutputFormat outputFormat; * @author Simon Willnauer
*
private final HttpServletResponse response; */
public class GDataResponse {
private static final String DEFAUL_NAMESPACE_URI = "http://www.w3.org/2005/Atom"; private int error;
private static final Namespace DEFAULT_NAMESPACE = new Namespace("", private boolean isError = false;
DEFAUL_NAMESPACE_URI);
private String encoding;
/**
* Creates a new GDataResponse private OutputFormat outputFormat;
*
* @param response - private final HttpServletResponse response;
* The underlaying {@link HttpServletResponse}
*/ protected static final String XMLMIME_ATOM = "text/xml";
public GDataResponse(HttpServletResponse response) {
if (response == null) protected static final String XMLMIME_RSS = "text/xml";
throw new IllegalArgumentException("response must not be null");
this.response = response; private static final String DEFAUL_NAMESPACE_URI = "http://www.w3.org/2005/Atom";
this.response.setContentType("text/xml");
} private static final Namespace DEFAULT_NAMESPACE = new Namespace("",
DEFAUL_NAMESPACE_URI);
/**
* Sets an error code to this FeedResponse. private static final String HEADER_LASTMODIFIED = "Last-Modified";
*
* @param errorCode - /**
* {@link HttpServletResponse} error code * Creates a new GDataResponse
*/ *
public void setError(int errorCode) { * @param response -
this.isError = true; * The underlaying {@link HttpServletResponse}
this.error = errorCode; */
} public GDataResponse(HttpServletResponse response) {
/** if (response == null)
* Sets the status of the underlaying response throw new IllegalArgumentException("response must not be null");
* @see HttpServletResponse this.response = response;
* @param responseCode - the status of the response
*/ }
public void setResponseCode(int responseCode){
this.response.setStatus(responseCode); /**
} * Sets an error code to this FeedResponse.
/** *
* This method sends the specified error to the user if set * @param errorCode -
* * {@link HttpServletResponse} error code
* @throws IOException - */
* if an I/O Exception occures public void setError(int errorCode) {
*/ this.isError = true;
public void sendError() throws IOException { this.error = errorCode;
if (this.isError) }
this.response.sendError(this.error);
} /**
* Sets the status of the underlaying response
/** *
* @return - the {@link HttpServletResponse} writer * @see HttpServletResponse
* @throws IOException - * @param responseCode -
* If an I/O exception occures * the status of the response
*/ */
public Writer getWriter() throws IOException { public void setResponseCode(int responseCode) {
return this.response.getWriter(); this.response.setStatus(responseCode);
} }
/** /**
* Sends a response for a get e.g. query request. This method must not * This method sends the specified error to the user if set
* invoked in a case of an error performing the requeste action. *
* * @throws IOException -
* @param feed - * if an I/O Exception occures
* the feed to respond to the client */
* @param profile - public void sendError() throws IOException {
* the extension profil for the feed to write if (this.isError)
* @throws IOException - this.response.sendError(this.error);
* if an I/O exception accures, often caused by an already
* closed Writer or OutputStream }
*
*/ /**
public void sendResponse(BaseFeed feed, ExtensionProfile profile) * @return - the {@link HttpServletResponse} writer
throws IOException { * @throws IOException -
if (feed == null) * If an I/O exception occures
throw new IllegalArgumentException("feed must not be null"); */
if(profile == null) public Writer getWriter() throws IOException {
throw new IllegalArgumentException("extension profil must not be null"); return this.response.getWriter();
XmlWriter writer = createWriter(); }
if (this.outputFormat.equals(OutputFormat.ATOM)) /**
feed.generateAtom(writer, profile); * Sends a response for a get e.g. query request. This method must not
else * invoked in a case of an error performing the requeste action.
feed.generateRss(writer, profile); *
* @param feed -
} * the feed to respond to the client
* @param profile -
/** * the extension profil for the feed to write
* * @throws IOException -
* Sends a response for an update, insert or delete request. This method * if an I/O exception accures, often caused by an already
* must not invoked in a case of an error performing the requeste action. * closed Writer or OutputStream
* If the specified response format is ATOM the default namespace will be set to ATOM. *
* @param entry - */
* the modified / created entry to send public void sendResponse(BaseFeed feed, ExtensionProfile profile)
* @param profile - throws IOException {
* the entries extension profile if (feed == null)
* @throws IOException - throw new IllegalArgumentException("feed must not be null");
* if an I/O exception accures, often caused by an already if (profile == null)
* closed Writer or OutputStream throw new IllegalArgumentException(
*/ "extension profil must not be null");
public void sendResponse(BaseEntry entry, ExtensionProfile profile) DateTime time = feed.getUpdated();
throws IOException { if (time != null)
if (entry == null) setLastModifiedHeader(time.getValue());
throw new IllegalArgumentException("entry must not be null"); XmlWriter writer = createWriter();
if(profile == null)
throw new IllegalArgumentException("extension profil must not be null"); if (this.outputFormat.equals(OutputFormat.ATOM)) {
XmlWriter writer = createWriter(); this.response.setContentType(XMLMIME_ATOM);
if (this.outputFormat.equals(OutputFormat.ATOM)) feed.generateAtom(writer, profile);
entry.generateAtom(writer, profile); } else {
else this.response.setContentType(XMLMIME_RSS);
entry.generateRss(writer, profile); feed.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); * Sends a response for an update, insert or delete request. This method
return writer; * 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.
/** *
* This encoding will be used to encode the xml representation of feed or * @param entry -
* entry written to the {@link HttpServletResponse} output stream. * the modified / created entry to send
* * @param profile -
* @return - the entry / feed encoding * the entries extension profile
*/ * @throws IOException -
public String getEncoding() { * if an I/O exception accures, often caused by an already
return this.encoding; * closed Writer or OutputStream
} */
public void sendResponse(BaseEntry entry, ExtensionProfile profile)
/** throws IOException {
* This encoding will be used to encode the xml representation of feed or if (entry == null)
* entry written to the {@link HttpServletResponse} output stream. <i>UTF-8</i> throw new IllegalArgumentException("entry must not be null");
* <i>ISO-8859-1</i> if (profile == null)
* throw new IllegalArgumentException(
* @param encoding - "extension profil must not be null");
* string represents the encoding DateTime time = entry.getUpdated();
*/ if (time != null)
public void setEncoding(String encoding) { setLastModifiedHeader(time.getValue());
this.encoding = encoding; XmlWriter writer = createWriter();
} if (this.outputFormat.equals(OutputFormat.ATOM))
entry.generateAtom(writer, profile);
/** else
* @return - the response entry.generateRss(writer, profile);
* {@link org.apache.lucene.gdata.server.GDataRequest.OutputFormat} }
*/
public OutputFormat getOutputFormat() { private XmlWriter createWriter() throws IOException {
return this.outputFormat; 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);
* @param outputFormat - return writer;
* the response }
* {@link org.apache.lucene.gdata.server.GDataRequest.OutputFormat}
*/ /**
public void setOutputFormat(OutputFormat outputFormat) { * This encoding will be used to encode the xml representation of feed or
this.outputFormat = outputFormat; * entry written to the {@link HttpServletResponse} output stream.
} *
/** * @return - the entry / feed encoding
* @see Object#toString() */
*/ public String getEncoding() {
@Override return this.encoding;
public String toString(){ }
StringBuilder builder = new StringBuilder(" GDataResponse: ");
builder.append("Error: ").append(this.error); /**
builder.append(" outputFormat: ").append(getOutputFormat()); * This encoding will be used to encode the xml representation of feed or
builder.append(" encoding: ").append(this.encoding); * entry written to the {@link HttpServletResponse} output stream. <i>UTF-8</i>
* <i>ISO-8859-1</i>
return builder.toString(); *
* @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);
}
}

View File

@ -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"); * @author Simon Willnauer
* 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 */
* public class GDataService implements Service {
* Unless required by applicable law or agreed to in writing, software private static final Log LOGGER = LogFactory.getLog(GDataService.class);
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. protected Storage storage;
* See the License for the specific language governing permissions and
* limitations under the License. protected GDataServerRegistry registry = GDataServerRegistry.getRegistry();
*/
package org.apache.lucene.gdata.server; private static final Generator generator;
import java.io.IOException; private static final String generatorName = "Lucene GData-Server";
import java.util.List;
private static final String generatorURI = "http://lucene.apache.org";
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; private static final String XMLMIME = "application/atom+xml";
import org.apache.lucene.gdata.server.registry.GDataServerRegistry; static {
import org.apache.lucene.gdata.storage.Storage; generator = new Generator();
import org.apache.lucene.gdata.storage.StorageException; generator.setName(generatorName);
import org.apache.lucene.gdata.storage.StorageFactory; generator.setUri(generatorURI);
generator.setVersion("0.1");
import com.google.gdata.data.BaseEntry; }
import com.google.gdata.data.BaseFeed;
import com.google.gdata.data.DateTime; protected GDataService() throws ServiceException {
import com.google.gdata.data.Generator; try {
import com.google.gdata.data.Link; StorageController controller = GDataServerRegistry.getRegistry()
import com.google.gdata.util.ParseException; .lookup(StorageController.class,
ComponentType.STORAGECONTROLLER);
/** if (controller == null)
* @author Simon Willnauer throw new StorageException(
* "StorageController is not registered");
*/ this.storage = controller.getStorage();
public class GDataService extends Service {
private static final Log LOGGER = LogFactory.getLog(GDataService.class); } catch (StorageException e) {
LOGGER
private Storage storage; .fatal(
"Can't get Storage Instance -- can't serve any requests",
private GDataServerRegistry registry = GDataServerRegistry.getRegistry(); e);
ServiceException ex = new ServiceException(
private static final Generator generator; "Can't get Storage instance" + e.getMessage(), e);
ex.setStackTrace(e.getStackTrace());
private static final String generatorName = "Lucene GData-Server"; throw ex;
}
private static final String generatorURI = "http://lucene.apache.org"; }
static {
generator = new Generator(); /**
generator.setName(generatorName); * @see org.apache.lucene.gdata.server.Service#createEntry(org.apache.lucene.gdata.server.GDataRequest,
generator.setUri(generatorURI); * org.apache.lucene.gdata.server.GDataResponse)
generator.setVersion("0.1"); */
}
public BaseEntry createEntry(GDataRequest request, GDataResponse response)
protected GDataService() throws ServiceException { throws ServiceException {
try {
this.storage = StorageFactory.getStorage(); if (LOGGER.isInfoEnabled())
LOGGER.info("create Entry for feedId: " + request.getFeedId());
} catch (StorageException e) {
LOGGER ServerBaseEntry entry = buildEntry(request, response);
.fatal( entry.setFeedId(request.getFeedId());
"Can't get Storage Instance -- can't serve any requests", entry.setServiceConfig(request.getConfigurator());
e); setTimeStamps(entry.getEntry());
ServiceException ex = new ServiceException( BaseEntry retVal = null;
"Can't get Storage instance" + e.getMessage(), e); try {
ex.setStackTrace(e.getStackTrace()); retVal = this.storage.storeEntry(entry);
throw ex; } catch (Exception e) {
} response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} ServiceException ex = new ServiceException("Could not store entry",
e);
/** ex.setStackTrace(e.getStackTrace());
* @see org.apache.lucene.gdata.server.Service#createEntry(org.apache.lucene.gdata.server.GDataRequest, throw ex;
* org.apache.lucene.gdata.server.GDataResponse) }
*/ return retVal;
@Override }
public BaseEntry createEntry(GDataRequest request, GDataResponse response)
throws ServiceException { /**
* @see org.apache.lucene.gdata.server.Service#deleteEntry(org.apache.lucene.gdata.server.GDataRequest,
checkFeedIsRegisterd(request); * org.apache.lucene.gdata.server.GDataResponse)
if (LOGGER.isInfoEnabled()) */
LOGGER.info("create Entry for feedId: " + request.getFeedId());
BaseEntry entry = buildEntry(request); public BaseEntry deleteEntry(GDataRequest request, GDataResponse response)
setUpdateTime(entry); throws ServiceException {
try {
ServerBaseEntry entry = new ServerBaseEntry();
this.storage.storeEntry(entry, request.getFeedId()); entry.setServiceConfig(request.getConfigurator());
} catch (Exception e) { entry.setFeedId(request.getFeedId());
ServiceException ex = new ServiceException("Could not store entry", entry.setId(request.getEntryId());
e); if (entry.getId() == null)
ex.setStackTrace(e.getStackTrace()); throw new ServiceException(
throw ex; "entry id is null -- can not delete null entry");
} try {
return entry; this.storage.deleteEntry(entry);
} } catch (ResourceNotFoundException e) {
response.setError(HttpServletResponse.SC_BAD_REQUEST);
/** ServiceException ex = new ServiceException(
* @see org.apache.lucene.gdata.server.Service#deleteEntry(org.apache.lucene.gdata.server.GDataRequest, "Could not delete entry", e);
* org.apache.lucene.gdata.server.GDataResponse) ex.setStackTrace(e.getStackTrace());
*/ throw ex;
@Override } catch (Exception e) {
public BaseEntry deleteEntry(GDataRequest request, GDataResponse response) response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
throws ServiceException { ServiceException ex = new ServiceException(
checkFeedIsRegisterd(request); "Could not delete entry", e);
String entryid = request.getEntryId(); ex.setStackTrace(e.getStackTrace());
String feedid = request.getFeedId(); throw ex;
try { }
this.storage.deleteEntry(entryid, feedid); return null;
} catch (Exception e) { }
ServiceException ex = new ServiceException(
"Could not delete entry", e); /**
ex.setStackTrace(e.getStackTrace()); * @see org.apache.lucene.gdata.server.Service#updateEntry(org.apache.lucene.gdata.server.GDataRequest,
throw ex; * org.apache.lucene.gdata.server.GDataResponse)
} */
return null;
} public BaseEntry updateEntry(GDataRequest request, GDataResponse response)
throws ServiceException {
/**
* @see org.apache.lucene.gdata.server.Service#updateEntry(org.apache.lucene.gdata.server.GDataRequest, ServerBaseEntry entry = buildEntry(request, response);
* org.apache.lucene.gdata.server.GDataResponse) entry.setFeedId(request.getFeedId());
*/
@Override entry.setServiceConfig(request.getConfigurator());
public BaseEntry updateEntry(GDataRequest request, GDataResponse response) if (LOGGER.isInfoEnabled())
throws ServiceException { LOGGER.info("update Entry" + entry.getId() + " for feedId: "
checkFeedIsRegisterd(request); + request.getFeedId());
if (entry.getId() == null) {
BaseEntry entry = buildEntry(request); response.setError(HttpServletResponse.SC_BAD_REQUEST);
String feedid = request.getFeedId(); throw new ServiceException("Entry id is null can not update entry");
if (LOGGER.isInfoEnabled()) }
LOGGER.info("update Entry" + entry.getId() + " for feedId: " if (!entry.getId().equals(request.getEntryId())) {
+ feedid); if (LOGGER.isInfoEnabled())
setUpdateTime(entry); LOGGER
try { .info("Entry id in the entry xml does not match the requested resource -- XML-ID:"
this.storage.updateEntry(entry, feedid); + entry.getId()
} catch (StorageException e) { + "; Requested resource: "
ServiceException ex = new ServiceException( + request.getEntryId());
"Could not update entry", e); response.setError(HttpServletResponse.SC_BAD_REQUEST);
ex.setStackTrace(e.getStackTrace()); throw new ServiceException(
throw ex; "Entry id in the entry xml does not match the requested resource");
} }
return entry; setTimeStamps(entry.getEntry());
} BaseEntry retVal = null;
try {
/** retVal = this.storage.updateEntry(entry);
* @see org.apache.lucene.gdata.server.Service#getFeed(org.apache.lucene.gdata.server.GDataRequest, } catch (ResourceNotFoundException e) {
* org.apache.lucene.gdata.server.GDataResponse) response.setError(HttpServletResponse.SC_BAD_REQUEST);
*/ ServiceException ex = new ServiceException(
@SuppressWarnings("unchecked") "Could not update entry", e);
@Override ex.setStackTrace(e.getStackTrace());
public BaseFeed getFeed(GDataRequest request, GDataResponse response) throw ex;
throws ServiceException { } catch (StorageException e) {
checkFeedIsRegisterd(request); response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
ServiceException ex = new ServiceException(
try { "Could not update entry", e);
// TODO remove when storing feeds is implemented just for ex.setStackTrace(e.getStackTrace());
// development throw ex;
BaseFeed feed = this.storage.getFeed(request.getFeedId(), request }
.getStartIndex(), request.getItemsPerPage()); return retVal;
buildDynamicFeedElements(request, feed); }
List<BaseEntry> list = feed.getEntries();
addContextPath(list, request.getContextPath()); /**
return feed; * @see org.apache.lucene.gdata.server.Service#getFeed(org.apache.lucene.gdata.server.GDataRequest,
} catch (StorageException e) { * org.apache.lucene.gdata.server.GDataResponse)
ServiceException ex = new ServiceException("Could not get feed", e); */
ex.setStackTrace(e.getStackTrace()); @SuppressWarnings("unchecked")
throw ex; public BaseFeed getFeed(GDataRequest request, GDataResponse response)
} throws ServiceException {
} ServerBaseFeed feed = new ServerBaseFeed();
feed.setId(request.getFeedId());
/* feed.setStartIndex(request.getStartIndex());
* build the dynamic elements like self link and next link feed.setItemsPerPage(request.getItemsPerPage());
*/ feed.setServiceConfig(request.getConfigurator());
private void buildDynamicFeedElements(final GDataRequest request, try {
final BaseFeed feed) { BaseFeed retVal = this.storage.getFeed(feed);
feed.setGenerator(generator); dynamicElementFeedStragey(retVal, request);
feed.setItemsPerPage(request.getItemsPerPage());
feed.getLinks().add( return retVal;
buildLink(Link.Rel.SELF, Link.Type.ATOM, request.getSelfId())); /*
// TODO add next link * resouce not found will be detected in Gdata request.
} * the request queries the storage for the feed to get the serivce for the feed
*/
private Link buildLink(String rel, String type, String href) { } catch (StorageException e) {
Link retVal = new Link(); response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
retVal.setHref(href); ServiceException ex = new ServiceException("Could not get feed", e);
retVal.setRel(rel); ex.setStackTrace(e.getStackTrace());
retVal.setType(type); throw ex;
return retVal; }
}
}
/*
* every entry has an ID which has to have a prefix. The prefix is the private Link buildLink(String rel, String type, String href) {
* context path of the requested feed. This will be used to request the Link retVal = new Link();
* entry directly retVal.setHref(href);
*/ retVal.setRel(rel);
private void addContextPath(List<BaseEntry> list, final String contextPath) { retVal.setType(type);
for (BaseEntry entry : list) { return retVal;
addcontextPath(entry, contextPath); }
}
} private ServerBaseEntry buildEntry(final GDataRequest request,
final GDataResponse response) throws ServiceException {
@SuppressWarnings("unchecked") try {
private BaseEntry addcontextPath(final BaseEntry entry, ServerBaseEntry entry = new ServerBaseEntry(GDataEntityBuilder
final String contextPath) { .buildEntry(request));
String id = contextPath + entry.getId(); return entry;
entry.setId(id);
Link self = new Link(); } catch (ParseException e) {
self.setRel("self"); response.setError(HttpServletResponse.SC_BAD_REQUEST);
self.setHref(id); ServiceException ex = new ServiceException(
self.setType("application/atom+xml"); "Could not parse entry from incoming request", e);
entry.getLinks().add(self); ex.setStackTrace(e.getStackTrace());
return entry; throw ex;
} } catch (IOException e) {
response.setError(HttpServletResponse.SC_BAD_REQUEST);
private BaseEntry buildEntry(final GDataRequest request) ServiceException ex = new ServiceException(
throws ServiceException { "Could not read or open input stream", e);
try { ex.setStackTrace(e.getStackTrace());
return GDataEntityBuilder.buildEntry(request); throw ex;
}
} catch (ParseException e) { }
ServiceException ex = new ServiceException(
"Could not parse entry from incoming request", e); private BaseEntry setTimeStamps(final BaseEntry entry) {
ex.setStackTrace(e.getStackTrace()); if (entry.getUpdated() == null)
throw ex; entry.setUpdated(DateTime.now());
} catch (IOException e) { if (entry.getPublished() == null)
ServiceException ex = new ServiceException( entry.setPublished(DateTime.now());
"Could not read or open input stream", e); return entry;
ex.setStackTrace(e.getStackTrace()); }
throw ex;
} /**
} * @see org.apache.lucene.gdata.server.Service#getSingleEntry(org.apache.lucene.gdata.server.GDataRequest,
* org.apache.lucene.gdata.server.GDataResponse)
/* */
* checks whether the reqeuested feed is registered
*/ public BaseEntry getSingleEntry(GDataRequest request, GDataResponse response)
private void checkFeedIsRegisterd(final GDataRequest request) throws ServiceException {
throws FeedNotFoundException {
if (!this.registry.isFeedRegistered(request.getFeedId())) try {
throw new FeedNotFoundException( ServerBaseEntry entry = new ServerBaseEntry();
"Feed could not be found - is not registed - Feed ID:" entry.setServiceConfig(request.getConfigurator());
+ request.getFeedId()); entry.setFeedId(request.getFeedId());
this.storage.setExtensionProfile(request.getExtensionProfile()); entry.setId(request.getEntryId());
} if(entry.getId() == null){
response.setError(HttpServletResponse.SC_BAD_REQUEST);
private BaseEntry setUpdateTime(final BaseEntry entry) { throw new ServiceException("entry is null can't get entry");
entry.setUpdated(DateTime.now()); }
return entry;
} BaseEntry retVal = null;
retVal = this.storage.getEntry(entry);
/** dynamicElementEntryStragey(retVal, request);
* @see org.apache.lucene.gdata.server.Service#getSingleEntry(org.apache.lucene.gdata.server.GDataRequest, return retVal;
* org.apache.lucene.gdata.server.GDataResponse) } catch (ResourceNotFoundException e) {
*/ response.setError(HttpServletResponse.SC_BAD_REQUEST);
@Override ServiceException ex = new ServiceException(
public BaseEntry getSingleEntry(GDataRequest request, GDataResponse response) "Could not get entry", e);
throws ServiceException { ex.setStackTrace(e.getStackTrace());
checkFeedIsRegisterd(request); throw ex;
} catch (StorageException e) {
try { ServiceException ex = new ServiceException("Could not get feed", e);
BaseEntry entry = this.storage.getEntry(request.getEntryId(), ex.setStackTrace(e.getStackTrace());
request.getFeedId()); throw ex;
if(entry == null) }
return null; }
addcontextPath(entry, request.getContextPath());
return entry; /*
} catch (StorageException e) { * adds all dynamic element to the entry
ServiceException ex = new ServiceException("Could not get feed", e); */
ex.setStackTrace(e.getStackTrace()); private void dynamicElementEntryStragey(final BaseEntry entry,
throw ex; 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<BaseEntry> 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;
}
}
}

View File

@ -16,6 +16,8 @@
package org.apache.lucene.gdata.server; package org.apache.lucene.gdata.server;
import java.util.Date;
import com.google.gdata.data.BaseEntry; import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.BaseFeed; 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 * 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) public abstract BaseEntry getSingleEntry(final GDataRequest request, final GDataResponse response)
throws ServiceException; 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;

View File

@ -12,52 +12,59 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.lucene.gdata.server; package org.apache.lucene.gdata.server;
/** /**
* @author Simon Willnauer * 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.
* *
*/ * @author Simon Willnauer
public class ServiceException extends Exception { *
*/
/** public class ServiceException extends Exception {
*
*/ /**
private static final long serialVersionUID = -7099825107871876584L; *
*/
/** private static final long serialVersionUID = -7099825107871876584L;
*
*/ /**
public ServiceException() { * Constructs a new ServiceException
super(); */
public ServiceException() {
} super();
/** }
* @param arg0
*/ /**
public ServiceException(String arg0) { * Constructs a new ServiceException
super(arg0); * @param arg0 - the exception message
*/
} public ServiceException(String arg0) {
super(arg0);
/**
* @param arg0 }
* @param arg1
*/ /**
public ServiceException(String arg0, Throwable arg1) { * Constructs a new ServiceException
super(arg0, arg1); * @param arg0 - the exceptin message
* @param arg1 - the exception cause
} */
public ServiceException(String arg0, Throwable arg1) {
/** super(arg0, arg1);
* @param arg0
*/ }
public ServiceException(Throwable arg0) {
super(arg0); /**
* Constructs a new ServiceException
} * @param arg0 - the exception cause
*/
} public ServiceException(Throwable arg0) {
super(arg0);
}
}

View File

@ -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"); * @author Simon Willnauer
* 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 */
* @Component(componentType=ComponentType.SERVICEFACTORY)
* Unless required by applicable law or agreed to in writing, software public class ServiceFactory implements ServerComponent {
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. private static final Log LOG = LogFactory.getLog(ServiceFactory.class);
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.gdata.server; /**
* public constructor to enable loading via the registry
* @see org.apache.lucene.gdata.server.registry.Component
/** * @see org.apache.lucene.gdata.server.registry.GDataServerRegistry
* The {@link ServiceFactory} creates {@link Service} implementations to access */
* the GData - Server components. public ServiceFactory() {
* //
* @author Simon Willnauer }
*
*/ /**
public class ServiceFactory { * Creates a {@link Service} instance.
*
private static ServiceFactory INSTANCE = null; * @return a Service instance
*/
/** public Service getService() {
* @return - a Singleton Instance of the factory try{
*/ return new GDataService();
public static synchronized ServiceFactory getInstance() { }catch (Exception e) {
if (INSTANCE == null) //
INSTANCE = new ServiceFactory(); }
return INSTANCE; return null;
}
}
/**
private ServiceFactory() { * Creates a {@link AdminService} instance
// private constructor --> singleton * @return a AdminService instance
} */
public AdminService getAdminService(){
/** try {
* Creates a {@link Service} implementation. return new GDataAdminService();
* } catch (ServiceException e) {
* @return a Service Implementation LOG.warn("Factory method can not create GDataAdminService returning null-- "+e.getMessage(),e);
*/ }
public Service getService() { return null;
try{ }
return new GDataService();
}catch (Exception e) { /**
// * @see org.apache.lucene.gdata.server.registry.ServerComponent#initialize()
} */
return null; public void initialize() {
} //
} }
/**
* @see org.apache.lucene.gdata.server.registry.ServerComponent#destroy()
*/
public void destroy() {
//
}
}

View File

@ -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
}
}

View File

@ -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;
}
}

View File

@ -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"); * The GDataServerRegistry represents the registry component of the GData
* you may not use this file except in compliance with the License. * Server. All provided services and server components will be registered here.
* You may obtain a copy of the License at * The Gdata Server serves RSS / ATOM feeds for defined services. Each service
* provides <i>n</i> feeds of a defined subclass of
* {@link com.google.gdata.data.BaseFeed}. Each feed contains <i>m</i> 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.
* <p>
* The entry,feed and the ExtensionProfile classes are defined in the
* gdata-config.xml and will be loaded when the server starts up.
* </p>
* <p>
* 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.
* </p>
* <p>The GDataServerRegistry is a Singleton</p>
* *
* http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * @author Simon Willnauer
* 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 public class GDataServerRegistry {
* limitations under the License. private static GDataServerRegistry INSTANCE;
*/
package org.apache.lucene.gdata.server.registry; private static final Log LOGGER = LogFactory
.getLog(GDataServerRegistry.class);
import java.util.HashMap;
import java.util.Map; private final Map<String, ProvidedService> serviceTypeMap = new HashMap<String, ProvidedService>();
import org.apache.commons.logging.Log; private final Map<ComponentType, ComponentBean> componentMap = new HashMap<ComponentType, ComponentBean>(
import org.apache.commons.logging.LogFactory; 10);
import org.apache.lucene.gdata.storage.StorageController;
private GDataServerRegistry() {
import com.google.gdata.data.ExtensionProfile; // private - singleton
}
/**
* /**
* The FeedRegistry represents the registry component of the GData Server. All * @return a Sinleton registry instance
* feed configurations will be registered here. Feed configurations contain */
* several informationsa about GData feed like: public static synchronized GDataServerRegistry getRegistry() {
* <ol> if (INSTANCE == null)
* <li>the feed id - where the feed can be accessed via http methodes</li> INSTANCE = new GDataServerRegistry();
* <li>the feed type - feed types are implementations of the abstract return INSTANCE;
* {@link com.google.gdata.data.BaseFeed}</li> }
* </ol>
* 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 * Registers a {@link ProvidedService}
* requests. *
* * @param configurator -
* @author Simon Willnauer * the configurator to register in the registry
* */
*/ public void registerService(ProvidedService configurator) {
public class GDataServerRegistry { if (configurator == null) {
private static GDataServerRegistry INSTANCE; LOGGER.warn("Feedconfigurator is null -- skip registration");
return;
private StorageController storageInstance; }
this.serviceTypeMap.put(configurator.getName(), configurator);
private static final Log LOGGER = LogFactory }
.getLog(GDataServerRegistry.class);
/**
private final Map<String, FeedInstanceConfigurator> feedTypMap = new HashMap<String, FeedInstanceConfigurator>(); * Looks up the {@link ProvidedServiceConfig} by the given service name.
*
private GDataServerRegistry() { * @param service
// private - singleton * @return - the {@link ProvidedServiceConfig} or <code>null</code> if the
} * no configuration for this service has been registered
*/
/** public ProvidedService getProvidedService(String service) {
* @return a Sinleton registry instance if (service == null)
*/ throw new IllegalArgumentException(
public static synchronized GDataServerRegistry getRegistry() { "Service is null - must not be null to get registered feedtype");
if (INSTANCE == null) return this.serviceTypeMap.get(service);
INSTANCE = new GDataServerRegistry(); }
return INSTANCE;
} protected void flushRegistry() {
this.serviceTypeMap.clear();
/** this.componentMap.clear();
* Registers a {@link FeedInstanceConfigurator} }
*
* @param configurator - /**
* the configurator to register in the registry * @param service -
*/ * the name of the service
public void registerFeed(FeedInstanceConfigurator configurator) { * @return - <code>true</code> if and only if the service is registered,
if (configurator == null) { * otherwise <code>false</code>.
LOGGER.warn("Feedconfigurator is null -- skip registration"); */
return; public boolean isServiceRegistered(String service) {
} return this.serviceTypeMap.containsKey(service);
this.feedTypMap.put(configurator.getFeedId(), configurator);
} }
/** /**
* Looks up the {@link FeedInstanceConfigurator} by the given feed id. * Destroys the registry and release all resources
* */
* @param feedId public void destroy() {
* @return - the {@link FeedInstanceConfigurator} or <code>null</code> if for (ComponentBean component : this.componentMap.values()) {
* the no configuration for this feed has been registered component.getObject().destroy();
*/ }
public FeedInstanceConfigurator getFeedConfigurator(String feedId) { flushRegistry();
if (feedId == null)
throw new IllegalArgumentException( }
"Feed URL is null - must not be null to get registered feedtype");
return this.feedTypMap.get(feedId); /**
} * This method is the main interface to the Component Lookup Service of the
* registry. Every GDATA - Server component like STORAGE or the INDEXER
protected void flushRegistry() { * component will be accessible via this method. To get a Component from the
this.feedTypMap.clear(); * 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:
/** * <p>
* @param feedId - * <code> registryInstance.lookup(StorageController.class,ComponentType.STORAGECONTROLLER);</code>
* the id of the feed as the feed is registered * </p>
* @return - <code>true</code> if and only if the feed is registered, *
* otherwise <code>false</code>. * @param <R>
*/ * the type of the expected return value
public boolean isFeedRegistered(String feedId) { * @param clazz -
return this.feedTypMap.containsKey(feedId); * Class object of the expected return value
* @param compType -
} * The component type
* @return the registered component or <code>null</code> if the component
/** * can not looked up.
* @param storage */
*/ @SuppressWarnings("unchecked")
public void registerStorage(StorageController storage) { public <R> R lookup(Class<R> clazz, ComponentType compType) {
if (this.storageInstance != null) ComponentBean bean = this.componentMap.get(compType);
throw new IllegalStateException( if (bean == null)
"Storage already registered -- Instance of " return null;
+ this.storageInstance.getClass()); if (bean.getSuperType().equals(clazz))
this.storageInstance = storage; return (R) bean.getObject();
} return null;
}
/**
* Destroys the registry and release all resources /**
*/ * @param <E>
public void destroy() { * @param componentClass
flushRegistry(); * @throws RegistryException
this.storageInstance.destroy(); */
this.storageInstance = null; @SuppressWarnings("unchecked")
public <E extends ServerComponent> void registerComponent(final Class<E> componentClass)
} throws RegistryException {
/** if (componentClass == null)
* Creates the {@link ExtensionProfile} for a registered feed throw new IllegalArgumentException(
* @param feedId - the feed id "component class must not be null");
* @return - the extension profil for this feed of <code>null</code> if
* the feed is not registered or the extension profile could not be if(!checkImplementsServerComponent(componentClass))
* instanciated throw new RegistryException("can not register component. the given class does not implement ServerComponent interface -- "+componentClass.getName());
*/ try {
public ExtensionProfile getExtensionProfile(final String feedId) {
FeedInstanceConfigurator configurator = this.feedTypMap.get(feedId); Component annotation = componentClass.getAnnotation(Component.class);
if (configurator == null) if (annotation == null)
return null; throw new RegistryException(
Class clazz = configurator.getExtensionProfilClass(); "can not register component. the given class is not a component -- "
try { + componentClass.getName());
return (ExtensionProfile) clazz.newInstance(); ComponentType type = annotation.componentType();
} catch (Exception e) { if (this.componentMap.containsKey(type))
LOGGER throw new RegistryException("component already registered -- "
.error("Can not create instance of ExtensionProfil for class: " + type.name());
+ clazz + " -- feedId: " + feedId); Class superType = type.getClass().getField(type.name())
.getAnnotation(SuperType.class).superType();
} if (!checkSuperType(componentClass, superType))
return null; 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;
}
}
}

View File

@ -12,30 +12,59 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.lucene.gdata.server.registry; package org.apache.lucene.gdata.server.registry;
import com.google.gdata.data.ExtensionProfile; import java.io.IOException;
import com.google.gdata.data.Feed;
import org.apache.commons.digester.Digester;
/** import org.xml.sax.SAXException;
* @author Simon Willnauer
/**
* 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.
* *
*/ * @author Simon Willnauer
public class RegistryBuilder { *
*/
/** class RegistryBuilder {
*
*/ /**
public static void buildRegistry(){ * builds the {@link GDataServerRegistry} accessible via the
// TODO Implement this!! -- just for develping purposes * {@link GDataServerRegistry#getRegistry()} method
GDataServerRegistry reg = GDataServerRegistry.getRegistry(); *
FeedInstanceConfigurator configurator = new FeedInstanceConfigurator(); * @throws IOException -
configurator.setFeedType(Feed.class); * if an IOException occures while reading the config file
configurator.setFeedId("weblog"); * @throws SAXException -
configurator.setExtensionProfileClass(ExtensionProfile.class); * if the config file can not be parsed
reg.registerFeed(configurator); */
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"));
}
}

View File

@ -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.
* <p>
* This ContextListener has to be configured in the <code>web.xml</code>
* deployment descriptor.
* </p>
* <p>
* 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, public class RegistryContextListener implements ServletContextListener {
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. private GDataServerRegistry serverRegistry;
* See the License for the specific language governing permissions and
* limitations under the License. private static final Log LOG = LogFactory
*/ .getLog(RegistryContextListener.class);
package org.apache.lucene.gdata.server.registry; /**
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
import javax.servlet.ServletContextEvent; */
import javax.servlet.ServletContextListener; public void contextInitialized(ServletContextEvent arg0) {
LOG.info("RegistryContextListener has been loaded");
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; try {
RegistryBuilder.buildRegistry();
/** this.serverRegistry = GDataServerRegistry.getRegistry();
* This Listener creates the } catch (Exception e) {
* {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry} when the this.serverRegistry.destroy();
* context is loaded. The registry will be loaded before the LOG.error("can not register requiered components", e);
* {@link org.apache.lucene.gdata.servlet.RequestControllerServlet} is loaded. throw new RuntimeException("Can not register required components",
* The Registry will be loaded and set up befor the REST interface is available. e);
* <p> }
* This ContextListener has to be configured in the <code>web.xml</code>
* deployment descriptor.</p>
* }
*
* @author Simon Willnauer /**
* * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
*/ */
public class RegistryContextListener implements ServletContextListener { public void contextDestroyed(ServletContextEvent arg0) {
private GDataServerRegistry serverRegistry; LOG.info("Destroying context");
this.serverRegistry.destroy();
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();
}
}

View File

@ -5,6 +5,6 @@
<meta name="Author" content="Simon Willnauer"> <meta name="Author" content="Simon Willnauer">
</head> </head>
<body> <body>
Internal registry - registering feeds and configurations Internal registry - registering services and server components
</body> </body>
</html> </html>

View File

@ -18,10 +18,15 @@ package org.apache.lucene.gdata.servlet;
import java.io.IOException; import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; 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_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 <code>service</code> method to dispatch * This overwrites the protected <code>service</code> method to dispatch
@ -92,6 +99,17 @@ public abstract class AbstractGdataServlet extends HttpServlet {
super.service(arg0, arg1); 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");
} }
} }

View File

@ -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"); * @author Simon Willnauer
* 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 */
* public class RequestControllerServlet extends AbstractGdataServlet {
* Unless required by applicable law or agreed to in writing, software private static final Log LOGGER = LogFactory.getLog(RequestControllerServlet.class);
* 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 * Version ID since this class implements
* limitations under the License. *
*/ * @see java.io.Serializable
*/
package org.apache.lucene.gdata.servlet; private static final long serialVersionUID = 7540810742476175576L;
import java.io.IOException; /**
* @see javax.servlet.http.HttpServlet#doDelete(javax.servlet.http.HttpServletRequest,
import javax.servlet.ServletConfig; * javax.servlet.http.HttpServletResponse)
import javax.servlet.ServletException; */
import javax.servlet.http.HttpServletRequest; @Override
import javax.servlet.http.HttpServletResponse; protected void doDelete(HttpServletRequest arg0, HttpServletResponse arg1)
throws ServletException, IOException {
import org.apache.commons.logging.Log; GDataRequestHandler hanlder = HANDLER_FACTORY.getEntryDeleteHandler();
import org.apache.commons.logging.LogFactory; if(LOGGER.isInfoEnabled())
import org.apache.lucene.gdata.servlet.handler.DefaultRequestHandlerFactory; LOGGER.info("Process DELETE request");
import org.apache.lucene.gdata.servlet.handler.GDataRequestHandler;
import org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory; hanlder.processRequest(arg0, arg1);
}
/**
* Provides a clean basic interface for GDATA Client API and requests to the /**
* GDATA Server. This Servlet dispatches the incoming requests to defined GDATA * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
* request handlers. Each of the handler processes the incoming request and * javax.servlet.http.HttpServletResponse)
* responds according to the requested action. */
* @Override
* @author Simon Willnauer protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1)
* throws ServletException, IOException {
*/ GDataRequestHandler hanlder = HANDLER_FACTORY.getFeedQueryHandler();
public class RequestControllerServlet extends AbstractGdataServlet { if(LOGGER.isInfoEnabled())
private static RequestHandlerFactory HANDLER_FACTORY = null; LOGGER.info("Process GET request");
private static final Log LOGGER = LogFactory.getLog(RequestControllerServlet.class); hanlder.processRequest(arg0, arg1);
}
/**
* Version ID since this class implements /**
* * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
* @see java.io.Serializable * javax.servlet.http.HttpServletResponse)
*/ */
private static final long serialVersionUID = 7540810742476175576L; @Override
protected void doPost(HttpServletRequest arg0, HttpServletResponse arg1)
/** throws ServletException, IOException {
* @see javax.servlet.http.HttpServlet#doDelete(javax.servlet.http.HttpServletRequest, GDataRequestHandler hanlder = HANDLER_FACTORY.getEntryInsertHandler();
* javax.servlet.http.HttpServletResponse) if(LOGGER.isInfoEnabled())
*/ LOGGER.info("Process POST request");
@Override hanlder.processRequest(arg0, arg1);
protected void doDelete(HttpServletRequest arg0, HttpServletResponse arg1) }
throws ServletException, IOException {
GDataRequestHandler hanlder = HANDLER_FACTORY.getDeleteHandler(); /**
if(LOGGER.isInfoEnabled()) * @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest,
LOGGER.info("Process DELETE request"); * javax.servlet.http.HttpServletResponse)
*/
hanlder.processRequest(arg0, arg1); @Override
} protected void doPut(HttpServletRequest arg0, HttpServletResponse arg1)
throws ServletException, IOException {
/** GDataRequestHandler hanlder = HANDLER_FACTORY.getEntryUpdateHandler();
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, if(LOGGER.isInfoEnabled())
* javax.servlet.http.HttpServletResponse) LOGGER.info("Process PUT request");
*/ hanlder.processRequest(arg0, arg1);
@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);
}
}

View File

@ -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. public abstract class AbstractGdataRequestHandler extends RequestAuthenticator implements
* You may obtain a copy of the License at GDataRequestHandler {
* private final static Log LOG = LogFactory
* http://www.apache.org/licenses/LICENSE-2.0 .getLog(AbstractGdataRequestHandler.class);
*
* Unless required by applicable law or agreed to in writing, software protected Service service;
* distributed under the License is distributed on an "AS IS" BASIS, protected GDataRequest feedRequest;
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. protected GDataResponse feedResponse;
* See the License for the specific language governing permissions and
* limitations under the License. /**
*/ * @see org.apache.lucene.gdata.servlet.handler.GDataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
package org.apache.lucene.gdata.servlet.handler; */
public abstract void processRequest(HttpServletRequest request,
import java.io.IOException; HttpServletResponse response) throws ServletException, IOException;
import javax.servlet.ServletException; protected void initializeRequestHandler(final HttpServletRequest request, final HttpServletResponse response, final GDataRequestType type)
import javax.servlet.http.HttpServletRequest; throws GDataRequestException, ServletException {
import javax.servlet.http.HttpServletResponse; this.feedRequest = new GDataRequest(request, type);
this.feedResponse = new GDataResponse(response);
import org.apache.commons.logging.Log; getService();
import org.apache.commons.logging.LogFactory; try {
import org.apache.lucene.gdata.server.GDataRequest; this.feedRequest.initializeRequest();
import org.apache.lucene.gdata.server.GDataRequestException; } catch (GDataRequestException e) {
import org.apache.lucene.gdata.server.GDataResponse; this.feedResponse.setError(HttpServletResponse.SC_NOT_FOUND);
import org.apache.lucene.gdata.server.Service; LOG.warn("Couldn't initialize FeedRequest - " + e.getMessage(), e);
import org.apache.lucene.gdata.server.ServiceFactory; throw e;
import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; }
}
/**
* @author Simon Willnauer
*
*/ protected void sendError() throws IOException {
public abstract class AbstractGdataRequestHandler implements this.feedResponse.sendError();
GDataRequestHandler {
private final static Log LOG = LogFactory }
.getLog(AbstractGdataRequestHandler.class);
protected void setFeedResponseFormat() {
this.feedResponse.setOutputFormat(this.feedRequest.getRequestedResponseFormat());
protected GDataRequest feedRequest; }
protected GDataResponse feedResponse;
protected void setFeedResponseStatus(int status) {
/** this.feedResponse.setResponseCode(status);
* @see org.apache.lucene.gdata.servlet.handler.GDataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, }
* javax.servlet.http.HttpServletResponse)
*/ protected void setError(int error) {
public abstract void processRequest(HttpServletRequest request, this.feedResponse.setError(error);
HttpServletResponse response) throws ServletException, IOException; }
protected void initializeRequestHandler(final HttpServletRequest request, final HttpServletResponse response, final GDataRequestType type) private void getService() throws ServletException {
throws GDataRequestException { GDataServerRegistry registry = GDataServerRegistry.getRegistry();
this.feedRequest = new GDataRequest(request, type); ServiceFactory serviceFactory = registry.lookup(ServiceFactory.class,ComponentType.SERVICEFACTORY);
this.feedResponse = new GDataResponse(response); this.service = serviceFactory.getService();
try { if(this.service == null)
this.feedRequest.initializeRequest(); throw new ServletException("Service not available");
} catch (GDataRequestException e) {
this.feedResponse.setError(HttpServletResponse.SC_NOT_FOUND); }
LOG.warn("Couldn't initialize FeedRequest - " + e.getMessage(), e);
throw e; protected void closeService(){
} this.service.close();
} }
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;
}
}

View File

@ -1,84 +1,83 @@
/** /**
* Copyright 2004 The Apache Software Foundation * Copyright 2004 The Apache Software Foundation
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.lucene.gdata.servlet.handler; package org.apache.lucene.gdata.servlet.handler;
import java.io.IOException; import java.io.IOException;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.server.FeedNotFoundException; import org.apache.lucene.gdata.data.GDataAccount.AccountRole;
import org.apache.lucene.gdata.server.GDataRequestException; 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.ServiceException; import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType;
import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType;
/**
/** * Default Handler implementation. This handler processes the incoming
* Default Handler implementation. This handler processes the incoming * {@link org.apache.lucene.gdata.server.GDataRequest} and deletes the requested
* {@link org.apache.lucene.gdata.server.GDataRequest} and deletes the requested * feed entry from the storage and the search component.
* feed entry from the storage and the search component. * <p>
* <p> * The handler sends following response to the client:
* The handler sends following response to the client: * </p>
* </p> * <ol>
* <ol> * <li>if the entry could be deleted - HTTP status code <i>200 OK</i></li>
* <li>if the entry could be deleted - HTTP status code <i>200 OK</i></li> * <li>if an error occures - HTTP status code <i>500 INTERNAL SERVER ERROR</i></li>
* <li>if an error occures - HTTP status code <i>500 INTERNAL SERVER ERROR</i></li> * <li>if the resource could not found - HTTP status code <i>404 NOT FOUND</i></li>
* <li>if the resource could not found - HTTP status code <i>404 NOT FOUND</i></li> * </ol>
* </ol>
* *
* @author Simon Willnauer * @author Simon Willnauer
* *
*/ */
public class DefaultDeleteHandler extends AbstractGdataRequestHandler { public class DefaultDeleteHandler extends AbstractGdataRequestHandler {
private static final Log LOG = LogFactory private static final Log LOG = LogFactory
.getLog(DefaultDeleteHandler.class); .getLog(DefaultDeleteHandler.class);
/** /**
* @throws ServletException * @throws ServletException
* @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, * @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse) * javax.servlet.http.HttpServletResponse)
*/ */
@Override @Override
public void processRequest(HttpServletRequest request, public void processRequest(HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException { HttpServletResponse response) throws IOException, ServletException {
try { try {
initializeRequestHandler(request, response,GDataRequestType.DELETE); initializeRequestHandler(request, response,GDataRequestType.DELETE);
} catch (GDataRequestException e) { } catch (GDataRequestException e) {
sendError(); sendError();
return; return;
} }
if(!authenticateAccount(request,AccountRole.ENTRYAMINISTRATOR)){
Service service = getService(); setError(HttpServletResponse.SC_UNAUTHORIZED);
try { sendError();
service.deleteEntry(this.feedRequest, this.feedResponse); return;
} catch (FeedNotFoundException e) { }
LOG.error("Could not process DeleteFeed request Feed Not Found- "
+ e.getMessage(), e); try {
setError(HttpServletResponse.SC_NOT_FOUND); this.service.deleteEntry(this.feedRequest, this.feedResponse);
sendError();
} catch (ServiceException e) { } catch (ServiceException e) {
LOG.error("Could not process DeleteFeed request - " LOG.error("Could not process DeleteFeed request - "
+ e.getMessage(), e); + e.getMessage(), e);
setError(HttpServletResponse.SC_BAD_REQUEST); sendError();
sendError(); }
} closeService();
} }
} }

View File

@ -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.
* <p>
* 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.
* </p>
* <p>
* The DefaultGetHandler supports HTTP Conditional GET. It set the Last-Modified
* response header based upon the value of the <atom:updated> 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.</p>
* *
* 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, public class DefaultGetHandler extends AbstractGdataRequestHandler {
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. private static final Log LOG = LogFactory.getLog(DefaultGetHandler.class);
* See the License for the specific language governing permissions and
* limitations under the License. /**
*/ * @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
package org.apache.lucene.gdata.servlet.handler; */
@Override
import java.io.IOException; public void processRequest(HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
import javax.servlet.ServletException; try {
import javax.servlet.http.HttpServletRequest; initializeRequestHandler(request, response, GDataRequestType.GET);
import javax.servlet.http.HttpServletResponse; } catch (GDataRequestException e) {
sendError();
import org.apache.commons.logging.Log; return;
import org.apache.commons.logging.LogFactory; }
import org.apache.lucene.gdata.server.GDataRequestException;
import org.apache.lucene.gdata.server.Service; try {
import org.apache.lucene.gdata.server.ServiceException; String modifiedSince = this.feedRequest.getModifiedSince();
import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; if (!checkIsModified(modifiedSince)) {
this.feedResponse
import com.google.gdata.data.BaseEntry; .setStatus(HttpServletResponse.SC_NOT_MODIFIED);
import com.google.gdata.data.BaseFeed; return;
}
/** if (LOG.isInfoEnabled())
* Default Handler implementation. This handler processes the incoming LOG.info("Requested output formate: "
* {@link org.apache.lucene.gdata.server.GDataRequest} and retrieves the + this.feedRequest.getRequestedResponseFormat());
* requested feed from the underlaying storage. this.feedResponse.setOutputFormat(this.feedRequest
* <p> .getRequestedResponseFormat());
* This hander also processes search queries and retrives the search hits from if (this.feedRequest.isFeedRequested()) {
* the underlaying search component. The user query will be accessed via the BaseFeed feed = this.service.getFeed(this.feedRequest,
* {@link org.apache.lucene.gdata.server.GDataRequest} instance passed to the this.feedResponse);
* {@link Service} class.
* </p> this.feedResponse.sendResponse(feed, this.feedRequest
* .getConfigurator().getExtensionProfile());
* } else {
* @author Simon Willnauer BaseEntry entry = this.service.getSingleEntry(this.feedRequest,
* this.feedResponse);
*/ this.feedResponse.sendResponse(entry, this.feedRequest
public class DefaultGetHandler extends AbstractGdataRequestHandler { .getConfigurator().getExtensionProfile());
private static final Log LOG = LogFactory.getLog(DefaultGetHandler.class); }
/** } catch (ServiceException e) {
* @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, LOG.error("Could not process GetFeed request - " + e.getMessage(),
* javax.servlet.http.HttpServletResponse) e);
*/ sendError();
@Override }
public void processRequest(HttpServletRequest request, closeService();
HttpServletResponse response) throws IOException, ServletException {
try { }
initializeRequestHandler(request, response, GDataRequestType.GET);
} catch (GDataRequestException e) { /**
sendError(); *
return; * returns true if the resource has been modified since the specified
} * reqeust header value
Service service = getService(); */
try { private boolean checkIsModified(String lastModified)
if (LOG.isInfoEnabled()) throws ServiceException {
LOG.info("Requested output formate: " if (lastModified == null)
+ this.feedRequest.getRequestedResponseFormat()); return true;
this.feedResponse.setOutputFormat(this.feedRequest try {
.getRequestedResponseFormat()); Date clientDate = DateFormater.parseDate(lastModified,DateFormater.HTTP_HEADER_DATE_FORMAT,DateFormater.HTTP_HEADER_DATE_FORMAT_TIME_OFFSET);
if(this.feedRequest.isFeedRequested()){ Date entityDate;
BaseFeed feed = service if (this.feedRequest.isFeedRequested())
.getFeed(this.feedRequest, this.feedResponse); entityDate = this.service.getFeedLastModified(this.feedRequest
.getFeedId());
this.feedResponse.sendResponse(feed, this.feedRequest.getExtensionProfile()); else
}else{ entityDate = this.service.getEntryLastModified(this.feedRequest
BaseEntry entry = service.getSingleEntry(this.feedRequest,this.feedResponse); .getEntryId(),this.feedRequest.getFeedId());
if(entry == null){ if(LOG.isInfoEnabled())
this.feedResponse.setError(HttpServletResponse.SC_NOT_FOUND); LOG.info("comparing date clientDate: "+clientDate+"; lastmodified: "+entityDate);
sendError(); return (entityDate.getTime()-clientDate.getTime() > 1000);
} } catch (java.text.ParseException e) {
this.feedResponse.sendResponse(entry, this.feedRequest.getExtensionProfile()); LOG.info("Couldn't parse Last-Modified header -- "+lastModified,e);
}
}
return true;
} 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();
}
}
}

View File

@ -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.
* <p>
* The handler sends following response to the client:
* </p>
* <ol>
* <li>if the entry was added - HTTP status code <i>200 OK</i></li>
* <li>if an error occures - HTTP status code <i>500 INTERNAL SERVER ERROR</i></li>
* <li>if the resource could not found - HTTP status code <i>404 NOT FOUND</i></li>
* </ol>
* <p>The added entry will be send back to the client if the insert request was successful.</p>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * @author Simon Willnauer
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at */
* public class DefaultInsertHandler extends AbstractGdataRequestHandler {
* http://www.apache.org/licenses/LICENSE-2.0 private static final Log LOG = LogFactory.getLog(DefaultInsertHandler.class);
* /**
* Unless required by applicable law or agreed to in writing, software * @throws ServletException
* distributed under the License is distributed on an "AS IS" BASIS, * @see org.apache.lucene.gdata.servlet.handler.GDataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
* See the License for the specific language governing permissions and @Override
* limitations under the License. public void processRequest(HttpServletRequest request,
*/ HttpServletResponse response) throws IOException, ServletException {
try {
package org.apache.lucene.gdata.servlet.handler; initializeRequestHandler(request,response,GDataRequestType.INSERT);
} catch (GDataRequestException e) {
import java.io.IOException; sendError();
return;
import javax.servlet.ServletException; }
import javax.servlet.http.HttpServletRequest; if(!authenticateAccount(this.feedRequest,AccountRole.ENTRYAMINISTRATOR)){
import javax.servlet.http.HttpServletResponse; setError(HttpServletResponse.SC_UNAUTHORIZED);
sendError();
import org.apache.commons.logging.Log; return;
import org.apache.commons.logging.LogFactory; }
import org.apache.lucene.gdata.server.GDataRequestException;
import org.apache.lucene.gdata.server.Service; try{
import org.apache.lucene.gdata.server.ServiceException; BaseEntry entry = this.service.createEntry(this.feedRequest,this.feedResponse);
import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; setFeedResponseFormat();
setFeedResponseStatus(HttpServletResponse.SC_CREATED);
import com.google.gdata.data.BaseEntry; this.feedResponse.sendResponse(entry, this.feedRequest.getConfigurator().getExtensionProfile());
/** }catch (ServiceException e) {
* Default Handler implementation. This handler processes the incoming LOG.error("Could not process GetFeed request - "+e.getMessage(),e);
* {@link org.apache.lucene.gdata.server.GDataRequest} and inserts the requested this.feedResponse.sendError();
* feed entry into the storage and the search component. }
* <p> closeService();
* The handler sends following response to the client:
* </p> }
* <ol>
* <li>if the entry was added - HTTP status code <i>200 OK</i></li> }
* <li>if an error occures - HTTP status code <i>500 INTERNAL SERVER ERROR</i></li>
* <li>if the resource could not found - HTTP status code <i>404 NOT FOUND</i></li>
* </ol>
* <p>The added entry will be send back to the client if the insert request was successful.</p>
*
* @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();
}
}
}

View File

@ -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"); * @author Simon Willnauer
* 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 */
* @Component(componentType=ComponentType.REQUESTHANDLERFACTORY)
* Unless required by applicable law or agreed to in writing, software public class DefaultRequestHandlerFactory extends RequestHandlerFactory {
* 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. * public constructor to enable loading via the registry
*/ * @see org.apache.lucene.gdata.server.registry.Component
* @see org.apache.lucene.gdata.server.registry.GDataServerRegistry
package org.apache.lucene.gdata.servlet.handler; */
public DefaultRequestHandlerFactory() {
/** //
* Default implementation for RequestHandlerFactory Builds the }
* {@link org.apache.lucene.gdata.servlet.handler.GDataRequestHandler}
* instances. /**
* * @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getEntryUpdateHandler()
* @author Simon Willnauer */
* @Override
*/ public GDataRequestHandler getEntryUpdateHandler() {
public class DefaultRequestHandlerFactory extends RequestHandlerFactory {
return new DefaultUpdateHandler();
DefaultRequestHandlerFactory() { }
//
} /**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getEntryDeleteHandler()
/** */
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getUpdateHandler() @Override
*/ public GDataRequestHandler getEntryDeleteHandler() {
@Override
public GDataRequestHandler getUpdateHandler() { return new DefaultDeleteHandler();
}
return new DefaultUpdateHandler();
} /**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getFeedQueryHandler()
/** */
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getDeleteHandler() @Override
*/ public GDataRequestHandler getFeedQueryHandler() {
@Override
public GDataRequestHandler getDeleteHandler() { return new DefaultGetHandler();
}
return new DefaultDeleteHandler();
} /**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getEntryInsertHandler()
/** */
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getQueryHandler() @Override
*/ public GDataRequestHandler getEntryInsertHandler() {
@Override
public GDataRequestHandler getQueryHandler() { return new DefaultInsertHandler();
}
return new DefaultGetHandler();
} /**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getInsertAccountHandler()
/** */
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getInsertHandler() @Override
*/ public GDataRequestHandler getInsertAccountHandler() {
@Override
public GDataRequestHandler getInsertHandler() { return new InsertAccountStrategy();
}
return new DefaultInsertHandler();
} /**
* @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() {
//
}
}

View File

@ -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.
* <p>
* The handler sends following response to the client:
* </p>
* <ol>
* <li>if the entry was successfully updated - HTTP status code <i>200 OK</i></li>
* <li>if an error occures - HTTP status code <i>500 INTERNAL SERVER ERROR</i></li>
* <li>if the resource could not found - HTTP status code <i>404 NOT FOUND</i></li>
* </ol>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * @author Simon Willnauer
* 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.
* <p>
* The handler sends following response to the client:
* </p>
* <ol>
* <li>if the entry was successfully updated - HTTP status code <i>200 OK</i></li>
* <li>if an error occures - HTTP status code <i>500 INTERNAL SERVER ERROR</i></li>
* <li>if the resource could not found - HTTP status code <i>404 NOT FOUND</i></li>
* </ol>
* *
* @author Simon Willnauer */
* public class DefaultUpdateHandler extends AbstractGdataRequestHandler {
*/ private static final Log LOG = LogFactory
public class DefaultUpdateHandler extends AbstractGdataRequestHandler { .getLog(DefaultUpdateHandler.class);
private static final Log LOG = LogFactory
.getLog(DefaultUpdateHandler.class); /**
* @throws ServletException
/** * @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest,
* @throws ServletException * javax.servlet.http.HttpServletResponse)
* @see org.apache.lucene.gdata.servlet.handler.AbstractGdataRequestHandler#processRequest(javax.servlet.http.HttpServletRequest, */
* javax.servlet.http.HttpServletResponse) @Override
*/ public void processRequest(HttpServletRequest request,
@Override HttpServletResponse response) throws IOException, ServletException {
public void processRequest(HttpServletRequest request, try {
HttpServletResponse response) throws IOException, ServletException { initializeRequestHandler(request, response,GDataRequestType.UPDATE);
try { } catch (GDataRequestException e) {
initializeRequestHandler(request, response,GDataRequestType.UPDATE); setError(HttpServletResponse.SC_UNAUTHORIZED);
} catch (GDataRequestException e) { sendError();
sendError(); return;
return; }
} if(!authenticateAccount(request,AccountRole.ENTRYAMINISTRATOR)){
sendError();
Service service = getService(); return;
try { }
BaseEntry entry = service.updateEntry(this.feedRequest,
this.feedResponse); try {
setFeedResponseFormat(); BaseEntry entry = this.service.updateEntry(this.feedRequest,
setFeedResponseStatus(HttpServletResponse.SC_OK); this.feedResponse);
this.feedResponse.sendResponse(entry, this.feedRequest.getExtensionProfile()); setFeedResponseFormat();
}catch (FeedNotFoundException e) { setFeedResponseStatus(HttpServletResponse.SC_OK);
LOG.error("Could not process UpdateFeed request - " this.feedResponse.sendResponse(entry, this.feedRequest.getConfigurator().getExtensionProfile());
+ e.getMessage(), e);
setError(HttpServletResponse.SC_NOT_FOUND); }
catch (ServiceException e) {
sendError(); LOG.error("Could not process UpdateFeed request - "
} + e.getMessage(), e);
catch (ServiceException e) { sendError();
}
LOG.error("Could not process UpdateFeed request - " closeService();
+ e.getMessage(), e); }
setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
sendError();
}
}
}

View File

@ -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. public abstract class RequestHandlerFactory implements ServerComponent {
* 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, * public constructor to enable loading via the registry
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * @see org.apache.lucene.gdata.server.registry.Component
* See the License for the specific language governing permissions and * @see org.apache.lucene.gdata.server.registry.GDataServerRegistry
* limitations under the License. */
*/ public RequestHandlerFactory() {
super();
package org.apache.lucene.gdata.servlet.handler;
}
/**
* @author Simon Willnauer
* /**
*/ * Creates a EntryUpdateHandler which processes a GDATA UPDATE request.
public abstract class RequestHandlerFactory { * @return - a RequestHandlerInstance
*/
private static RequestHandlerFactory INSTANCE = null; public abstract GDataRequestHandler getEntryUpdateHandler();
/** /**
* This method creates a singleton instance of the given type. The fist call * Creates a EntryDeleteHandler which processes a GDATA DELETE request.
* will create an instance of the given class which will be returned in * @return - a RequestHandlerInstance
* every subsequent call. Any subsequent call to this method will ignore the */
* given class object. public abstract GDataRequestHandler getEntryDeleteHandler();
*
* @param factoryImplementation - /**
* the factory implementation (must be a subtype of this Class) * Creates a FeedQueryHandler which processes a GDATA Query / Get request.
* * @return - a RequestHandlerInstance
* @return - a singleton instance of the given type */
* public abstract GDataRequestHandler getFeedQueryHandler();
*/
public static synchronized RequestHandlerFactory getInstance( /**
Class factoryImplementation) { * Creates a EntryInsertHandler which processes a GDATA Insert request.
if (INSTANCE == null) { * @return - a RequestHandlerInstance
*/
INSTANCE = createInstance(factoryImplementation); public abstract GDataRequestHandler getEntryInsertHandler();
} /**
return INSTANCE; * Creates a InsertAccountHandler which processes a Account Insert request.
} * @return - a RequestHandlerInstance
*/
/** public abstract GDataRequestHandler getInsertAccountHandler();
* Singleton - Pattern using private constructor /**
* * Creates a DeleteAccountHandler which processes a Account Delete request.
*/ * @return - a RequestHandlerInstance
RequestHandlerFactory() { */
super(); public abstract GDataRequestHandler getDeleteAccountHandler();
/**
} * Creates a UpdateAccountHandler which processes a Account Update request.
* @return - a RequestHandlerInstance
private static RequestHandlerFactory createInstance( */
final Class qualifiedClass) { public abstract GDataRequestHandler getUpdateAccountHandler();
if (qualifiedClass == null) /**
throw new IllegalArgumentException( * Creates a InsertFeedHandler which processes a Feed Insert request.
"Factory class is null -- must be a implementation of org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory"); * @return - a RequestHandlerInstance
try { */
return (RequestHandlerFactory) qualifiedClass.newInstance(); public abstract GDataRequestHandler getInsertFeedHandler();
} catch (Exception e) { /**
FactoryImplementationException ex = new FactoryImplementationException( * Creates a UpdateFeedHandler which processes a Feed Insert request.
"Factory implementation could not be created", e.getCause()); * @return - a RequestHandlerInstance
ex.setStackTrace(e.getStackTrace()); */
throw ex; public abstract GDataRequestHandler getUpdateFeedHandler();
} /**
} * Creates a DeleteFeedHandler which processes a Feed Insert request.
* @return - a RequestHandlerInstance
/** */
* Creates a UpdateHandler which processes a GDATA UPDATE request. public abstract GDataRequestHandler getDeleteFeedHandler();
* @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);
}
}
}

View File

@ -51,7 +51,9 @@ public class IDGenerator {
private static final int DEFAULT_CAPACITY = 10; 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 * Constructs a new ID generator. with a fixed capacity of prebuild ids. The
@ -91,7 +93,9 @@ public class IDGenerator {
if (this.runner == null) { if (this.runner == null) {
UIDProducer producer = new UIDProducer(this.blockingQueue, UIDProducer producer = new UIDProducer(this.blockingQueue,
this.secureRandom, this.mdigest); 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(); this.runner.start();
} }
} }

View File

@ -12,89 +12,263 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.lucene.gdata.storage; package org.apache.lucene.gdata.storage;
import java.util.List; import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.data.ServerBaseEntry;
import com.google.gdata.data.BaseEntry; import org.apache.lucene.gdata.data.ServerBaseFeed;
import com.google.gdata.data.BaseFeed;
import com.google.gdata.data.ExtensionProfile; import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.BaseFeed;
/**
* This is the main storage interface. The Storage represents the internal /**
* server storage. It acts as a Database to persist the feed data. * A interface every storage implementation must provide to access the
* This inferface is not public yet!! * <tt>Storage</tt>. It describes all access methodes needed to store,
* * retrieve and look up data stored in the <tt>Storage</tt> component. This
* @author Simon Willnauer * interface acts as a <tt>Facade</tt> to hide the storage implementation from
* * the user.
*/ * <p>
public interface Storage { * This could also act as a proxy for a remote storage. It also removes any
* restrictions from custom storage implementations.
/** * </p>
* This stores an incoming entry for a later retrival. *
* The Entry will be associated with the feedid. *
* @param entry - the entry * @author Simon Willnauer
* @param feedId - the feedID *
* @return - the stored Entry */
* @throws StorageException /*
*/ * not final yet
public abstract BaseEntry storeEntry(BaseEntry entry, String feedId) */
throws StorageException; public interface Storage {
/** /**
* @param entryId *
* @param feedId * Stores the given entry. The ServerBaseEntry must provide a feed id and
* @throws StorageException * the service type. configuration for the entry.
*/ *
public abstract void deleteEntry(String entryId, String feedId) * @param entry -
throws StorageException; * the entry to store
*
/** * @return - the stored Entry for the server response
* @param entry * @throws StorageException -
* @param feedId * if the entry can not be stored or required field are not set.
* @return */
* @throws StorageException public abstract BaseEntry storeEntry(ServerBaseEntry entry)
*/ throws StorageException;
public abstract BaseEntry updateEntry(BaseEntry entry, String feedId)
throws StorageException; /**
* Deletes the given entry. The ServerBaseEntry just hase to provide the
/** * entry id to be deleted.
* @param feedId *
* @param startIndex * @param entry -
* @param resultCount * the entry to delete from the storage
* @return * @throws StorageException -
* @throws StorageException * if the entry can not be deleted or the entry does not exist
*/ * or required field are not set.
public abstract BaseFeed getFeed(String feedId, int startIndex, */
int resultCount) throws StorageException; public abstract void deleteEntry(ServerBaseEntry entry)
throws StorageException;
/**
* @param entryId /**
* @param feedId * Updates the given entry. The ServerBaseEntry must provide a feed id,
* @return * service id and the
* @throws StorageException * {@link org.apache.lucene.gdata.server.registry.ProvidedService}
*/ *
public abstract BaseEntry getEntry(String entryId, String feedId) * @param entry -
throws StorageException; * the entry to update
*
/** * @return - the updated entry for server response.
* @param entryIdList * @throws StorageException -
* @param feedId * if the entry can not be updated or does not exist or required
* @return * field are not set.
* @throws StorageException */
*/ public abstract BaseEntry updateEntry(ServerBaseEntry entry)
public abstract List<BaseEntry> getEntries(List<String> entryIdList, throws StorageException;
String feedId) throws StorageException;
/**
/** * Retrieves the requested feed from the storage. The given ServerBaseFeed
* @param profile * 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
public abstract void setExtensionProfile(final ExtensionProfile profile); * provided.
*
/** * @param feed -
* close this storage instance * the to retieve from the storage
*/ * @return the requested feed
public abstract void close(); * @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 <tt>password</tt>
* and <tt>accountname</tt>
*
* @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
* <tt>password</tt> and <tt>accountname</tt>
*
* @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
* <code>new Long(0)</code> 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
* <code>new Long(0)</code> 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;
}

View File

@ -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
* <tt>Stroage</tt> Factory. The <tt>StroageController</tt> 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.
* <p>
* This instances, registered in the registry must be thread save as they are
* shared between several clients
* </p>
* <p>
* 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 <i>administrator</i> and a default
* password <i>password</i>. 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()}
* </p>
*
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * @author Simon Willnauer
* 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 */
* public interface StorageController extends ServerComponent {
* Unless required by applicable law or agreed to in writing, software /**
* distributed under the License is distributed on an "AS IS" BASIS, * Destroys the controller - this method is called by the registry when the
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * context will be destroyed
* See the License for the specific language governing permissions and */
* limitations under the License. public abstract void destroy();
*/
package org.apache.lucene.gdata.storage; /**
* Creates Storage instances to access the underlaying storage component
/** *
* @author Simon Willnauer * @return a storage instance
* * @throws StorageException -
*/ * if the storage instance can not be created
public interface StorageController { */
/** public abstract Storage getStorage() throws StorageException;
* Destroys the controller }
*/
public abstract void destroy();
}

View File

@ -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;
}
}
}

View File

@ -16,19 +16,26 @@
package org.apache.lucene.gdata.storage.lucenestorage; package org.apache.lucene.gdata.storage.lucenestorage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.LinkedList;
import java.util.Map; import java.util.List;
import java.util.concurrent.locks.Lock; import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock; import java.util.Set;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.Map.Entry;
import java.util.concurrent.locks.Lock;
import org.apache.commons.logging.Log; import java.util.concurrent.locks.ReadWriteLock;
import org.apache.commons.logging.LogFactory; import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
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 * 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 { public class StorageBuffer {
private static final Log LOG = LogFactory.getLog(StorageBuffer.class); private static final Log LOG = LogFactory.getLog(StorageBuffer.class);
private final Map<String, Map<String, StorageEntryWrapper>> bufferMap; private final Map<String, Map<String, StorageEntryWrapper>> bufferMap;
private final Map<String, Long> modifiyMap;
private final List<String> excludeList; private final List<String> excludeList;
@ -86,6 +95,9 @@ public class StorageBuffer {
this.excludeList = new ArrayList<String>( this.excludeList = new ArrayList<String>(
expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT
: expectedBufferCount); : expectedBufferCount);
this.modifiyMap = new HashMap<String, Long>(
expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT
: expectedBufferCount);
} }
/** /**
@ -114,7 +126,9 @@ public class StorageBuffer {
20); 20);
newFeedMap.put(wrapper.getEntryId(), wrapper); newFeedMap.put(wrapper.getEntryId(), wrapper);
this.bufferMap.put(feedId, newFeedMap); this.bufferMap.put(feedId, newFeedMap);
} }
addLastModified(wrapper.getFeedId(),wrapper.getTimestamp());
} finally { } finally {
/* /*
* add all to exclude from searches doc will be available via the * add all to exclude from searches doc will be available via the
@ -124,6 +138,22 @@ public class StorageBuffer {
this.writeLock.unlock(); 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<Entry<String,Long>> getLastModified(){
return this.modifiyMap.entrySet();
}
/** /**
* Returns all entries for the given feed id sorted by the update timestamp * Returns all entries for the given feed id sorted by the update timestamp
@ -173,6 +203,7 @@ public class StorageBuffer {
if (tempMap == null) if (tempMap == null)
return; return;
tempMap.remove(entryId); tempMap.remove(entryId);
this.addLastModified(feedId,new Long(System.currentTimeMillis()));
} finally { } finally {
this.writeLock.unlock(); this.writeLock.unlock();
@ -230,6 +261,7 @@ public class StorageBuffer {
private void clearBuffer() { private void clearBuffer() {
this.bufferMap.clear(); this.bufferMap.clear();
this.excludeList.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<Link>();
}
/**
* @param arg0
*/
@SuppressWarnings("unchecked")
public BufferableEntry(BaseEntry arg0) {
super(arg0);
this.links = new LinkedList<Link>();
}
/**
* @see com.google.gdata.data.BaseEntry#declareExtensions(com.google.gdata.data.ExtensionProfile)
*/
@Override
public void declareExtensions(ExtensionProfile arg0) {
//
}
}
} }

View File

@ -1,286 +1,398 @@
package org.apache.lucene.gdata.storage.lucenestorage; package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry; import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.storage.IDGenerator; import org.apache.lucene.gdata.server.registry.Component;
import org.apache.lucene.gdata.storage.StorageController; import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.storage.StorageException; import org.apache.lucene.gdata.storage.IDGenerator;
import org.apache.lucene.gdata.storage.lucenestorage.configuration.StorageConfigurator; import org.apache.lucene.gdata.storage.Storage;
import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter; import org.apache.lucene.gdata.storage.StorageController;
import org.apache.lucene.index.IndexModifier; import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.gdata.storage.lucenestorage.configuration.StorageConfigurator;
import org.apache.lucene.store.Directory; import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter;
import org.apache.lucene.store.FSDirectory; import org.apache.lucene.index.IndexModifier;
import org.apache.lucene.index.IndexWriter;
/** import org.apache.lucene.search.IndexSearcher;
* TODO document this import org.apache.lucene.store.Directory;
* @author Simon Willnauer import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.RAMDirectory;
/**
*
* *
*/ * @author Simon Willnauer
public class StorageCoreController implements StorageController{ *
protected static final Log LOG = LogFactory.getLog(StorageCoreController.class); */
private IndexSearcher searcher; @Component(componentType = ComponentType.STORAGECONTROLLER)
private static StorageCoreController coreController; public class StorageCoreController implements StorageController {
private final Directory storageDir; protected static final Log LOG = LogFactory
private final StorageModifier modifier; .getLog(StorageCoreController.class);
private ReferenceCounter<StorageQuery> storageQuery;
private StorageBuffer currentBuffer; private IndexSearcher searcher;
private Object storageControllerLock = new Object();
private static final int DEFAULT_STORAGE_BUFFER_SIZE = 10; private final Directory storageDir;
private static final int DEFAULT_STORAGE_PERSIST_FACTOR = 10;
private static final String STORAGELOG = ".lucenestorage"; private final StorageModifier modifier;
private int storageBufferSize;
private int storagePersistFactor; private ReferenceCounter<StorageQuery> storageQuery;
private StorageConfigurator configurator;
private IDGenerator idGenerator; private StorageBuffer currentBuffer;
private int indexOptimizeInterval;
private Object storageControllerLock = new Object();
private StorageCoreController()throws IOException, StorageException{
this(null); 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 <tt>StoragCoreController</tt> 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 <tt>StorageQuery</tt> to query the storage index. The
* returned object is a reference counter to keep track of the references to
* the <tt>StorageQuery</tt>. The reference is already incremented before
* returned from this method.
* <p>
* if the reference counter has no remaining references the resource e.g.
* the <tt>StorageQuery</tt> will be closed. This ensures that a
* <tt>StorageQuery</tt> 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.
* </p>
*
* @return a {@link ReferenceCounter} instance holding the StorageQuery as a
* resource.
*
*/
protected ReferenceCounter<StorageQuery> 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<StorageQuery> getNewStorageQueryHolder(
final StorageQuery query) {
ReferenceCounter<StorageQuery> holder = new ReferenceCounter<StorageQuery>(
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 <tt>StorageQuery</tt> 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 <tt>StorageBuffer</tt>.
*
* @return - storage buffer size
*/
public int getStorageBufferSize() {
return this.storageBufferSize;
}
/**
* The size of the <tt>StorageBuffer</tt>. This size should be at least
* as big as the persist factor to prevent the <tt>StorageBuffer</tt> 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 void createAdminAccount() throws StorageException{
GDataAccount adminAccount = GDataAccount.createAdminAccount();
private StorageCoreController(final Directory dir) throws IOException, StorageException { StorageAccountWrapper wrapper = new StorageAccountWrapper(adminAccount);
synchronized (StorageCoreController.class) { this.getStorageModifier().createAccount(wrapper);
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<StorageQuery> 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<StorageQuery> getNewStorageQueryHolder(final StorageQuery query){
ReferenceCounter<StorageQuery> holder = new ReferenceCounter<StorageQuery>(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);
}
}
}

View File

@ -12,177 +12,215 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.lucene.gdata.storage.lucenestorage; package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.gdata.data.ServerBaseEntry;
import com.google.gdata.data.BaseEntry; import org.apache.lucene.gdata.server.registry.ProvidedService;
import com.google.gdata.data.ExtensionProfile; import org.apache.lucene.gdata.server.registry.ProvidedServiceConfig;
import com.google.gdata.util.common.xml.XmlWriter; import org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer.BufferableEntry;
/** import com.google.gdata.data.BaseEntry;
* This immutable class wrapps Entries for an internal Storage representation of import com.google.gdata.util.common.xml.XmlWriter;
* an entry. This class also acts as a Documentfactory for lucene documents to
* be stored inside the index. /**
* * This immutable class wrapps <tt>ServerBaseEntry</tt> for an internal
* @author Simon Willnauer * Storage representation of an entry. This class also acts as a Documentfactory
* * for lucene documents to be stored inside the index.
*/ *
public class StorageEntryWrapper implements Comparable<StorageEntryWrapper> { * @author Simon Willnauer
private static final String INTERNAL_ENCODING = "UTF-8"; *
*/
/** public class StorageEntryWrapper implements Comparable<StorageEntryWrapper>,
* lucene field name Entry id StorageWrapper {
*/
public final static String FIELD_ENTRY_ID = "entryId"; private static final long serialVersionUID = -4619985652059888526L;
/** private static final String INTERNAL_ENCODING = "UTF-8";
* lucene field name feed id
*/ /**
public final static String FIELD_FEED_ID = "feedId"; * lucene field name Entry id
*/
/** public final static String FIELD_ENTRY_ID = "entryId";
* lucene field name entry content
*/ /**
public final static String FIELD_CONTENT = "content"; * lucene field name feed id
*/
/** public final static String FIELD_FEED_REFERENCE = "feedReference";
* lucene field name creating timestamp
*/ /**
public final static String FIELD_TIMESTAMP = "timestamp"; * lucene field name entry content
*/
private final String entryId; public final static String FIELD_CONTENT = "content";
private final String feedId; /**
* lucene field name creating timestamp
private final String content; */
public final static String FIELD_TIMESTAMP = "timestamp";
private final transient BaseEntry entry;
private final String entryId;
private final Long timestamp;
private final String feedId;
private transient Document document;
private String content;
private StorageOperation operation;
private final ServerBaseEntry entry;
private final ExtensionProfile profile;
private Long timestamp;
/**
* Creates a new StorageEntryWrapper. private transient Document document;
*
* @param entry - private StorageOperation operation;
* the entry to wrap
* @param feedId - private ProvidedService config;
* the feed id
* @param operation - /**
* the StorageOperation * Creates a new StorageEntryWrapper.
* @param profile - *
* the ExtensionProfil for the given entry * @param entry -
* @throws IOException - * the entry to wrap
* if the entry content can not be generated *
*/ * @param operation -
protected StorageEntryWrapper(final BaseEntry entry, final String feedId, * the StorageOperation
StorageOperation operation, final ExtensionProfile profile) *
throws IOException { * @throws IOException -
this.entry = entry; * if the entry content can not be generated
this.operation = operation; */
this.entryId = entry.getId(); public StorageEntryWrapper(final ServerBaseEntry entry,
this.feedId = feedId; StorageOperation operation) throws IOException {
this.profile = profile;
this.content = buildContent(); this.entry = entry;
this.timestamp = new Long(System.currentTimeMillis()); this.operation = operation;
this.entryId = entry.getId();
} this.feedId = entry.getFeedId();
if (operation != StorageOperation.DELETE) {
private String buildContent() throws IOException { this.config = entry.getServiceConfig();
StringWriter writer = new StringWriter(); this.content = buildContent();
XmlWriter xmlWriter = new XmlWriter(writer, INTERNAL_ENCODING);
this.entry.generateAtom(xmlWriter, this.profile); }
return writer.toString(); this.timestamp = new Long(
this.entry.getUpdated() != null ? this.entry.getUpdated()
} .getValue() : System.currentTimeMillis());
/**
* @return - the lucene document representing the entry }
*/
public Document getLuceneDocument() { private String buildContent() throws IOException {
if (this.document != null) StringWriter writer = new StringWriter();
return this.document; XmlWriter xmlWriter = new XmlWriter(writer, INTERNAL_ENCODING);
this.document = new Document(); this.entry.generateAtom(xmlWriter, this.config.getExtensionProfile());
this.document.add(new Field("entryId", this.entryId, Field.Store.YES, return writer.toString();
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)); * @see org.apache.lucene.gdata.storage.lucenestorage.StorageWrapper#getLuceneDocument()
this.document.add(new Field("timestamp", this.timestamp.toString(), */
Field.Store.YES, Field.Index.UN_TOKENIZED)); public Document getLuceneDocument() {
if(this.operation == StorageOperation.DELETE)
return this.document; return null;
if (this.document != null)
} return this.document;
this.document = new Document();
/** this.document.add(new Field(FIELD_ENTRY_ID, this.entryId,
* @return - the wrapped entry Field.Store.YES, Field.Index.UN_TOKENIZED));
*/ this.document.add(new Field(FIELD_FEED_REFERENCE, this.feedId,
public BaseEntry getEntry() { Field.Store.YES, Field.Index.UN_TOKENIZED));
return this.entry; 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 - the entry id
*/ return this.document;
public String getEntryId() {
return this.entryId; }
}
/**
/** * @return - the wrapped entry
* @return - the feed id */
*/ public BaseEntry getEntry() {
public String getFeedId() { /*
return this.feedId; * this wrapps the entry again. BufferableEntry creates a new instance
} * for the dynamic element like links.
*/
/** return new BufferableEntry(this.entry.getEntry());
* Storage operations }
*
* @author Simon Willnauer /**
* * @return - the entry id
*/ */
public static enum StorageOperation { public String getEntryId() {
/** return this.entryId;
* delete }
*/
DELETE, /**
/** * @return - the feed id
* update */
*/ public String getFeedId() {
UPDATE, return this.feedId;
/** }
* insert
*/ /**
INSERT * Storage operations
} *
* @author Simon Willnauer
/** *
* @return the specified storage operation */
*/ public static enum StorageOperation {
public StorageOperation getOperation() { /**
return this.operation; * delete
} */
DELETE,
/** /**
* @see java.lang.Comparable#compareTo(T) * update
*/ */
public int compareTo(StorageEntryWrapper arg0) { UPDATE,
return arg0.timestamp == this.timestamp ? 0 /**
: (arg0.timestamp > this.timestamp ? 1 : -1); * 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;
}
}

View File

@ -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 * @author Simon Willnauer
* 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 public class StorageImplementation implements Storage {
* limitations under the License. private final StorageCoreController controller;
*/
private static final Log LOG = LogFactory
package org.apache.lucene.gdata.storage.lucenestorage; .getLog(StorageImplementation.class);
import java.io.IOException; /**
import java.util.List; * Creates a new StorageImplementation
*
import org.apache.commons.logging.Log; * @throws StorageException -
import org.apache.commons.logging.LogFactory; * if the storage controller can not be obtained
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; */
public StorageImplementation() throws StorageException {
import com.google.gdata.data.BaseEntry; this.controller = (StorageCoreController) GDataServerRegistry
import com.google.gdata.data.BaseFeed; .getRegistry().lookup(StorageController.class,
import com.google.gdata.data.ExtensionProfile; ComponentType.STORAGECONTROLLER);
import com.google.gdata.data.Feed; if (this.controller == null)
throw new StorageException("Can't get registered StorageController");
/** }
* This is an implementation of the
* {@link org.apache.lucene.gdata.storage.Storage} interface. The /**
* StorageImplementation provides access to the * @see org.apache.lucene.gdata.storage.Storage#storeEntry(org.apache.lucene.gdata.data.ServerBaseEntry)
* {@link org.apache.lucene.gdata.storage.lucenestorage.StorageQuery} and the */
* {@link org.apache.lucene.gdata.storage.lucenestorage.StorageModifier}. This public BaseEntry storeEntry(final ServerBaseEntry entry)
* class will be instanciated per client request. throws StorageException {
*
* if (entry == null)
* throw new StorageException("entry is null");
* @author Simon Willnauer StorageModifier modifier = this.controller.getStorageModifier();
* String id = this.controller.releaseID();
*/ entry.setId(entry.getFeedId() + id);
public class StorageImplementation implements Storage { if (LOG.isInfoEnabled())
private final StorageCoreController controller; LOG.info("Store entry " + id + " -- feed: " + entry.getFeedId());
private ExtensionProfile profile; try {
StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,
private static final Log LOG = LogFactory StorageOperation.INSERT);
.getLog(StorageImplementation.class); modifier.insertEntry(wrapper);
} catch (IOException e) {
/** StorageException ex = new StorageException("Can't create Entry -- "
* Creates a new StorageImplementation + e.getMessage(), e);
* ex.setStackTrace(e.getStackTrace());
* @throws StorageException - throw ex;
* if the
* {@link org.apache.lucene.gdata.storage.StorageController} can }
* not be created
* @throws IOException - return entry.getEntry();
* if the }
* {@link org.apache.lucene.gdata.storage.StorageController} can
* not be created /**
* @see StorageCoreController#getStorageCoreController() * @see org.apache.lucene.gdata.storage.Storage#deleteEntry(org.apache.lucene.gdata.data.ServerBaseEntry)
* */
*/ public void deleteEntry(final ServerBaseEntry entry)
public StorageImplementation() throws IOException, StorageException { throws StorageException {
this.controller = StorageCoreController.getStorageCoreController();
} if (entry == null)
throw new StorageException("Entry is null");
/**
* @see org.apache.lucene.gdata.storage.Storage#storeEntry(com.google.gdata.data.BaseEntry, if (LOG.isInfoEnabled())
* java.lang.String) LOG.info("delete entry " + entry.getId() + " -- feed: "
*/ + entry.getFeedId());
public BaseEntry storeEntry(BaseEntry entry, String feedId) StorageModifier modifier = this.controller.getStorageModifier();
throws StorageException { ReferenceCounter<StorageQuery> query = this.controller.getStorageQuery();
if (this.profile == null) try{
throw new StorageException( if(query.get().isEntryStored(entry.getId(),entry.getFeedId())){
"Can process ExtensionProfile not set -- is null");
if (feedId == null) modifier.deleteEntry(new StorageEntryWrapper(entry,StorageOperation.DELETE));
throw new StorageException("No feed ID specified -- is null"); }
StorageModifier modifier = this.controller.getStorageModifier(); else
String id = this.controller.releaseID(); throw new ResourceNotFoundException("Entry for entry id: "+entry.getId()+" is not stored");
entry.setId(feedId + id); }catch (IOException e) {
if (LOG.isInfoEnabled()) throw new StorageException("Can not access storage");
LOG.info("Store entry " + id + " -- feed: " + feedId); }finally{
query.decrementRef();
try { }
StorageEntryWrapper wrapper = new StorageEntryWrapper(entry, }
feedId, StorageOperation.INSERT, this.profile);
modifier.insertEntry(wrapper); /**
} catch (IOException e) { * @see org.apache.lucene.gdata.storage.Storage#updateEntry(org.apache.lucene.gdata.data.ServerBaseEntry)
StorageException ex = new StorageException("Can't create Entry -- " */
+ e.getMessage(), e); public BaseEntry updateEntry(ServerBaseEntry entry) throws StorageException {
ex.setStackTrace(e.getStackTrace());
throw ex; if (entry == null)
throw new StorageException("entry is null");
} if(entry.getId() == null)
throw new StorageException("entry id is null");
return entry; if(entry.getFeedId() == null)
} throw new StorageException("feed id is null");
if (LOG.isInfoEnabled())
/** LOG.info("update entry " + entry.getId() + " -- feed: "
* @see org.apache.lucene.gdata.storage.Storage#deleteEntry(java.lang.String, + entry.getFeedId());
* java.lang.String) StorageModifier modifier = this.controller.getStorageModifier();
*/ ReferenceCounter<StorageQuery> query = this.controller.getStorageQuery();
public void deleteEntry(String entryId, String feedId) try {
throws StorageException { StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,
if (this.profile == null) StorageOperation.UPDATE);
throw new StorageException( if(query.get().isEntryStored(entry.getId(),entry.getFeedId()))
"Can process ExtensionProfile not set -- is null"); modifier.updateEntry(wrapper);
if (feedId == null) else
throw new StorageException("No feed ID specified -- is null"); throw new ResourceNotFoundException("Entry for entry id: "+entry.getId()+" is not stored");
if (entryId == null)
throw new StorageException("No entry ID specified -- is null"); } catch (IOException e) {
if (LOG.isInfoEnabled()) LOG.error("Can't update entry for feedID: " + entry.getFeedId()
LOG.info("delete entry " + entryId + " -- feed: " + feedId); + "; entryId: " + entry.getId() + " -- " + e.getMessage(),
StorageModifier modifier = this.controller.getStorageModifier(); e);
modifier.deleteEntry(entryId, feedId); StorageException ex = new StorageException("Can't create Entry -- "
} + e.getMessage(), e);
ex.setStackTrace(e.getStackTrace());
/** throw ex;
* @see org.apache.lucene.gdata.storage.Storage#updateEntry(com.google.gdata.data.BaseEntry,
* java.lang.String) }
*/
public BaseEntry updateEntry(BaseEntry entry, String feedId) return entry.getEntry();
throws StorageException {
if (this.profile == null) }
throw new StorageException(
"Can process ExtensionProfile not set -- is null"); /**
if (feedId == null) * @see org.apache.lucene.gdata.storage.Storage#getFeed(org.apache.lucene.gdata.data.ServerBaseFeed)
throw new StorageException("No feed ID specified -- is null"); */
if (entry == null) @SuppressWarnings("unchecked")
throw new StorageException("enrty is null"); public BaseFeed getFeed(final ServerBaseFeed feed) throws StorageException {
if (entry.getId() == null)
throw new StorageException("No entry ID specified -- is null"); if (feed == null)
if (LOG.isInfoEnabled()) throw new StorageException("feed is null");
LOG.info("update entry " + entry.getId() + " -- feed: " + feedId); if (LOG.isInfoEnabled())
StorageModifier modifier = this.controller.getStorageModifier(); LOG.info("get feed: " + feed.getId() + " startindex: "
+ feed.getStartIndex() + " resultCount: "
try { + feed.getItemsPerPage());
StorageEntryWrapper wrapper = new StorageEntryWrapper(entry, ReferenceCounter<StorageQuery> query = null;
feedId, StorageOperation.UPDATE, this.profile); try {
modifier.updateEntry(wrapper); query = this.controller.getStorageQuery();
} catch (IOException e) { BaseFeed retVal = query.get().getLatestFeedQuery(feed.getId(),
LOG.error("Can't update entry for feedID: " + feedId feed.getItemsPerPage(), feed.getStartIndex(),
+ "; entryId: " + entry.getId() + " -- " + e.getMessage(), feed.getServiceConfig());
e); return retVal;
StorageException ex = new StorageException("Can't create Entry -- " } catch (Exception e) {
+ e.getMessage(), e); LOG.error("Can't get latest feed for feedID: " + feed.getId()
ex.setStackTrace(e.getStackTrace()); + " -- " + e.getMessage(), e);
throw ex; StorageException ex = new StorageException("Can't create Entry -- "
+ e.getMessage(), e);
} ex.setStackTrace(e.getStackTrace());
throw ex;
return entry;
} finally {
} if (query != null)
query.decrementRef();
/** }
* @see org.apache.lucene.gdata.storage.Storage#getFeed(java.lang.String,
* int, int) }
*/
@SuppressWarnings("unchecked") /**
public BaseFeed getFeed(String feedId, int startIndex, int resultCount) * @see org.apache.lucene.gdata.storage.Storage#getEntry(org.apache.lucene.gdata.data.ServerBaseEntry)
throws StorageException { */
if (this.profile == null) public BaseEntry getEntry(final ServerBaseEntry entry)
throw new StorageException( throws StorageException {
"Can process ExtensionProfile not set -- is null");
if (feedId == null) if (entry == null)
throw new StorageException("No feed ID specified -- is null"); throw new StorageException("No entry specified -- is null");
if (LOG.isInfoEnabled()) if (LOG.isInfoEnabled())
LOG.info("get feed: " + feedId + " startindex: " + startIndex LOG.info("get entry " + entry.getId() + " -- feed: "
+ " resultCount: " + resultCount); + entry.getFeedId());
ReferenceCounter<StorageQuery> query = null; ReferenceCounter<StorageQuery> query = null;
try { try {
query = this.controller.getStorageQuery(); query = this.controller.getStorageQuery();
List<BaseEntry> resultList = query.get().getLatestFeedQuery(feedId, BaseEntry retVal = query.get().singleEntryQuery(entry.getId(),
resultCount, startIndex, this.profile); entry.getFeedId(), entry.getServiceConfig());
BaseFeed feed = new Feed(); if(retVal == null)
feed.getEntries().addAll(resultList); throw new ResourceNotFoundException("can not get entry for entry ID "+entry.getId());
return feed; return retVal;
} catch (Exception e) { } catch (Exception e) {
LOG.error("Can't get latest feed for feedID: " + feedId + " -- " LOG.error("Can't get entry for feedID: " + entry.getFeedId()
+ e.getMessage(), e); + "; entryId: " + entry.getId() + " -- " + e.getMessage(),
StorageException ex = new StorageException("Can't create Entry -- " e);
+ e.getMessage(), e); StorageException ex = new StorageException("Can't create Entry -- "
ex.setStackTrace(e.getStackTrace()); + e.getMessage(), e);
throw ex; ex.setStackTrace(e.getStackTrace());
throw ex;
} finally {
if (query != null) } finally {
query.decrementRef(); if (query != null)
} query.decrementRef();
}
}
}
/**
* @see org.apache.lucene.gdata.storage.Storage#getEntry(java.lang.String, /**
* java.lang.String) * @see org.apache.lucene.gdata.storage.Storage#close()
*/ */
public BaseEntry getEntry(String entryId, String feedId) public void close() {
throws StorageException { //
if (this.profile == null) }
throw new StorageException(
"Can process ExtensionProfile not set -- is null"); /**
if (feedId == null) * @see org.apache.lucene.gdata.storage.Storage#storeAccount(org.apache.lucene.gdata.data.GDataAccount)
throw new StorageException("No feed ID specified -- is null"); */
if (entryId == null) public void storeAccount(GDataAccount Account) throws StorageException {
throw new StorageException("No entry ID specified -- is null"); if (Account == null)
if (LOG.isInfoEnabled()) throw new StorageException("Can not save null Account");
LOG.info("get entry " + entryId + " -- feed: " + feedId); ReferenceCounter<StorageQuery> query = null;
ReferenceCounter<StorageQuery> query = null; try {
try { query = this.controller.getStorageQuery();
query = this.controller.getStorageQuery(); if (query.get().getUser(Account.getName()) != null)
return query.get().singleEntryQuery(entryId, feedId, this.profile); throw new StorageException("Account already exists");
} catch (Exception e) { StorageModifier modifier = this.controller.getStorageModifier();
LOG.error("Can't get entry for feedID: " + feedId + "; entryId: " StorageAccountWrapper wrapper = new StorageAccountWrapper(Account);
+ entryId + " -- " + e.getMessage(), e); modifier.createAccount(wrapper);
StorageException ex = new StorageException("Can't create Entry -- " } catch (Exception e) {
+ e.getMessage(), e); LOG.error("Can't save Account -- " + e.getMessage(), e);
ex.setStackTrace(e.getStackTrace()); StorageException ex = new StorageException("Can't save Account -- "
throw ex; + e.getMessage(), e);
ex.setStackTrace(e.getStackTrace());
} finally { throw ex;
if (query != null)
query.decrementRef(); } finally {
} if (query != null)
query.decrementRef();
} }
}
/**
* @see org.apache.lucene.gdata.storage.Storage#getEntries(java.util.List, /**
* java.lang.String) * @see org.apache.lucene.gdata.storage.Storage#updateAccount(org.apache.lucene.gdata.data.GDataAccount)
*/ */
public List<BaseEntry> getEntries(List<String> entryIdList, String feedId) public void updateAccount(GDataAccount Account) throws StorageException {
throws StorageException { if (Account == null)
throw new StorageException("not implemented yet"); throw new StorageException("Can not update null Account");
// TODO implement this ReferenceCounter<StorageQuery> query = null;
try {
} query = this.controller.getStorageQuery();
if (query.get().getUser(Account.getName()) == null)
/** throw new StorageException("Account does not exist");
* @see org.apache.lucene.gdata.storage.Storage#close() StorageModifier modifier = this.controller.getStorageModifier();
*/ StorageAccountWrapper wrapper = new StorageAccountWrapper(Account);
public void close() { 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);
* @see org.apache.lucene.gdata.storage.Storage#setExtensionProfile(com.google.gdata.data.ExtensionProfile) ex.setStackTrace(e.getStackTrace());
*/ throw ex;
public void setExtensionProfile(ExtensionProfile profile) {
this.profile = profile; } 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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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();
}
}
}

View File

@ -1,236 +1,445 @@
package org.apache.lucene.gdata.storage.lucenestorage; package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.ArrayList;
import java.util.HashMap; import java.util.Collection;
import java.util.LinkedList; import java.util.HashMap;
import java.util.List; import java.util.LinkedList;
import java.util.Map; import java.util.List;
import java.util.concurrent.locks.Lock; import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock; 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.commons.logging.Log;
import org.apache.lucene.document.Document; import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.storage.StorageException; import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexModifier; import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.index.Term; import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
import org.apache.lucene.index.IndexModifier;
/** import org.apache.lucene.index.Term;
* TODO document this
* @author Simon Willnauer /**
* 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.
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* *
*/ * @author Simon Willnauer
public class StorageModifier { *
protected static final Log LOG = LogFactory.getLog(StorageModifier.class); */
public class StorageModifier {
private final List<Term> deletedDocumentQueue; protected static final Log LOG = LogFactory.getLog(StorageModifier.class);
private final List<Term> deletedForUpdateDocumentQueue;
private final List<Term> deletedDocumentQueue;
private final Map<String,Document> documentMap;
private final List<Term> deletedForUpdateDocumentQueue;
private volatile int persistFactor; private final Map<String, Document> documentMap;
private volatile int modifiedCounter = 0; private final List<Document> forceWriteDocuments;
private static int DEFAULT_PERSIST_FACTOR = 10; private final List<Term> forceWriteTerms;
private StorageBuffer buffer; private volatile int persistFactor;
private IndexModifier modifier; private volatile int modifiedCounter = 0;
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false); private static int DEFAULT_PERSIST_FACTOR = 10;
private Lock readLock = this.lock.readLock(); private StorageBuffer buffer;
private Lock writeLock = this.lock.writeLock(); private IndexModifier modifier;
private final static int DEFAULT_OPTIMIZE_INTERVAL = 10;
private final int optimizeInterval; private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false);
private int optimizeCounter = 0;
private Lock readLock = this.lock.readLock();
/**
* TODO document this private Lock writeLock = this.lock.writeLock();
* @param modifier
* @param buffer private final static int DEFAULT_OPTIMIZE_INTERVAL = 10;
* @param persitsFactor
* @param optimizeInterval private final int optimizeInterval;
*/
public StorageModifier(final IndexModifier modifier, private volatile int optimizeCounter = 0;
final StorageBuffer buffer, int persitsFactor,int optimizeInterval) {
this.deletedDocumentQueue = new LinkedList<Term>(); private final StorageCoreController controller;
this.deletedForUpdateDocumentQueue = new LinkedList<Term>();
this.documentMap = new HashMap<String,Document>(persitsFactor); /**
this.buffer = buffer; * Creates a new StorageModifier
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
* *
*/ * @param controller -
public void deleteEntry(final String entryId, final String feedId) throws StorageException { * the registered StorageController
try { * @param modifier -
this.readLock.lock(); * the IndexModifier
Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID, entryId); * @param buffer -
this.buffer.addDeleted(entryId, feedId); * the StorageBuffer
this.deletedDocumentQueue.add(tempTerm); * @param persitsFactor -
storageModified(); * the factor when the changes will be persisted to the storage
} finally { * index
this.readLock.unlock(); * @param optimizeInterval -
} * after how many storage operations the index will be optimized
} */
protected StorageModifier(final StorageCoreController controller,
private void storageModified() throws StorageException { final IndexModifier modifier, final StorageBuffer buffer,
this.readLock.unlock(); int persitsFactor, int optimizeInterval) {
this.writeLock.lock(); this.deletedDocumentQueue = new LinkedList<Term>();
this.deletedForUpdateDocumentQueue = new LinkedList<Term>();
try { this.documentMap = new HashMap<String, Document>(persitsFactor);
incrementCounter(); this.forceWriteDocuments = new ArrayList<Document>(5);
if (this.persistFactor > this.modifiedCounter) this.forceWriteTerms = new ArrayList<Term>(5);
return; this.buffer = buffer;
this.controller = controller;
if (LOG.isInfoEnabled())
LOG.info("Storage modified for " + this.modifiedCounter this.persistFactor = persitsFactor > 0 ? persitsFactor
+ " times. Write Persistent index"); : DEFAULT_PERSIST_FACTOR;
writePersistentIndex((this.optimizeCounter >= this.optimizeInterval)); this.modifier = modifier;
requestNewIndexModifier(); this.optimizeInterval = optimizeInterval < DEFAULT_OPTIMIZE_INTERVAL ? DEFAULT_OPTIMIZE_INTERVAL
: optimizeInterval;
this.modifiedCounter = 0;
} catch (IOException e) { }
LOG.error("Writing persistent index failed - Recovering", e);
} finally { /**
this.readLock.lock(); * Updates the given entry. First the alredy persisted entry will be
this.writeLock.unlock(); * removed, after marking as deleted the new Entry will be written.
} *
* @param wrapper -
} * the wrapper containing the entry
* @throws StorageException -
protected void forceWrite() throws IOException, StorageException { * if the entry can not be stored
this.writeLock.lock(); */
try { public void updateEntry(StorageEntryWrapper wrapper)
if (LOG.isInfoEnabled()) throws StorageException {
LOG.info("ForceWrite called -- current modifiedCounter: " if(wrapper.getOperation() != StorageOperation.UPDATE)
+ this.modifiedCounter + " - persisting changes"); throw new StorageException("Illegal method call -- updateEntry does not accept other storageOperations than update");
writePersistentIndex(true); this.readLock.lock();
requestNewIndexModifier(); try {
this.modifiedCounter = 0; Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID,
} finally { wrapper.getEntryId());
this.writeLock.unlock(); this.documentMap.put(wrapper.getEntryId(), wrapper
} .getLuceneDocument());
} this.deletedForUpdateDocumentQueue.add(tempTerm);
this.buffer.addEntry(wrapper);
private void requestNewIndexModifier() throws IOException, StorageException { storageModified();
StorageCoreController controller = StorageCoreController } finally {
.getStorageCoreController(); this.readLock.unlock();
controller.registerNewStorageQuery(); }
this.buffer = controller.releaseNewStorageBuffer(); }
this.modifier = controller.createIndexModifier();
} /**
* Inserts a new Entry to the Lucene index storage
private void writePersistentIndex(final boolean optimize) throws IOException { *
try { * @param wrapper -
/* * the wrapper containing the entry
* first delete all updated documents * @throws StorageException -
*/ * if the entry can not be stored
for(Term entryIdTerm : this.deletedForUpdateDocumentQueue) { */
this.modifier.deleteDocuments(entryIdTerm); public void insertEntry(StorageEntryWrapper wrapper)
} throws StorageException {
/* if(wrapper.getOperation() != StorageOperation.INSERT)
* add all documents throw new StorageException("Illegal method call -- insertEntry does not accept other storage operations than insert");
*/ this.readLock.lock();
Collection<Document> documents = this.documentMap.values(); try {
for (Document doc : documents) { this.documentMap.put(wrapper.getEntryId(), wrapper
this.modifier.addDocument(doc); .getLuceneDocument());
} this.buffer.addEntry(wrapper);
/* storageModified();
* delete all documents marked as deleted. As the DocumentIDs are } finally {
* unique the document marked as deleted must not persist after the this.readLock.unlock();
* 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) { * Deletes the entry for the given entry id.
this.modifier.deleteDocuments(entryIdTerm); * @param wrapper - the wrapper containing the information to delete
} *
this.modifier.flush(); * @throws StorageException -
if(optimize){ * if the entry can not be deleted
if(LOG.isInfoEnabled()) *
LOG.info("Optimizing index -- optimize interval "+this.optimizeInterval); */
this.modifier.optimize(); public void deleteEntry(final StorageEntryWrapper wrapper)
} throws StorageException {
if(wrapper.getOperation() != StorageOperation.DELETE)
} finally { throw new StorageException("Illegal method call -- insertEntry does not accept other storage operations than delete");
if(optimize) this.readLock.lock();
this.optimizeCounter = 0; try {
this.modifier.close(); Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID,
this.deletedForUpdateDocumentQueue.clear(); wrapper.getEntryId());
this.deletedDocumentQueue.clear(); this.deletedDocumentQueue.add(tempTerm);
this.documentMap.clear(); this.buffer.addDeleted(wrapper.getEntryId(), wrapper.getFeedId());
} storageModified();
} } finally {
this.readLock.unlock();
protected void close()throws IOException{ }
this.writeLock.lock(); }
try {
if (LOG.isInfoEnabled()) /**
LOG.info("ForceWrite called -- current modifiedCounter: " * Adds a new Feed to the storage. Feed action will be not buffered. Call to
+ this.modifiedCounter + " - persisting changes"); * this method forces the index to be written.
*
writePersistentIndex(true); * @param wrapper -
this.modifiedCounter = 0; * the wrapper containing the feed;
} finally { * @throws StorageException -
this.writeLock.unlock(); * if the feed can not be written
} */
} public void createFeed(StorageFeedWrapper wrapper) throws StorageException {
this.readLock.lock();
private void incrementCounter(){ try {
this.optimizeCounter++; this.forceWriteDocuments.add(wrapper.getLuceneDocument());
this.modifiedCounter++; 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<Document> 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++;
}
}

View File

@ -12,331 +12,481 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.lucene.gdata.storage.lucenestorage; package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.apache.lucene.document.Document; import org.apache.commons.logging.Log;
import org.apache.lucene.gdata.server.FeedNotFoundException; import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.server.GDataEntityBuilder; import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term; import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.search.BooleanClause; import org.apache.lucene.gdata.server.GDataEntityBuilder;
import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.search.Hit; import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.search.Hits; import org.apache.lucene.index.Term;
import org.apache.lucene.search.Searcher; import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.Sort; import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.SortField; import org.apache.lucene.search.Hit;
import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.Hits;
import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.Sort;
import com.google.gdata.data.BaseEntry; import org.apache.lucene.search.SortField;
import com.google.gdata.data.ExtensionProfile; import org.apache.lucene.search.TermQuery;
import com.google.gdata.util.ParseException; import org.apache.lucene.search.BooleanClause.Occur;
/** import com.google.gdata.data.BaseEntry;
* StorageQuery wrapps a Lucene {@link org.apache.lucene.search.IndexSearcher} import com.google.gdata.data.BaseFeed;
* and a {@link org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer} to import com.google.gdata.data.DateTime;
* perform all request on the lucene storage. import com.google.gdata.util.ParseException;
* The wrapped components are thread - safe.
* <p> /**
* An instance of this class will serve all client requests. To obtain the * StorageQuery wrapps a Lucene {@link org.apache.lucene.search.IndexSearcher}
* current instance of the {@link StorageQuery} the method * and a {@link org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer} to
* {@link org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#getStorageQuery()} * perform all request on the lucene storage. The wrapped components are thread -
* has to be invoked. This method will release the current StorageQuery. * safe.
* </p> * <p>
* @see org.apache.lucene.search.IndexSearcher * An instance of this class will serve all client requests. To obtain the
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController * current instance of the {@link StorageQuery} the method
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#getStorageQuery()}
* * has to be invoked. This method will release the current StorageQuery.
* @author Simon Willnauer * </p>
* *
*/ * @see org.apache.lucene.search.IndexSearcher
public class StorageQuery { * @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController
private final StorageBuffer buffer; * @see org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer
*
private final Searcher searcher; * @author Simon Willnauer
*
/* */
* Sort the result by timestamp desc public class StorageQuery {
*/ private static final Log LOG = LogFactory.getLog(StorageQuery.class);
private final Sort timeStampSort = new Sort(new SortField(StorageEntryWrapper.FIELD_TIMESTAMP, private final StorageBuffer buffer;
SortField.STRING, true));
private final Searcher searcher;
/**
* Creates a new StorageQuery /*
* * Sort the result by timestamp desc
* @param buffer - */
* the buffer instance to get the buffered inserts, updates from. private final Sort timeStampSort = new Sort(new SortField(
* @param searcher - StorageEntryWrapper.FIELD_TIMESTAMP, SortField.STRING, true));
* the searcher instance to use to query the storage index.
* /**
* * Creates a new StorageQuery
*/ *
protected StorageQuery(final StorageBuffer buffer, final Searcher searcher) { * @param buffer -
* the buffer instance to get the buffered inserts, updates from.
this.buffer = buffer; * @param searcher -
this.searcher = searcher; * the searcher instance to use to query the storage index.
*
} *
*/
private Hits storageQuery(List<String> entryId) throws IOException { protected StorageQuery(final StorageBuffer buffer, final Searcher searcher) {
BooleanQuery query = new BooleanQuery();
/* this.buffer = buffer;
* query the index using a BooleanQuery this.searcher = searcher;
*/
for (String id : entryId) { }
TermQuery termQuery = new TermQuery(new Term(
StorageEntryWrapper.FIELD_ENTRY_ID, id)); private Hits storageQuery(List<String> entryId) throws IOException {
// use an OR query BooleanQuery query = new BooleanQuery();
query.add(new BooleanClause(termQuery, Occur.SHOULD)); /*
} * query the index using a BooleanQuery
*/
return this.searcher.search(query, new ModifiedEntryFilter(this.buffer for (String id : entryId) {
.getExculdList())); TermQuery termQuery = new TermQuery(new Term(
} StorageEntryWrapper.FIELD_ENTRY_ID, id));
// use an OR query
/* query.add(new BooleanClause(termQuery, Occur.SHOULD));
* query the storage index for a entire feed. }
*/
private Hits storageFeedQuery(final String feedId, final Sort sort) return this.searcher.search(query, new ModifiedEntryFilter(this.buffer
throws IOException { .getExculdList()));
TermQuery query = new TermQuery(new Term(StorageEntryWrapper.FIELD_FEED_ID, feedId)); }
return this.searcher.search(query, new ModifiedEntryFilter(this.buffer
.getExculdList()), sort); /*
* query the storage index for a entire feed.
} */
private Hits storageFeedQuery(final String feedId, final Sort sort)
/* throws IOException {
* get a single entry TermQuery query = new TermQuery(new Term(
*/ StorageEntryWrapper.FIELD_FEED_REFERENCE, feedId));
private Hits storageQuery(String entryId) throws IOException { return this.searcher.search(query, new ModifiedEntryFilter(this.buffer
TermQuery termQuery = new TermQuery(new Term( .getExculdList()), sort);
StorageEntryWrapper.FIELD_ENTRY_ID, entryId));
/* }
* Filter entries inside the buffer, buffered entries might contain
* deleted entries. These entries must be found!! /*
*/ * get a single entry
return this.searcher.search(termQuery, new ModifiedEntryFilter( */
this.buffer.getExculdList())); 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
* This method fetches the latest feed entries from the storage. Feed * deleted entries. These entries must be found!!
* ususaly requested via a search query or as a simple query to the REST */
* interface. return this.searcher.search(termQuery, new ModifiedEntryFilter(
* <p> this.buffer.getExculdList()));
* 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, * This method fetches the latest feed entries from the storage. Feed
* the underlaying lucene index will be searcher for all documents of the * ususaly requested via a search query or as a simple query to the REST
* specified feed sorted by storing timestamp desc. * interface.
* </p> * <p>
* <p> * The REST interface requestes all the entries from a Storage. The Storage
* The entries will be searched in a feed context specified by the given * retrieves the entries corresponding to the parameters specified. This
* feed ID * method first requests the latest entries or updated entries from the
* </p> * {@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
* @param feedId - * specified feed sorted by storing timestamp desc.
* the requested feed, this id will be used to retrieve the * </p>
* entries. * <p>
* @param resultCount - * The entries will be searched in a feed context specified by the given
* how many entries are requested * feed ID
* @param startIndex - * </p>
* the offset of the entriy to start from. *
* @param profil - *
* the extension profile used to create the entriy instances * @param feedId -
* @return - an ordered list of {@link BaseEntry} objects, or an empty list * the requested feed, this id will be used to retrieve the
* if no entries could be found * entries.
* @throws IOException - * @param resultCount -
* if the index could not be queries or the entries could not be * how many entries are requested
* build * @param startIndex -
* @throws FeedNotFoundException - * the offset of the entriy to start from.
* if the requested feed is not registered * @param config -
* @throws ParseException - * the FeedInstanceConfiguration contaning extension profile used
* if an entry could not be parsed while building it from the * to create the entriy instances
* Lucene Document. * @return - an ordered list of {@link BaseEntry} objects, or an empty list
*/ * if no entries could be found
// TODO check input parameter * @throws IOException -
public List<BaseEntry> getLatestFeedQuery(final String feedId, * if the index could not be queries or the entries could not be
final int resultCount, final int startIndex, * build
final ExtensionProfile profil) throws IOException, * @throws ParseException -
FeedNotFoundException, ParseException { * if an entry could not be parsed while building it from the
List<BaseEntry> returnList = new ArrayList<BaseEntry>(resultCount); * Lucene Document.
List<StorageEntryWrapper> bufferedWrapperList = this.buffer */
.getSortedEntries(feedId); // TODO check input parameter
int alreadyAdded = 0; @SuppressWarnings("unchecked")
int offset = startIndex - 1; public BaseFeed getLatestFeedQuery(final String feedId,
if (bufferedWrapperList != null final int resultCount, final int startIndex,
&& bufferedWrapperList.size() >= startIndex) { final ProvidedService config) throws IOException,
ParseException {
for (; alreadyAdded < resultCount; alreadyAdded++) { DateTime updated = null;
if ((bufferedWrapperList.size() - offset) > 0) { Hits feedHits = storageFeedQuery(feedId);
StorageEntryWrapper wrappedEntry = bufferedWrapperList if(feedHits.length() == 0)
.get(offset++); return null;
returnList.add(wrappedEntry.getEntry()); BaseFeed retVal = buildFeedFromLuceneDocument(feedHits.doc(0),config);
} else
break; List<BaseEntry> returnList = new ArrayList<BaseEntry>(resultCount);
} List<StorageEntryWrapper> bufferedWrapperList = this.buffer
// reset offset .getSortedEntries(feedId);
offset = startIndex - 1; int alreadyAdded = 0;
if (alreadyAdded == resultCount) int offset = startIndex - 1;
return returnList;
} else { if (bufferedWrapperList != null
/* && bufferedWrapperList.size() >= startIndex) {
* if the buffersize is less than the startindex the buffersize must updated = bufferedWrapperList.get(0).getEntry().getUpdated();
* be considered. Sublists would not be a repeatable read part of for (; alreadyAdded < resultCount; alreadyAdded++) {
* the whole list if ((bufferedWrapperList.size() - offset) > 0) {
*/ StorageEntryWrapper wrappedEntry = bufferedWrapperList
if (bufferedWrapperList != null) .get(offset++);
offset = startIndex - 1 - bufferedWrapperList.size(); returnList
} .add(wrappedEntry.getEntry());
} else
Hits hits = storageFeedQuery(feedId, this.timeStampSort); break;
if (hits.length() > 0) { }
// reset offset
for (; (offset < hits.length()) && (alreadyAdded < resultCount); offset++, alreadyAdded++) { offset = startIndex - 1;
Document doc = hits.doc(offset); if (alreadyAdded == resultCount){
BaseEntry entry = buildEntryFromLuceneDocument(doc, profil); retVal.getEntries().addAll(returnList);
returnList.add(entry); retVal.setUpdated(updated);
} return retVal;
}
} } else {
return returnList; /*
} * 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
* This method retrieves a single entry from the storage. If the */
* {@link StorageBuffer} does not contain the requested entry the if (bufferedWrapperList != null)
* underlaying storage index will be searched. offset = startIndex - 1 - bufferedWrapperList.size();
* <p> }
* The Entry will be searched in a feed context specified by the given feed
* ID Hits hits = storageFeedQuery(feedId, this.timeStampSort);
* </p> if (hits.length() > 0) {
*
* @param entryId - for (; (offset < hits.length()) && (alreadyAdded < resultCount); offset++, alreadyAdded++) {
* the entry to fetch Document doc = hits.doc(offset);
* @param feedId - BaseEntry entry = buildEntryFromLuceneDocument(doc, config);
* the feedid eg. feed context returnList.add(entry);
* @param profil - }
* the extension profile used to create the entriy instances if(updated == null){
* @return - the requested {@link BaseEntry} or <code>null</code> if the try{
* entry can not be found long updatedTimeStamp = Long.parseLong(hits.doc(0).get(StorageEntryWrapper.FIELD_TIMESTAMP));
* @throws IOException - updated = new DateTime(updatedTimeStamp);
* if the index could not be queries or the entries could not be }catch (Exception e) {
* build LOG.warn("could not create DateTime -- "+e.getMessage(),e);
* @throws FeedNotFoundException - updated = buildEntryFromLuceneDocument(hits.doc(0),config).getUpdated();
* if the requested feed is not registered }
* @throws ParseException - }
* if an entry could not be parsed while building it from the }
* Lucene Document. retVal.setUpdated(updated);
*/ retVal.getEntries().addAll(returnList);
public BaseEntry singleEntryQuery(final String entryId, return retVal;
final String feedId, final ExtensionProfile profil) }
throws IOException, FeedNotFoundException, ParseException {
StorageEntryWrapper wrapper = this.buffer.getEntry(entryId, feedId); /**
* This method retrieves a single entry from the storage. If the
if (wrapper == null) { * {@link StorageBuffer} does not contain the requested entry the
Hits hits = storageQuery(entryId); * underlaying storage index will be searched.
if (hits.length() <= 0) * <p>
return null; * The Entry will be searched in a feed context specified by the given feed
Document doc = hits.doc(0); * ID
* </p>
return buildEntryFromLuceneDocument(doc, profil); *
} * @param entryId -
return wrapper.getEntry(); * the entry to fetch
* @param feedId -
} * the feedid eg. feed context
* @param config -
/** * the FeedInstanceConfiguration contaning extension profile used
* Fetches the requested entries from the storage. The given list contains * to create the entriy instances
* entry ids to be looked up in the storage. First the {@link StorageBuffer} * @return - the requested {@link BaseEntry} or <code>null</code> if the
* will be queried for the entry ids. If not all of the entries remain in * entry can not be found
* the buffer the underlaying lucene index will be searched. The entries are * @throws IOException -
* not guaranteed to be in the same order as they are in the given id list. * if the index could not be queries or the entries could not be
* Entry ID's not found in the index or the buffer will be omitted. * build
* <p> * @throws ParseException -
* The entries will be searched in a feed context specified by the given * if an entry could not be parsed while building it from the
* feed ID * Lucene Document.
* </p> */
* public BaseEntry singleEntryQuery(final String entryId,
* @param entryIds - final String feedId, final ProvidedService config)
* the entriy ids to fetch. throws IOException, ParseException {
* @param feedId - StorageEntryWrapper wrapper = this.buffer.getEntry(entryId, feedId);
* the feed id eg. feed context.
* @param profil - if (wrapper == null) {
* the extension profile used to create the entry instances. Hits hits = storageQuery(entryId);
* @return - the list of entries corresponding to the given entry id list. if (hits.length() <= 0)
* @throws IOException - return null;
* if the index could not be queries or the entries could not be Document doc = hits.doc(0);
* build
* @throws FeedNotFoundException - return buildEntryFromLuceneDocument(doc, config);
* if the requested feed is not registered }
* @throws ParseException - /*
* if an entry could not be parsed while building it from the * ServerBaseEntry enables the dynamic element of the entry like the
* Lucene Document. * links to be dynamic. BufferedEntries will be reused until they are
*/ * written.
public List<BaseEntry> entryQuery(List<String> entryIds, */
final String feedId, final ExtensionProfile profil) return wrapper.getEntry();
throws IOException, FeedNotFoundException, ParseException {
List<BaseEntry> resultList = new ArrayList<BaseEntry>(entryIds.size()); }
List<String> searchList = new ArrayList<String>(entryIds.size());
for (String entry : entryIds) { /**
* Fetches the requested entries from the storage. The given list contains
StorageEntryWrapper bufferedEntry = this.buffer.getEntry(entry, * entry ids to be looked up in the storage. First the {@link StorageBuffer}
feedId); * will be queried for the entry ids. If not all of the entries remain in
if (bufferedEntry != null) { * the buffer the underlaying lucene index will be searched. The entries are
resultList.add(bufferedEntry.getEntry()); * not guaranteed to be in the same order as they are in the given id list.
} else * Entry ID's not found in the index or the buffer will be omitted.
searchList.add(entry); * <p>
} * The entries will be searched in a feed context specified by the given
if (searchList.isEmpty()) * feed ID
return resultList; * </p>
*
Hits hits = storageQuery(searchList); * @param entryIds -
Iterator hitIterator = hits.iterator(); * the entriy ids to fetch.
while (hitIterator.hasNext()) { * @param feedId -
Hit hit = (Hit) hitIterator.next(); * the feed id eg. feed context.
Document doc = hit.getDocument(); * @param config -
BaseEntry entry = buildEntryFromLuceneDocument(doc, profil); * the FeedInstanceConfiguration contaning extension profile used
resultList.add(entry); * to create the entriy instances
*
} * @return - the list of entries corresponding to the given entry id list.
* @throws IOException -
return resultList; * 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
private BaseEntry buildEntryFromLuceneDocument(final Document doc, * Lucene Document.
final ExtensionProfile profil) throws FeedNotFoundException, */
ParseException, IOException { public List<BaseEntry> entryQuery(List<String> entryIds,
StringReader reader = new StringReader(doc.getField(StorageEntryWrapper.FIELD_CONTENT) final String feedId, final ProvidedService config)
.stringValue()); throws IOException, ParseException {
return GDataEntityBuilder.buildEntry(doc.getField(StorageEntryWrapper.FIELD_FEED_ID) List<BaseEntry> resultList = new ArrayList<BaseEntry>(entryIds.size());
.stringValue(), reader, profil); List<String> searchList = new ArrayList<String>(entryIds.size());
for (String entry : entryIds) {
}
StorageEntryWrapper bufferedEntry = this.buffer.getEntry(entry,
/** feedId);
* Closes all resources used in the {@link StorageQuery}. The instance can if (bufferedEntry != null) {
* not be reused after invoking this method. resultList.add(bufferedEntry.getEntry());
* } else
* @throws IOException - searchList.add(entry);
* if the resouces can not be closed }
*/ if (searchList.isEmpty())
public void close() throws IOException { return resultList;
this.searcher.close();
this.buffer.close(); 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 <code>null</code> 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 <code>true</code> if and only if a feed is stored for the provided feed ID, <code>false</code> 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 <code>null</code> 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;
}
}

View File

@ -37,7 +37,8 @@ public class StorageConfigurator {
private final boolean keepRecoveredFiles; private final boolean keepRecoveredFiles;
private final boolean recover; private final boolean recover;
private final boolean ramDirectory;
private static StorageConfigurator INSTANCE = null; private static StorageConfigurator INSTANCE = null;
private final int indexOptimizeInterval; private final int indexOptimizeInterval;
@ -64,7 +65,8 @@ public class StorageConfigurator {
.getProperty("gdata.server.storage.lucene.directory"); .getProperty("gdata.server.storage.lucene.directory");
this.indexOptimizeInterval = Integer.parseInt(properties this.indexOptimizeInterval = Integer.parseInt(properties
.getProperty("gdata.server.storage.lucene.optimizeInterval")); .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() { public int getIndexOptimizeInterval() {
return this.indexOptimizeInterval; return this.indexOptimizeInterval;
}
/**
* @return Returns the ramDirectory.
*/
public boolean isRamDirectory() {
return this.ramDirectory;
} }
} }

View File

@ -15,18 +15,18 @@
*/ */
package org.apache.lucene.gdata.server; package org.apache.lucene.gdata.server;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType; import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType;
import org.apache.lucene.gdata.server.GDataRequest.OutputFormat; 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.apache.lucene.gdata.server.registry.GDataServerRegistry; import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.easymock.MockControl; import org.apache.lucene.gdata.server.registry.RegistryException;
import org.apache.lucene.gdata.utils.ProvidedServiceStub;
import com.google.gdata.data.ExtensionProfile; import org.apache.lucene.gdata.utils.StorageStub;
import com.google.gdata.data.Feed; import org.easymock.MockControl;
/** /**
* *
@ -39,14 +39,21 @@ public class TestGDataRequest extends TestCase {
private MockControl control; private MockControl control;
private GDataRequest feedRequest; private GDataRequest feedRequest;
static{
try {
GDataServerRegistry.getRegistry().registerComponent(StorageStub.class);
} catch (RegistryException e) {
e.printStackTrace();
}
}
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
FeedInstanceConfigurator configurator = new FeedInstanceConfigurator(); ProvidedService configurator = new ProvidedServiceStub();
configurator.setFeedType(Feed.class); GDataServerRegistry.getRegistry().registerService(configurator);
configurator.setFeedId("feed");
configurator.setExtensionProfileClass(ExtensionProfile.class);
GDataServerRegistry.getRegistry().registerFeed(configurator);
this.control = MockControl.createControl(HttpServletRequest.class); this.control = MockControl.createControl(HttpServletRequest.class);
this.request = (HttpServletRequest) this.control.getMock(); this.request = (HttpServletRequest) this.control.getMock();
this.feedRequest = new GDataRequest(this.request,GDataRequestType.GET); this.feedRequest = new GDataRequest(this.request,GDataRequestType.GET);
@ -216,7 +223,7 @@ public class TestGDataRequest extends TestCase {
public void testGetSelfId() throws GDataRequestException{ public void testGetSelfId() throws GDataRequestException{
String host = "www.apache.org"; String host = "www.apache.org";
String feedAndEntryID = "/feed/entryid"; 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.getHeader("Host"),host);
this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed/entryId/15"); this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed/entryId/15");
this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15"); this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15");
@ -227,13 +234,13 @@ public class TestGDataRequest extends TestCase {
queryString); queryString);
this.control.replay(); this.control.replay();
this.feedRequest.initializeRequest(); 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()); assertEquals("Self ID",selfID,this.feedRequest.getSelfId());
this.control.reset(); 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.getHeader("Host"),host);
this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed/entryId/15"); this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed/entryId/15");
this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15"); this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15");
@ -244,7 +251,7 @@ public class TestGDataRequest extends TestCase {
queryString); queryString);
this.control.replay(); this.control.replay();
this.feedRequest.initializeRequest(); 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()); assertEquals("Self ID",selfID,this.feedRequest.getSelfId());
this.control.reset(); this.control.reset();
@ -296,7 +303,7 @@ public class TestGDataRequest extends TestCase {
queryString); queryString);
this.control.replay(); this.control.replay();
assertEquals("?"+maxResults,this.feedRequest.getQueryString()); assertEquals(maxResults,this.feedRequest.getQueryString());
this.control.reset(); 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{ public void testGetNextId() throws GDataRequestException{
@ -352,7 +363,8 @@ public class TestGDataRequest extends TestCase {
// String queryString = "?max-results=25"; // String queryString = "?max-results=25";
// String startIndex = "&start-index=26"; // String startIndex = "&start-index=26";
// this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host); // 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("max-results"),"25",2);
// this.control.expectAndReturn(this.request.getParameter("start-index"),null); // this.control.expectAndReturn(this.request.getParameter("start-index"),null);
// this.control.expectAndDefaultReturn(this.request.getParameter("alt"), // this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
@ -361,22 +373,27 @@ public class TestGDataRequest extends TestCase {
// queryString); // queryString);
// this.control.replay(); // this.control.replay();
// this.feedRequest.initializeRequest(); // this.feedRequest.initializeRequest();
// String nextID = "http://"+host+"/feed"+queryString+startIndex; // String nextID = "http://"+host+"/feed/"+queryString+startIndex;
// //
// assertEquals("Next ID",nextID,this.feedRequest.getNextId()); // assertEquals("Next ID",nextID,this.feedRequest.getNextId());
// this.control.reset(); // 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.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("max-results"),"25",2);
// this.control.expectAndReturn(this.request.getParameter("start-index"),"26",2); // this.control.expectAndReturn(this.request.getParameter("start-index"),"26",2);
// this.control.expectAndDefaultReturn(this.request.getParameter("alt"), // this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
// null); // null);
// this.control.expectAndDefaultReturn(this.request.getQueryString(), // this.control.expectAndDefaultReturn(this.request.getQueryString(),
// queryString+startIndex); // queryString+startIndex);
// Enumeration e =
// this.control.expectAndDefaultReturn(this.request.getParameterNames(),)
//
//
// this.control.replay(); // this.control.replay();
// this.feedRequest.initializeRequest(); // this.feedRequest.initializeRequest();
// startIndex = "&start-index=51"; // startIndex = "&start-index=51";
@ -395,7 +412,7 @@ public class TestGDataRequest extends TestCase {
// null); // null);
// this.control.replay(); // this.control.replay();
// this.feedRequest.initializeRequest(); // 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()); // assertEquals("Self ID",selfID,this.feedRequest.getSelfId());
// this.control.reset(); // this.control.reset();

View File

@ -70,12 +70,12 @@ public class TestGDataResponse extends TestCase {
StringWriter stringWriter = new StringWriter(); StringWriter stringWriter = new StringWriter();
PrintWriter writer = new PrintWriter(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.response.setOutputFormat(OutputFormat.ATOM);
this.control.replay(); this.control.replay();
this.response.sendResponse(createFeed(),new ExtensionProfile this.response.sendResponse(createFeed(),new ExtensionProfile());
());
assertEquals("Simple XML representation",stringWriter.toString(),generatedFeedAtom); assertEquals("Simple XML representation",stringWriter.toString(),generatedFeedAtom);
this.control.reset(); this.control.reset();
@ -84,6 +84,7 @@ public class TestGDataResponse extends TestCase {
this.control.expectAndReturn(this.httpResponse.getWriter(),writer); this.control.expectAndReturn(this.httpResponse.getWriter(),writer);
this.response.setOutputFormat(OutputFormat.RSS); this.response.setOutputFormat(OutputFormat.RSS);
this.httpResponse.setContentType(GDataResponse.XMLMIME_RSS);
this.control.replay(); this.control.replay();
this.response.sendResponse(createFeed(),new ExtensionProfile this.response.sendResponse(createFeed(),new ExtensionProfile

View File

@ -1,98 +1,132 @@
/** /**
* Copyright 2004 The Apache Software Foundation * Copyright 2004 The Apache Software Foundation
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.lucene.gdata.server.registry; package org.apache.lucene.gdata.server.registry;
import com.google.gdata.data.Feed; import org.apache.lucene.gdata.server.ServiceFactory;
import org.apache.lucene.gdata.servlet.handler.DefaultRequestHandlerFactory;
import junit.framework.TestCase; import org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory;
import org.apache.lucene.gdata.storage.StorageController;
/** import org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController;
* @author Simon Willnauer
* import com.google.gdata.data.Entry;
*/ import com.google.gdata.data.Feed;
public class TestFeedRegistry extends TestCase {
private GDataServerRegistry reg; import junit.framework.TestCase;
private FeedInstanceConfigurator configurator;
@Override /**
protected void setUp(){ * @author Simon Willnauer
this.reg = GDataServerRegistry.getRegistry(); *
this.configurator = new FeedInstanceConfigurator(); */
} public class TestFeedRegistry extends TestCase {
/** private GDataServerRegistry reg;
* @see junit.framework.TestCase#tearDown() private ProvidedServiceConfig configurator;
*/ @Override
@Override protected void setUp(){
protected void tearDown() throws Exception { this.reg = GDataServerRegistry.getRegistry();
this.reg.flushRegistry(); this.configurator = new ProvidedServiceConfig();
} this.configurator.setEntryType(Entry.class);
/** this.configurator.setFeedType(Feed.class);
* Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getRegistry()' }
*/ /**
public void testGetRegistry() { * @see junit.framework.TestCase#tearDown()
*/
GDataServerRegistry reg1 = GDataServerRegistry.getRegistry(); @Override
assertEquals("test singleton",this.reg,reg1); protected void tearDown() throws Exception {
} this.reg.flushRegistry();
}
/** /**
* Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.registerFeed(FeedInstanceConfigurator)' * Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getRegistry()'
*/ */
public void testRegisterFeed() { public void testGetRegistry() {
String feedURL = "myFeed";
registerFeed(feedURL); GDataServerRegistry reg1 = GDataServerRegistry.getRegistry();
assertEquals("Registered Configurator",this.configurator,this.reg.getFeedConfigurator(feedURL)); assertEquals("test singleton",this.reg,reg1);
assertNull("not registered Configurator",this.reg.getFeedConfigurator("somethingElse")); }
try{
this.reg.getFeedConfigurator(null); /**
fail("Exception expected"); * Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.registerFeed(FeedInstanceConfigurator)'
}catch (IllegalArgumentException e) { */
// 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"));
* Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getFeedConfigurator(String)' try{
*/ this.reg.getProvidedService(null);
public void testFlushRegistry() { fail("Exception expected");
String feedURL = "testFeed"; }catch (IllegalArgumentException e) {
registerFeed(feedURL); //
assertEquals("Registered Configurator",this.configurator,this.reg.getFeedConfigurator(feedURL)); }
this.reg.flushRegistry(); }
assertNull("Registry flushed",this.reg.getFeedConfigurator(feedURL));
/**
* Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getFeedConfigurator(String)'
} */
public void testFlushRegistry() {
/** String service = "service";
* registerService(service);
*/
public void testIsFeedRegistered(){ assertEquals("Registered Configurator",this.configurator,this.reg.getProvidedService(service));
String myFeed = "myFeed"; this.reg.flushRegistry();
registerFeed(myFeed); assertNull("Registry flushed",this.reg.getProvidedService(service));
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){ */
public void testIsFeedRegistered(){
this.configurator.setFeedType(Feed.class); String service = "service";
this.configurator.setFeedId(feedURL); registerService(service);
this.reg.registerFeed(this.configurator); 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);
}
}

View File

@ -15,22 +15,24 @@
*/ */
package org.apache.lucene.gdata.server.registry; package org.apache.lucene.gdata.server.registry;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.lucene.gdata.server.FeedNotFoundException; import org.apache.lucene.gdata.data.ServerBaseEntry;
import org.apache.lucene.gdata.server.GDataEntityBuilder; 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.BaseEntry;
import com.google.gdata.data.Entry; import com.google.gdata.data.BaseFeed;
import com.google.gdata.data.ExtensionProfile; import com.google.gdata.data.Entry;
import com.google.gdata.data.Feed; import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.util.ParseException; import com.google.gdata.data.Feed;
import com.google.gdata.data.Source;
import com.google.gdata.util.ParseException;
/** /**
* @author Simon Willnauer * @author Simon Willnauer
@ -44,8 +46,9 @@ public class TestGDataEntityBuilder extends TestCase {
private static GDataServerRegistry reg = GDataServerRegistry.getRegistry(); private static GDataServerRegistry reg = GDataServerRegistry.getRegistry();
private Reader reader; private Reader reader;
private static String feedID = "myFeed"; private static String feedID = "myFeed";
private ExtensionProfile profile; private ProvidedServiceConfig config;
private static Class feedType = Feed.class; private static Class feedType = Feed.class;
private static Class entryType = Entry.class;
/** /**
@ -53,11 +56,12 @@ public class TestGDataEntityBuilder extends TestCase {
*/ */
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
FeedInstanceConfigurator config = new FeedInstanceConfigurator(); this.config = new ProvidedServiceConfig();
config.setFeedId(feedID);
config.setFeedType(feedType); this.config.setFeedType(feedType);
this.profile = new ExtensionProfile(); this.config.setEntryType(entryType);
reg.registerFeed(config); 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)' * 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); this.reader = new FileReader(incomingFeed);
BaseFeed feed = GDataEntityBuilder.buildFeed(feedID,this.reader,this.profile); BaseFeed feed = GDataEntityBuilder.buildFeed(this.reader,this.config);
assertNotNull(feed); assertNotNull(feed);
assertEquals("feed title",feed.getTitle().getPlainText(), feedTitleFromXML); assertEquals("feed title",feed.getTitle().getPlainText(), feedTitleFromXML);
assertTrue( feed instanceof Feed);
} }
/* /**
* Test method for 'org.apache.lucene.gdata.data.GDataEntityBuilder.buildEntry(String, Reader)' * 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); this.reader = new FileReader(incomingEntry);
BaseEntry entry = GDataEntityBuilder.buildEntry(feedID,this.reader,this.profile); BaseEntry entry = GDataEntityBuilder.buildEntry(this.reader,this.config);
assertNotNull(entry); assertNotNull(entry);
assertEquals("entry summary",entry.getSummary().getPlainText(),entrySummaryFromXML); assertEquals("entry summary",entry.getSummary().getPlainText(),entrySummaryFromXML);
assertTrue(entry instanceof Entry);
} }

View File

@ -1,247 +1,387 @@
package org.apache.lucene.gdata.storage.lucenestorage; package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException; import java.io.IOException;
import java.util.Date;
import junit.framework.TestCase;
import junit.framework.TestCase;
import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.gdata.data.ServerBaseEntry;
import org.apache.lucene.gdata.server.FeedNotFoundException; import org.apache.lucene.gdata.data.ServerBaseFeed;
import org.apache.lucene.gdata.server.registry.FeedInstanceConfigurator; import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry; import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.server.registry.RegistryBuilder; import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.storage.StorageException; import org.apache.lucene.gdata.storage.StorageController;
import org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController; import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper; import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
import org.apache.lucene.gdata.storage.lucenestorage.StorageModifier; import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter;
import org.apache.lucene.gdata.storage.lucenestorage.StorageQuery; import org.apache.lucene.gdata.utils.ProvidedServiceStub;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation; import org.apache.lucene.index.Term;
import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter; import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.index.IndexWriter; import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.index.Term; import org.apache.lucene.search.Hits;
import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query;
import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.Directory;
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.BaseEntry; import com.google.gdata.data.Entry;
import com.google.gdata.data.DateTime; import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.Entry; import com.google.gdata.data.TextContent;
import com.google.gdata.data.ExtensionProfile; import com.google.gdata.util.ParseException;
import com.google.gdata.data.Feed;
import com.google.gdata.data.PlainTextConstruct; public class TestStorageModifier extends TestCase {
import com.google.gdata.data.TextConstruct; private StorageModifier modifier;
import com.google.gdata.data.TextContent;
import com.google.gdata.util.ParseException; private int count = 1;
public class TestStorageModifier extends TestCase { private ProvidedService configurator;
private StorageModifier modifier;
private int count = 1; 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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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 ServerBaseEntry getServerEntry(BaseEntry e){
private Directory dir; ServerBaseEntry en = new ServerBaseEntry(e);
en.setFeedId(feedId);
en.setServiceConfig(this.configurator);
private static String feedId = "myFeed"; return en;
}
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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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<StorageQuery> 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;
}
}
}

View File

@ -1,175 +1,266 @@
package org.apache.lucene.gdata.storage.lucenestorage; package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.net.URL;
import java.util.List; import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import junit.framework.TestCase;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.gdata.server.FeedNotFoundException; import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.server.registry.FeedInstanceConfigurator; import org.apache.lucene.gdata.data.ServerBaseEntry;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry; import org.apache.lucene.gdata.data.ServerBaseFeed;
import org.apache.lucene.gdata.server.registry.RegistryBuilder; import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.storage.StorageException; import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController; import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper; import org.apache.lucene.gdata.storage.StorageController;
import org.apache.lucene.gdata.storage.lucenestorage.StorageModifier; import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.gdata.storage.lucenestorage.StorageQuery; import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation; import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter;
import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter; import org.apache.lucene.gdata.utils.ProvidedServiceStub;
import org.apache.lucene.index.IndexWriter; import org.apache.lucene.store.Directory;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory; import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.BaseFeed;
import com.google.gdata.data.BaseEntry; import com.google.gdata.data.DateTime;
import com.google.gdata.data.DateTime; import com.google.gdata.data.Entry;
import com.google.gdata.data.Entry; import com.google.gdata.util.ParseException;
import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.data.Feed; public class TestStorageQuery extends TestCase {
import com.google.gdata.util.ParseException; private StorageModifier modifier;
private int count = 30;
public class TestStorageQuery extends TestCase { private ReferenceCounter<StorageQuery> query;
private StorageModifier modifier; private ProvidedService configurator;
private int count = 30; private StorageCoreController controller;
private ReferenceCounter<StorageQuery> query; private Directory dir;
private ExtensionProfile profile; private static String feedId = "myFeed";
private static String accountName = "simon";
private Directory dir; private static String service = ProvidedServiceStub.SERVICE_NAME;
private static String feedId = "myFeed"; protected void setUp() throws Exception {
protected void setUp() throws Exception { GDataServerRegistry.getRegistry().registerComponent(StorageCoreController.class);
FeedInstanceConfigurator configurator = new FeedInstanceConfigurator(); this.configurator = new ProvidedServiceStub();
configurator.setFeedType(Feed.class);
configurator.setFeedId(feedId);
configurator.setExtensionProfileClass(ExtensionProfile.class); GDataServerRegistry.getRegistry().registerService(this.configurator);
GDataServerRegistry.getRegistry().registerFeed(configurator); this.controller = (StorageCoreController)GDataServerRegistry.getRegistry().lookup(StorageController.class,ComponentType.STORAGECONTROLLER);
this.profile = new ExtensionProfile(); this.modifier = this.controller.getStorageModifier();
this.dir = new RAMDirectory(); this.dir = this.controller.getDirectory();
IndexWriter writer; ServerBaseFeed feed = new ServerBaseFeed();
writer = new IndexWriter(this.dir,new StandardAnalyzer(),true); feed.setId(feedId);
writer.close(); feed.setServiceType(service);
this.modifier = StorageCoreController.getStorageCoreController(this.dir).getStorageModifier(); feed.setServiceConfig(this.configurator);
insertEntries(this.count);
this.query = StorageCoreController.getStorageCoreController().getStorageQuery(); 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<StorageEntryWrapper> tempList = new ArrayList<StorageEntryWrapper>(); * @param entrycount
for (int i = 0; i <= count ; i++) { * @throws IOException
Entry entry = new Entry(); * @throws InterruptedException
entry.setId(""+i); * @throws StorageException
*/
entry.setUpdated(new DateTime(System.currentTimeMillis(),0)); public void insertEntries(int entrycount) throws IOException,InterruptedException, StorageException{
StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,feedId,StorageOperation.INSERT,this.profile); List<StorageEntryWrapper> tempList = new ArrayList<StorageEntryWrapper>();
tempList.add(i,wrapper); 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<StorageQuery> 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<StorageQuery> queryAssureWritten = this.controller.getStorageQuery();
assertNotSame(queryAssureWritten,this.query);
feedQueryHelper(queryAssureWritten);
queryAssureWritten.decrementRef();
}
private void feedQueryHelper(ReferenceCounter<StorageQuery> currentQuery) throws IOException, ParseException{
BaseFeed feed = currentQuery.get().getLatestFeedQuery(feedId,25,1,this.configurator);
List<BaseEntry> 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); // test sub retrieve sublist
int offset = 15;
} int resultCount = 5;
for (StorageEntryWrapper entry : tempList) { feed = currentQuery.get().getLatestFeedQuery(feedId,resultCount,offset,this.configurator);
this.modifier.insertEntry(entry); List<BaseEntry> entrySubList = feed.getEntries();
}
}
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<StorageQuery> queryAssureWritten = StorageCoreController.getStorageCoreController().getStorageQuery();
assertNotSame(queryAssureWritten,this.query); assertTrue("listSize: "+entrySubList.size(),entrySubList.size() == resultCount);
FeedQueryHelper(queryAssureWritten); offset--;
queryAssureWritten.decrementRef(); for (BaseEntry entry : entrySubList) {
}
private void FeedQueryHelper(ReferenceCounter<StorageQuery> currentQuery) throws IOException, FeedNotFoundException, ParseException{ assertEquals(entry.getId(),entryList.get(offset).getId());
List<BaseEntry> entryList = currentQuery.get().getLatestFeedQuery(feedId,25,1,this.profile); offset++;
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<BaseEntry> 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>, String)'
*/
public void testEntryQuery() throws FeedNotFoundException, ParseException, IOException, StorageException {
entryQueryHelper(this.query);
StorageCoreController.getStorageCoreController().forceWrite();
ReferenceCounter<StorageQuery> queryAssureWritten = StorageCoreController.getStorageCoreController().getStorageQuery();
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>, String)'
*/
public void testEntryQuery() throws ParseException, IOException, StorageException {
entryQueryHelper(this.query);
this.controller.forceWrite();
ReferenceCounter<StorageQuery> 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"));
this.modifier.createAccount(new StorageAccountWrapper(user));
private void entryQueryHelper(ReferenceCounter<StorageQuery> currentQuery) throws IOException, FeedNotFoundException, ParseException{ GDataAccount queriedUser = this.query.get().getUser("simon");
assertNull(queriedUser);
List<String> entryIdList = new ArrayList<String>(); ReferenceCounter<StorageQuery> tempQuery = this.controller.getStorageQuery();
for (int i = 1; i <= this.count; i++) { queriedUser = tempQuery.get().getUser("simon");
entryIdList.add(""+i); assertTrue(queriedUser.equals(user));
} assertTrue(queriedUser.getAuthorMail().equals(user.getAuthorMail()));
List<BaseEntry> entryList = currentQuery.get().entryQuery(entryIdList,feedId,this.profile); assertTrue(queriedUser.getAuthorLink().equals(user.getAuthorLink()));
assertEquals(entryIdList.size(),entryList.size()); assertTrue(queriedUser.getAuthorname().equals(user.getAuthorname()));
List<String> entryIdCompare = new ArrayList<String>(); assertTrue(queriedUser.getPassword().equals(user.getPassword()));
for (BaseEntry entry : entryList) { }
entryIdCompare.add(entry.getId());
} public void testIsEntryStored() throws IOException{
assertTrue(entryIdList.containsAll(entryIdCompare));
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<StorageQuery> currentQuery) throws IOException, ParseException{
List<String> entryIdList = new ArrayList<String>();
for (int i = 1; i <= this.count; i++) {
entryIdList.add(""+i);
}
List<BaseEntry> entryList = currentQuery.get().entryQuery(entryIdList,feedId,this.configurator);
assertEquals(entryIdList.size(),entryList.size());
List<String> entryIdCompare = new ArrayList<String>();
for (BaseEntry entry : entryList) {
entryIdCompare.add(entry.getId());
}
assertTrue(entryIdList.containsAll(entryIdCompare));
}
}

View File

@ -1,24 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd"
version="2.4"> version="2.4">
<display-name>Lucene GData - Server</display-name> <display-name>Lucene GData - Server</display-name>
<description> <description>
Server-side implementation of the GData protocol based on Apache Server-side implementation of the GData protocol based on Apache
- Lucene - Lucene
</description> </description>
<listener> <listener>
<listener-class> org.apache.lucene.gdata.server.registry.RegistryContextListener</listener-class> <listener-class>
</listener> org.apache.lucene.gdata.server.registry.RegistryContextListener
<servlet> </listener-class>
<servlet-name>ControllerServlet</servlet-name> </listener>
<servlet-class> <servlet>
org.apache.lucene.gdata.servlet.RequestControllerServlet <servlet-name>ControllerServlet</servlet-name>
</servlet-class> <servlet-class>
</servlet> org.apache.lucene.gdata.servlet.RequestControllerServlet
<servlet-mapping> </servlet-class>
<servlet-name>ControllerServlet</servlet-name> </servlet>
<url-pattern>/*</url-pattern> <servlet-mapping>
</servlet-mapping> <servlet-name>ControllerServlet</servlet-name>
</web-app> <url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>AuthenticationServlet</servlet-name>
<servlet-class>
org.apache.lucene.gdata.servlet.AuthenticationServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AuthenticationServlet</servlet-name>
<url-pattern>/accounts/ClientLogin</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>FeedAdminServlet</servlet-name>
<servlet-class>
org.apache.lucene.gdata.servlet.FeedAdministrationServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FeedAdminServlet</servlet-name>
<url-pattern>/admin/feed</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>AccountAdminServlet</servlet-name>
<servlet-class>
org.apache.lucene.gdata.servlet.AccountAdministrationServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AccountAdminServlet</servlet-name>
<url-pattern>/admin/account</url-pattern>
</servlet-mapping>
</web-app>