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/commons-logging-1.1.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>
@ -37,11 +41,15 @@
<echo>Distributing GData War </echo>
<war destfile="${dist.dir}/${gdata.war.name}.war"
webxml="webroot/WEB-INF/web.xml" >
<fileset dir="webroot" excludes="WEB-INF/web.xml"/>
<metainf dir="webroot/meta-inf"/>
<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="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 file="${lucene.jar}" />
</war>

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

@ -18,13 +18,10 @@ package org.apache.lucene.gdata.server;
import java.io.IOException;
import java.io.Reader;
import org.apache.lucene.gdata.server.registry.DataBuilderException;
import org.apache.lucene.gdata.server.registry.FeedInstanceConfigurator;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.BaseFeed;
import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.util.ParseException;
/**
@ -36,15 +33,17 @@ import com.google.gdata.util.ParseException;
* To provide a generic builder class the {@link GDataEntityBuilder} requests
* the type of the feed / entry and the corresponding
* {@link com.google.gdata.data.ExtensionProfile} form the global
* {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry} and builds the
* instances from the provided reader.
* {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry} and
* builds the instances from the provided reader.
* </p>
* <p>
* This build will not returne the abstract base classes.
* </p>
*
* @author Simon Willnauer
*
*/
public class GDataEntityBuilder {
private static final GDataServerRegistry REGISTRY = GDataServerRegistry.getRegistry(); // TODO find another way for getting the registered feeds
/**
* Builds a {@link BaseFeed} instance from the {@link Reader} provided by
@ -53,51 +52,42 @@ public class GDataEntityBuilder {
* @param request -
* the request to build the instance from
* @return - a BaseFeed instance
* @throws FeedNotFoundException -
* if the feed is not registered
*
* @throws IOException -
* if an I/O Exception occures on the provided reader
* @throws ParseException -
* if the feed could not be parsed
*/
public static BaseFeed buildFeed(final GDataRequest request)
throws FeedNotFoundException, IOException, ParseException {
throws IOException, ParseException {
if (request == null)
throw new IllegalArgumentException("request must not be null");
return buildFeed(request.getFeedId(), request.getReader(),request.getExtensionProfile());
ProvidedService config = request.getConfigurator();
return buildFeed(request.getReader(), config);
}
/**
* Builds a {@link BaseFeed} from the provided {@link Reader}
*
* @param feedId -
* the feed ID to request the feed type from the registry
*
* @param reader -
* the reader to build the feed from
* @param profile - extension profile to parse the resource
* @param config -
* the feed instance config containing the extension profile to
* parse the resource
* @return - a BaseFeed instance
* @throws FeedNotFoundException -
* if the feed is not registered
*
* @throws IOException -
* if an I/O Exception occures on the provided reader
* @throws ParseException -
* if the feed could not be parsed
*/
public static BaseFeed buildFeed(final String feedId, final Reader reader,final ExtensionProfile profile)
throws FeedNotFoundException, ParseException, IOException {
public static BaseFeed buildFeed(final Reader reader,
final ProvidedService config) throws ParseException, IOException {
BaseFeed retVal = null;
try {
retVal = (BaseFeed) createEntityInstance(feedId);
} catch (FeedNotFoundException e) {
throw e;
} catch (Exception e) {
DataBuilderException ex = new DataBuilderException(
"Could not build Feed for Feed class ", e);
ex.setStackTrace(e.getStackTrace());
throw ex;
}
retVal.parseAtom(profile, reader);
retVal = createEntityInstance(config);
retVal.parseAtom(config.getExtensionProfile(), reader);
return retVal;
}
@ -109,63 +99,73 @@ public class GDataEntityBuilder {
* @param request -
* the request to build the instance from
* @return - a BaseEntry instance
* @throws FeedNotFoundException -
* if the feed, requested by the client is not registered
*
* @throws IOException -
* if an I/O Exception occures on the provided reader
* @throws ParseException -
* if the entry could not be parsed
*/
public static BaseEntry buildEntry(final GDataRequest request)
throws FeedNotFoundException, IOException, ParseException {
throws IOException, ParseException {
if (request == null)
throw new IllegalArgumentException("request must not be null");
return buildEntry(request.getFeedId(), request.getReader(),request.getExtensionProfile());
ProvidedService config = request.getConfigurator();
return buildEntry(request.getReader(), config);
}
/**
* Builds a {@link BaseFeed} instance from the {@link Reader} provided by
* the {@link GDataRequest}
* @param feedId -
* the feed ID to request the feed type from the registry
*
* @param reader -
* the reader to build the feed from
* @param profile - extension profile to parse the resource
* @param config -
* the instance config containing the extension profile to parse
* the resource
* @return - a BaseFeed instance
* @throws FeedNotFoundException -
* if the feed is not registered
*
* @throws IOException -
* if an I/O Exception occures on the provided reader
* @throws ParseException -
* if the entry could not be parsed
*/
public static BaseEntry buildEntry(final String feedId, final Reader reader,final ExtensionProfile profile)
throws FeedNotFoundException, ParseException, IOException {
public static BaseEntry buildEntry(final Reader reader,
final ProvidedService config) throws ParseException, IOException {
BaseEntry retVal = null;
try {
retVal = ((BaseFeed) createEntityInstance(feedId)).createEntry();
} catch (FeedNotFoundException e) {
throw e;
} catch (Exception e) {
DataBuilderException ex = new DataBuilderException(
"Could not build Entry for Entry class ", e);
ex.setStackTrace(e.getStackTrace());
throw ex;
BaseEntry e = createEntityInstance(config).createEntry();
e.parseAtom(config.getExtensionProfile(), reader);
return e;
}
private static BaseFeed createEntityInstance(
final ProvidedService config) {
if(config.getFeedType() == null)
throw new IllegalArgumentException("feedtype is null in ProvidedService");
BaseFeed retVal = null;
try {
retVal = (BaseFeed) config.getFeedType().newInstance();
} catch (Exception e) {
throw new EntityBuilderException("Can't instanciate Feed for feedType "+config.getFeedType().getName(),e);
}
retVal.parseAtom(new ExtensionProfile(), reader);
return retVal;
}
static class EntityBuilderException extends RuntimeException{
/**
*
*/
private static final long serialVersionUID = 7224011324202237951L;
EntityBuilderException(String arg0) {
super(arg0);
}
EntityBuilderException(String arg0, Throwable arg1) {
super(arg0, arg1);
private static Object createEntityInstance(String feedId)
throws FeedNotFoundException, InstantiationException,
IllegalAccessException {
FeedInstanceConfigurator config = REGISTRY.getFeedConfigurator(feedId);
if (config == null)
throw new FeedNotFoundException(
"No feed for requested feed ID found - " + feedId);
Class feedClass = config.getFeedType();
return feedClass.newInstance();
}
}
}

View File

@ -22,13 +22,17 @@ import java.util.Enumeration;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.server.authentication.AuthenticationController;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import com.google.gdata.data.ExtensionProfile;
import org.apache.lucene.gdata.storage.Storage;
import org.apache.lucene.gdata.storage.StorageController;
/**
* The GDataRequest Class wraps the incoming HttpServletRequest. Needed
@ -68,6 +72,10 @@ public class GDataRequest {
@SuppressWarnings("unused")
private static final String RESPONSE_FORMAT_PARAMETER_ATOM = "atom";
private static final String HTTP_HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
private static final String HTTP_HEADER_AUTH = "Authorization";
// Atom is the default resopnse format
private OutputFormat responseFormat = OutputFormat.ATOM;
@ -77,7 +85,7 @@ public class GDataRequest {
private String entryId = null;
private ExtensionProfile extensionProfile= null;
private ProvidedService configurator = null;
private String entryVersion = null;
@ -112,12 +120,31 @@ public class GDataRequest {
public void initializeRequest() throws GDataRequestException {
generateIdentificationProperties();
setOutputFormat();
// TODO remove this dependency
StorageController controller = GDataServerRegistry.getRegistry()
.lookup(StorageController.class,
ComponentType.STORAGECONTROLLER);
try {
Storage storage = controller.getStorage();
String service = storage.getServiceForFeed(this.feedId);
/*
* ExtensionProfile is used for building the Entry / Feed Instances from an inputstream or reader
* ExtensionProfile and the type is used for building the Entry /
* Feed Instances from an inputstream or reader
*
*/
this.extensionProfile = GDataServerRegistry.getRegistry().getExtensionProfile(this.feedId);
if(this.extensionProfile == null)
throw new GDataRequestException("feed is not registered or extension profile could not be created");
this.configurator = GDataServerRegistry.getRegistry()
.getProvidedService(service);
if (this.configurator == null)
throw new GDataRequestException(
"feed is not registered or extension profile could not be created");
} catch (Exception e) {
throw new GDataRequestException(
"feed is not registered or extension profile could not be created");
}
}
/**
@ -231,6 +258,7 @@ public class GDataRequest {
LOG.warn("Intems per page could not be parsed - " + e.getMessage(),
e);
}
return retval < 0 ? DEFAULT_ITEMS_PER_PAGE : retval;
}
@ -263,7 +291,7 @@ public class GDataRequest {
public String getSelfId() {
StringBuilder builder = new StringBuilder();
builder.append(buildRequestIDString(false));
builder.append("?");
builder.append(getQueryString());
return builder.toString();
@ -275,42 +303,48 @@ public class GDataRequest {
* @return the id of the next page
*/
public String getNextId() {
// StringBuilder builder = new StringBuilder();
// builder.append(buildRequestIDString());
//
// builder.append(getQueryString());
//
// if(this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER)==
// null){
// builder.append("&").append(START_INDEX_NEXT_PAGE_PARAMETER).append("=");
// builder.append(DEFAULT_ITEMS_PER_PAGE+1);
// }
// else{
//
// int next = 0;
// try{
// next =
// Integer.parseInt(this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER));
// }catch (Exception e) {
// //
// }
//
// if(next < 0)
// builder.append(DEFAULT_ITEMS_PER_PAGE+1);
// else
// builder.append(next+DEFAULT_ITEMS_PER_PAGE);
// int pos = builder.indexOf(START_INDEX_NEXT_PAGE_PARAMETER);
// boolean end = builder.lastIndexOf("&",pos) < pos;
// builder.replace(pos+START_INDEX_NEXT_PAGE_PARAMETER.length()+1,pos+START_INDEX_NEXT_PAGE_PARAMETER.length()+3,""+next);
//
//
// System.out.println(end);
// }
//
//
//
// return builder.toString();
return buildRequestIDString(false);
StringBuilder builder = new StringBuilder();
builder.append(buildRequestIDString(false));
builder.append("?");
Enumeration parameters = this.request.getParameterNames();
while (parameters.hasMoreElements()) {
String element = (String) parameters.nextElement();
String[] values = this.request.getParameterValues(element);
for (int i = 0; i < values.length; i++) {
builder.append(element).append("=");
if (element.equals(START_INDEX_NEXT_PAGE_PARAMETER)) {
int tempVal = DEFAULT_START_INDEX;
try {
tempVal = Integer.parseInt(values[i]);
} catch (Exception e) {
LOG.info("Can not parse StartIndex -- use defaut");
}
builder.append(tempVal + getItemsPerPage());
break;
}
builder.append(values[i]);
}
if (parameters.hasMoreElements())
builder.append("&");
}
if (this.request.getParameter(ITEMS_PER_PAGE_PARAMETER) == null) {
if (builder.charAt(builder.length() - 1) != '?')
builder.append('&');
builder.append(ITEMS_PER_PAGE_PARAMETER).append("=").append(
DEFAULT_ITEMS_PER_PAGE);
}
if (this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER) == null) {
builder.append('&');
builder.append(START_INDEX_NEXT_PAGE_PARAMETER).append("=");
builder.append(DEFAULT_ITEMS_PER_PAGE + 1);
}
return builder.toString();
}
@ -340,9 +374,9 @@ public class GDataRequest {
if (this.request.getParameter(ITEMS_PER_PAGE_PARAMETER) != null)
return retVal;
String tempString = (retVal == null ? "?" + ITEMS_PER_PAGE_PARAMETER
+ "=" + DEFAULT_ITEMS_PER_PAGE : "&" + ITEMS_PER_PAGE_PARAMETER
+ "=" + DEFAULT_ITEMS_PER_PAGE);
String tempString = (retVal == null ? ITEMS_PER_PAGE_PARAMETER + "="
+ DEFAULT_ITEMS_PER_PAGE : "&" + ITEMS_PER_PAGE_PARAMETER + "="
+ DEFAULT_ITEMS_PER_PAGE);
return retVal == null ? tempString : retVal + tempString;
@ -412,31 +446,92 @@ public class GDataRequest {
}
/**
* If the reuquest is a {@link GDataRequestType#GET} request and there is
* no entry id specified, the requested resource is a feed.
* 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
* @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('/'))));
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
* @return - <code>true</code> if an only if the requested resource is an
* entry
*/
public boolean isEntryRequested() {
return !this.isFeedRequested();
}
/**
* @return - the extensionProfile for the requested resource
* @return the configuration for this request
*/
public ExtensionProfile getExtensionProfile() {
return this.extensionProfile;
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

@ -18,13 +18,16 @@ package org.apache.lucene.gdata.server;
import java.io.IOException;
import java.io.Writer;
import java.util.Date;
import javax.servlet.http.HttpServletResponse;
import org.apache.lucene.gdata.server.GDataRequest.OutputFormat;
import org.apache.lucene.gdata.utils.DateFormater;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.BaseFeed;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.util.common.xml.XmlWriter;
import com.google.gdata.util.common.xml.XmlWriter.Namespace;
@ -50,6 +53,13 @@ import com.google.gdata.util.common.xml.XmlWriter.Namespace;
* {@link org.apache.lucene.gdata.server.GDataResponse#sendResponse(BaseEntry, ExtensionProfile)}
* which sends the entry e.g feed to the output stream.
* </p>
* <p>
* 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
* changed since the If-Modified-Since time, then the GData service returns a
* 304 (Not Modified) HTTP response.
* </p>
*
*
*
@ -68,11 +78,17 @@ public class GDataResponse {
private final HttpServletResponse response;
protected static final String XMLMIME_ATOM = "text/xml";
protected static final String XMLMIME_RSS = "text/xml";
private static final String DEFAUL_NAMESPACE_URI = "http://www.w3.org/2005/Atom";
private static final Namespace DEFAULT_NAMESPACE = new Namespace("",
DEFAUL_NAMESPACE_URI);
private static final String HEADER_LASTMODIFIED = "Last-Modified";
/**
* Creates a new GDataResponse
*
@ -83,7 +99,7 @@ public class GDataResponse {
if (response == null)
throw new IllegalArgumentException("response must not be null");
this.response = response;
this.response.setContentType("text/xml");
}
/**
@ -96,14 +112,18 @@ public class GDataResponse {
this.isError = true;
this.error = errorCode;
}
/**
* Sets the status of the underlaying response
*
* @see HttpServletResponse
* @param responseCode - the status of the response
* @param responseCode -
* the status of the response
*/
public void setResponseCode(int responseCode) {
this.response.setStatus(responseCode);
}
/**
* This method sends the specified error to the user if set
*
@ -113,6 +133,7 @@ public class GDataResponse {
public void sendError() throws IOException {
if (this.isError)
this.response.sendError(this.error);
}
/**
@ -142,21 +163,30 @@ public class GDataResponse {
if (feed == null)
throw new IllegalArgumentException("feed must not be null");
if (profile == null)
throw new IllegalArgumentException("extension profil must not be null");
throw new IllegalArgumentException(
"extension profil must not be null");
DateTime time = feed.getUpdated();
if (time != null)
setLastModifiedHeader(time.getValue());
XmlWriter writer = createWriter();
if (this.outputFormat.equals(OutputFormat.ATOM))
if (this.outputFormat.equals(OutputFormat.ATOM)) {
this.response.setContentType(XMLMIME_ATOM);
feed.generateAtom(writer, profile);
else
} else {
this.response.setContentType(XMLMIME_RSS);
feed.generateRss(writer, profile);
}
}
/**
*
* Sends a response for an update, insert or delete request. This method
* must not invoked in a case of an error performing the requeste action.
* If the specified response format is ATOM the default namespace will be set to ATOM.
* must not invoked in a case of an error performing the requeste action. If
* the specified response format is ATOM the default namespace will be set
* to ATOM.
*
* @param entry -
* the modified / created entry to send
* @param profile -
@ -170,7 +200,11 @@ public class GDataResponse {
if (entry == null)
throw new IllegalArgumentException("entry must not be null");
if (profile == null)
throw new IllegalArgumentException("extension profil must not be null");
throw new IllegalArgumentException(
"extension profil must not be null");
DateTime time = entry.getUpdated();
if (time != null)
setLastModifiedHeader(time.getValue());
XmlWriter writer = createWriter();
if (this.outputFormat.equals(OutputFormat.ATOM))
entry.generateAtom(writer, profile);
@ -224,6 +258,7 @@ public class GDataResponse {
public void setOutputFormat(OutputFormat outputFormat) {
this.outputFormat = outputFormat;
}
/**
* @see Object#toString()
*/
@ -236,7 +271,20 @@ public class GDataResponse {
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

@ -16,14 +16,21 @@
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 org.apache.lucene.gdata.storage.StorageFactory;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.BaseFeed;
@ -33,21 +40,26 @@ import com.google.gdata.data.Link;
import com.google.gdata.util.ParseException;
/**
* default implementation of the {@link org.apache.lucene.gdata.server.Service}
* interface.
*
* @author Simon Willnauer
*
*/
public class GDataService extends Service {
public class GDataService implements Service {
private static final Log LOGGER = LogFactory.getLog(GDataService.class);
private Storage storage;
protected Storage storage;
private GDataServerRegistry registry = GDataServerRegistry.getRegistry();
protected GDataServerRegistry registry = GDataServerRegistry.getRegistry();
private static final Generator generator;
private static final String generatorName = "Lucene GData-Server";
private static final String generatorURI = "http://lucene.apache.org";
private static final String XMLMIME = "application/atom+xml";
static {
generator = new Generator();
generator.setName(generatorName);
@ -57,7 +69,13 @@ public class GDataService extends Service {
protected GDataService() throws ServiceException {
try {
this.storage = StorageFactory.getStorage();
StorageController controller = GDataServerRegistry.getRegistry()
.lookup(StorageController.class,
ComponentType.STORAGECONTROLLER);
if (controller == null)
throw new StorageException(
"StorageController is not registered");
this.storage = controller.getStorage();
} catch (StorageException e) {
LOGGER
@ -75,40 +93,55 @@ public class GDataService extends Service {
* @see org.apache.lucene.gdata.server.Service#createEntry(org.apache.lucene.gdata.server.GDataRequest,
* org.apache.lucene.gdata.server.GDataResponse)
*/
@Override
public BaseEntry createEntry(GDataRequest request, GDataResponse response)
throws ServiceException {
checkFeedIsRegisterd(request);
if (LOGGER.isInfoEnabled())
LOGGER.info("create Entry for feedId: " + request.getFeedId());
BaseEntry entry = buildEntry(request);
setUpdateTime(entry);
try {
this.storage.storeEntry(entry, request.getFeedId());
ServerBaseEntry entry = buildEntry(request, response);
entry.setFeedId(request.getFeedId());
entry.setServiceConfig(request.getConfigurator());
setTimeStamps(entry.getEntry());
BaseEntry retVal = null;
try {
retVal = this.storage.storeEntry(entry);
} catch (Exception e) {
response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
ServiceException ex = new ServiceException("Could not store entry",
e);
ex.setStackTrace(e.getStackTrace());
throw ex;
}
return entry;
return retVal;
}
/**
* @see org.apache.lucene.gdata.server.Service#deleteEntry(org.apache.lucene.gdata.server.GDataRequest,
* org.apache.lucene.gdata.server.GDataResponse)
*/
@Override
public BaseEntry deleteEntry(GDataRequest request, GDataResponse response)
throws ServiceException {
checkFeedIsRegisterd(request);
String entryid = request.getEntryId();
String feedid = request.getFeedId();
ServerBaseEntry entry = new ServerBaseEntry();
entry.setServiceConfig(request.getConfigurator());
entry.setFeedId(request.getFeedId());
entry.setId(request.getEntryId());
if (entry.getId() == null)
throw new ServiceException(
"entry id is null -- can not delete null entry");
try {
this.storage.deleteEntry(entryid, feedid);
this.storage.deleteEntry(entry);
} catch (ResourceNotFoundException e) {
response.setError(HttpServletResponse.SC_BAD_REQUEST);
ServiceException ex = new ServiceException(
"Could not delete entry", e);
ex.setStackTrace(e.getStackTrace());
throw ex;
} catch (Exception e) {
response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
ServiceException ex = new ServiceException(
"Could not delete entry", e);
ex.setStackTrace(e.getStackTrace());
@ -121,26 +154,50 @@ public class GDataService extends Service {
* @see org.apache.lucene.gdata.server.Service#updateEntry(org.apache.lucene.gdata.server.GDataRequest,
* org.apache.lucene.gdata.server.GDataResponse)
*/
@Override
public BaseEntry updateEntry(GDataRequest request, GDataResponse response)
throws ServiceException {
checkFeedIsRegisterd(request);
BaseEntry entry = buildEntry(request);
String feedid = request.getFeedId();
ServerBaseEntry entry = buildEntry(request, response);
entry.setFeedId(request.getFeedId());
entry.setServiceConfig(request.getConfigurator());
if (LOGGER.isInfoEnabled())
LOGGER.info("update Entry" + entry.getId() + " for feedId: "
+ feedid);
setUpdateTime(entry);
+ request.getFeedId());
if (entry.getId() == null) {
response.setError(HttpServletResponse.SC_BAD_REQUEST);
throw new ServiceException("Entry id is null can not update entry");
}
if (!entry.getId().equals(request.getEntryId())) {
if (LOGGER.isInfoEnabled())
LOGGER
.info("Entry id in the entry xml does not match the requested resource -- XML-ID:"
+ entry.getId()
+ "; Requested resource: "
+ request.getEntryId());
response.setError(HttpServletResponse.SC_BAD_REQUEST);
throw new ServiceException(
"Entry id in the entry xml does not match the requested resource");
}
setTimeStamps(entry.getEntry());
BaseEntry retVal = null;
try {
this.storage.updateEntry(entry, feedid);
retVal = this.storage.updateEntry(entry);
} catch (ResourceNotFoundException e) {
response.setError(HttpServletResponse.SC_BAD_REQUEST);
ServiceException ex = new ServiceException(
"Could not update entry", e);
ex.setStackTrace(e.getStackTrace());
throw ex;
} catch (StorageException e) {
response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
ServiceException ex = new ServiceException(
"Could not update entry", e);
ex.setStackTrace(e.getStackTrace());
throw ex;
}
return entry;
return retVal;
}
/**
@ -148,21 +205,25 @@ public class GDataService extends Service {
* org.apache.lucene.gdata.server.GDataResponse)
*/
@SuppressWarnings("unchecked")
@Override
public BaseFeed getFeed(GDataRequest request, GDataResponse response)
throws ServiceException {
checkFeedIsRegisterd(request);
ServerBaseFeed feed = new ServerBaseFeed();
feed.setId(request.getFeedId());
feed.setStartIndex(request.getStartIndex());
feed.setItemsPerPage(request.getItemsPerPage());
feed.setServiceConfig(request.getConfigurator());
try {
// TODO remove when storing feeds is implemented just for
// development
BaseFeed feed = this.storage.getFeed(request.getFeedId(), request
.getStartIndex(), request.getItemsPerPage());
buildDynamicFeedElements(request, feed);
List<BaseEntry> list = feed.getEntries();
addContextPath(list, request.getContextPath());
return feed;
BaseFeed retVal = this.storage.getFeed(feed);
dynamicElementFeedStragey(retVal, request);
return retVal;
/*
* resouce not found will be detected in Gdata request.
* the request queries the storage for the feed to get the serivce for the feed
*/
} catch (StorageException e) {
response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
ServiceException ex = new ServiceException("Could not get feed", e);
ex.setStackTrace(e.getStackTrace());
throw ex;
@ -170,18 +231,6 @@ public class GDataService extends Service {
}
/*
* build the dynamic elements like self link and next link
*/
private void buildDynamicFeedElements(final GDataRequest request,
final BaseFeed feed) {
feed.setGenerator(generator);
feed.setItemsPerPage(request.getItemsPerPage());
feed.getLinks().add(
buildLink(Link.Rel.SELF, Link.Type.ATOM, request.getSelfId()));
// TODO add next link
}
private Link buildLink(String rel, String type, String href) {
Link retVal = new Link();
retVal.setHref(href);
@ -190,41 +239,21 @@ public class GDataService extends Service {
return retVal;
}
/*
* every entry has an ID which has to have a prefix. The prefix is the
* context path of the requested feed. This will be used to request the
* entry directly
*/
private void addContextPath(List<BaseEntry> list, final String contextPath) {
for (BaseEntry entry : list) {
addcontextPath(entry, contextPath);
}
}
@SuppressWarnings("unchecked")
private BaseEntry addcontextPath(final BaseEntry entry,
final String contextPath) {
String id = contextPath + entry.getId();
entry.setId(id);
Link self = new Link();
self.setRel("self");
self.setHref(id);
self.setType("application/atom+xml");
entry.getLinks().add(self);
return entry;
}
private BaseEntry buildEntry(final GDataRequest request)
throws ServiceException {
private ServerBaseEntry buildEntry(final GDataRequest request,
final GDataResponse response) throws ServiceException {
try {
return GDataEntityBuilder.buildEntry(request);
ServerBaseEntry entry = new ServerBaseEntry(GDataEntityBuilder
.buildEntry(request));
return entry;
} catch (ParseException e) {
response.setError(HttpServletResponse.SC_BAD_REQUEST);
ServiceException ex = new ServiceException(
"Could not parse entry from incoming request", e);
ex.setStackTrace(e.getStackTrace());
throw ex;
} catch (IOException e) {
response.setError(HttpServletResponse.SC_BAD_REQUEST);
ServiceException ex = new ServiceException(
"Could not read or open input stream", e);
ex.setStackTrace(e.getStackTrace());
@ -232,20 +261,11 @@ public class GDataService extends Service {
}
}
/*
* checks whether the reqeuested feed is registered
*/
private void checkFeedIsRegisterd(final GDataRequest request)
throws FeedNotFoundException {
if (!this.registry.isFeedRegistered(request.getFeedId()))
throw new FeedNotFoundException(
"Feed could not be found - is not registed - Feed ID:"
+ request.getFeedId());
this.storage.setExtensionProfile(request.getExtensionProfile());
}
private BaseEntry setUpdateTime(final BaseEntry entry) {
private BaseEntry setTimeStamps(final BaseEntry entry) {
if (entry.getUpdated() == null)
entry.setUpdated(DateTime.now());
if (entry.getPublished() == null)
entry.setPublished(DateTime.now());
return entry;
}
@ -253,18 +273,30 @@ public class GDataService extends Service {
* @see org.apache.lucene.gdata.server.Service#getSingleEntry(org.apache.lucene.gdata.server.GDataRequest,
* org.apache.lucene.gdata.server.GDataResponse)
*/
@Override
public BaseEntry getSingleEntry(GDataRequest request, GDataResponse response)
throws ServiceException {
checkFeedIsRegisterd(request);
try {
BaseEntry entry = this.storage.getEntry(request.getEntryId(),
request.getFeedId());
if(entry == null)
return null;
addcontextPath(entry, request.getContextPath());
return entry;
ServerBaseEntry entry = new ServerBaseEntry();
entry.setServiceConfig(request.getConfigurator());
entry.setFeedId(request.getFeedId());
entry.setId(request.getEntryId());
if(entry.getId() == null){
response.setError(HttpServletResponse.SC_BAD_REQUEST);
throw new ServiceException("entry is null can't get entry");
}
BaseEntry retVal = null;
retVal = this.storage.getEntry(entry);
dynamicElementEntryStragey(retVal, request);
return retVal;
} catch (ResourceNotFoundException e) {
response.setError(HttpServletResponse.SC_BAD_REQUEST);
ServiceException ex = new ServiceException(
"Could not get entry", e);
ex.setStackTrace(e.getStackTrace());
throw ex;
} catch (StorageException e) {
ServiceException ex = new ServiceException("Could not get feed", e);
ex.setStackTrace(e.getStackTrace());
@ -272,4 +304,95 @@ public class GDataService extends Service {
}
}
/*
* adds all dynamic element to the entry
*/
private void dynamicElementEntryStragey(final BaseEntry entry,
final GDataRequest request) {
setSelfLink(entry, request.getContextPath());
}
/*
* adds all dynamic element to the feed entries
*/
@SuppressWarnings("unchecked")
private void dynamicElementFeedStragey(final BaseFeed feed,
final GDataRequest request) {
buildDynamicFeedElements(request, feed);
List<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;
import java.util.Date;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.BaseFeed;
@ -39,7 +41,7 @@ import com.google.gdata.data.BaseFeed;
*
*
*/
public abstract class Service {
public interface Service {
/**
* Service method to create an entry in an already created and existing
@ -133,6 +135,27 @@ public abstract class Service {
public abstract BaseEntry getSingleEntry(final GDataRequest request, final GDataResponse response)
throws ServiceException;
/**
* will close the Service - service should not be used after this method has been called
*/
public void close();
/**
* Retruns the date of the last modification for the given feed id
* @param feedId - the id of the feed
* @return - the last modified date or the current date if the date can not be retrieved
* @throws ServiceException - if the storage can not be accessed
*/
public abstract Date getFeedLastModified(String feedId)throws ServiceException;
/**
* Retruns the date of the last modification for the given entry id
* @param entryId - the id of the entry
* @param feedId - the feed id this entry belongs to
* @return - the last modified date or the current date if the date can not be retrieved
* @throws ServiceException - if the storage can not be accessed
*/
public abstract Date getEntryLastModified(String entryId, String feedId)throws ServiceException;

View File

@ -17,6 +17,10 @@
package org.apache.lucene.gdata.server;
/**
* The ServiceException is used to encapsulate all {@link java.lang.Exception}
* throw by underlaying layers of the
* {@link org.apache.lucene.gdata.server.Service} layer.
*
* @author Simon Willnauer
*
*/
@ -28,7 +32,7 @@ public class ServiceException extends Exception {
private static final long serialVersionUID = -7099825107871876584L;
/**
*
* Constructs a new ServiceException
*/
public ServiceException() {
super();
@ -36,7 +40,8 @@ public class ServiceException extends Exception {
}
/**
* @param arg0
* Constructs a new ServiceException
* @param arg0 - the exception message
*/
public ServiceException(String arg0) {
super(arg0);
@ -44,8 +49,9 @@ public class ServiceException extends Exception {
}
/**
* @param arg0
* @param arg1
* Constructs a new ServiceException
* @param arg0 - the exceptin message
* @param arg1 - the exception cause
*/
public ServiceException(String arg0, Throwable arg1) {
super(arg0, arg1);
@ -53,7 +59,8 @@ public class ServiceException extends Exception {
}
/**
* @param arg0
* Constructs a new ServiceException
* @param arg0 - the exception cause
*/
public ServiceException(Throwable arg0) {
super(arg0);

View File

@ -15,36 +15,44 @@
*/
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)}
*
* @author Simon Willnauer
*
*/
public class ServiceFactory {
@Component(componentType=ComponentType.SERVICEFACTORY)
public class ServiceFactory implements ServerComponent {
private static final Log LOG = LogFactory.getLog(ServiceFactory.class);
private static ServiceFactory INSTANCE = null;
/**
* @return - a Singleton Instance of the factory
* public constructor to enable loading via the registry
* @see org.apache.lucene.gdata.server.registry.Component
* @see org.apache.lucene.gdata.server.registry.GDataServerRegistry
*/
public static synchronized ServiceFactory getInstance() {
if (INSTANCE == null)
INSTANCE = new ServiceFactory();
return INSTANCE;
}
private ServiceFactory() {
// private constructor --> singleton
public ServiceFactory() {
//
}
/**
* Creates a {@link Service} implementation.
* Creates a {@link Service} instance.
*
* @return a Service Implementation
* @return a Service instance
*/
public Service getService() {
try{
@ -54,4 +62,31 @@ public class ServiceFactory {
}
return null;
}
/**
* Creates a {@link AdminService} instance
* @return a AdminService instance
*/
public AdminService getAdminService(){
try {
return new GDataAdminService();
} catch (ServiceException e) {
LOG.warn("Factory method can not create GDataAdminService returning null-- "+e.getMessage(),e);
}
return null;
}
/**
* @see org.apache.lucene.gdata.server.registry.ServerComponent#initialize()
*/
public void initialize() {
//
}
/**
* @see org.apache.lucene.gdata.server.registry.ServerComponent#destroy()
*/
public void destroy() {
//
}
}

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

@ -20,23 +20,29 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.storage.StorageController;
import com.google.gdata.data.ExtensionProfile;
/**
*
* The FeedRegistry represents the registry component of the GData Server. All
* feed configurations will be registered here. Feed configurations contain
* several informationsa about GData feed like:
* <ol>
* <li>the feed id - where the feed can be accessed via http methodes</li>
* <li>the feed type - feed types are implementations of the abstract
* {@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
* requests.
* The GDataServerRegistry represents the registry component of the GData
* Server. All provided services and server components will be registered here.
* The Gdata Server serves RSS / ATOM feeds for defined services. Each service
* provides <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>
*
*
* @author Simon Willnauer
*
@ -44,12 +50,13 @@ import com.google.gdata.data.ExtensionProfile;
public class GDataServerRegistry {
private static GDataServerRegistry INSTANCE;
private StorageController storageInstance;
private static final Log LOGGER = LogFactory
.getLog(GDataServerRegistry.class);
private final Map<String, FeedInstanceConfigurator> feedTypMap = new HashMap<String, FeedInstanceConfigurator>();
private final Map<String, ProvidedService> serviceTypeMap = new HashMap<String, ProvidedService>();
private final Map<ComponentType, ComponentBean> componentMap = new HashMap<ComponentType, ComponentBean>(
10);
private GDataServerRegistry() {
// private - singleton
@ -65,90 +72,183 @@ public class GDataServerRegistry {
}
/**
* Registers a {@link FeedInstanceConfigurator}
* Registers a {@link ProvidedService}
*
* @param configurator -
* the configurator to register in the registry
*/
public void registerFeed(FeedInstanceConfigurator configurator) {
public void registerService(ProvidedService configurator) {
if (configurator == null) {
LOGGER.warn("Feedconfigurator is null -- skip registration");
return;
}
this.feedTypMap.put(configurator.getFeedId(), configurator);
this.serviceTypeMap.put(configurator.getName(), configurator);
}
/**
* Looks up the {@link FeedInstanceConfigurator} by the given feed id.
* Looks up the {@link ProvidedServiceConfig} by the given service name.
*
* @param feedId
* @return - the {@link FeedInstanceConfigurator} or <code>null</code> if
* the no configuration for this feed has been registered
* @param service
* @return - the {@link ProvidedServiceConfig} or <code>null</code> if the
* no configuration for this service has been registered
*/
public FeedInstanceConfigurator getFeedConfigurator(String feedId) {
if (feedId == null)
public ProvidedService getProvidedService(String service) {
if (service == null)
throw new IllegalArgumentException(
"Feed URL is null - must not be null to get registered feedtype");
return this.feedTypMap.get(feedId);
"Service is null - must not be null to get registered feedtype");
return this.serviceTypeMap.get(service);
}
protected void flushRegistry() {
this.feedTypMap.clear();
this.serviceTypeMap.clear();
this.componentMap.clear();
}
/**
* @param feedId -
* the id of the feed as the feed is registered
* @return - <code>true</code> if and only if the feed is registered,
* @param service -
* the name of the service
* @return - <code>true</code> if and only if the service is registered,
* otherwise <code>false</code>.
*/
public boolean isFeedRegistered(String feedId) {
return this.feedTypMap.containsKey(feedId);
public boolean isServiceRegistered(String service) {
return this.serviceTypeMap.containsKey(service);
}
/**
* @param storage
*/
public void registerStorage(StorageController storage) {
if (this.storageInstance != null)
throw new IllegalStateException(
"Storage already registered -- Instance of "
+ this.storageInstance.getClass());
this.storageInstance = storage;
}
/**
* Destroys the registry and release all resources
*/
public void destroy() {
for (ComponentBean component : this.componentMap.values()) {
component.getObject().destroy();
}
flushRegistry();
this.storageInstance.destroy();
this.storageInstance = null;
}
/**
* Creates the {@link ExtensionProfile} for a registered feed
* @param feedId - the feed id
* @return - the extension profil for this feed of <code>null</code> if
* the feed is not registered or the extension profile could not be
* instanciated
* This method is the main interface to the Component Lookup Service of the
* registry. Every GDATA - Server component like STORAGE or the INDEXER
* component will be accessible via this method. To get a Component from the
* lookup service specify the expected Class as an argument and the
* component type of the component to return. For a lookup of the
* STORAGECONTORLER the code looks like:
* <p>
* <code> registryInstance.lookup(StorageController.class,ComponentType.STORAGECONTROLLER);</code>
* </p>
*
* @param <R>
* the type of the expected return value
* @param clazz -
* Class object of the expected return value
* @param compType -
* The component type
* @return the registered component or <code>null</code> if the component
* can not looked up.
*/
public ExtensionProfile getExtensionProfile(final String feedId) {
FeedInstanceConfigurator configurator = this.feedTypMap.get(feedId);
if (configurator == null)
@SuppressWarnings("unchecked")
public <R> R lookup(Class<R> clazz, ComponentType compType) {
ComponentBean bean = this.componentMap.get(compType);
if (bean == null)
return null;
Class clazz = configurator.getExtensionProfilClass();
if (bean.getSuperType().equals(clazz))
return (R) bean.getObject();
return null;
}
/**
* @param <E>
* @param componentClass
* @throws RegistryException
*/
@SuppressWarnings("unchecked")
public <E extends ServerComponent> void registerComponent(final Class<E> componentClass)
throws RegistryException {
if (componentClass == null)
throw new IllegalArgumentException(
"component class must not be null");
if(!checkImplementsServerComponent(componentClass))
throw new RegistryException("can not register component. the given class does not implement ServerComponent interface -- "+componentClass.getName());
try {
return (ExtensionProfile) clazz.newInstance();
Component annotation = componentClass.getAnnotation(Component.class);
if (annotation == null)
throw new RegistryException(
"can not register component. the given class is not a component -- "
+ componentClass.getName());
ComponentType type = annotation.componentType();
if (this.componentMap.containsKey(type))
throw new RegistryException("component already registered -- "
+ type.name());
Class superType = type.getClass().getField(type.name())
.getAnnotation(SuperType.class).superType();
if (!checkSuperType(componentClass, superType))
throw new RegistryException("Considered Supertype <"
+ superType.getName() + "> is not a super type of <"
+ componentClass + ">");
ServerComponent comp = componentClass.newInstance();
comp.initialize();
ComponentBean bean = new ComponentBean(comp, superType);
this.componentMap.put(type, bean);
} catch (Exception e) {
LOGGER
.error("Can not create instance of ExtensionProfil for class: "
+ clazz + " -- feedId: " + feedId);
}
return null;
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

@ -15,27 +15,56 @@
*/
package org.apache.lucene.gdata.server.registry;
import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.data.Feed;
import java.io.IOException;
import org.apache.commons.digester.Digester;
import org.xml.sax.SAXException;
/**
* Reads the configuration file and creates the
* {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry} singleton
* instance. All services and components will be instanciated and registered in
* the registry.
*
* @author Simon Willnauer
*
*/
public class RegistryBuilder {
class RegistryBuilder {
/**
* builds the {@link GDataServerRegistry} accessible via the
* {@link GDataServerRegistry#getRegistry()} method
*
* @throws IOException -
* if an IOException occures while reading the config file
* @throws SAXException -
* if the config file can not be parsed
*/
public static void buildRegistry(){
// TODO Implement this!! -- just for develping purposes
GDataServerRegistry reg = GDataServerRegistry.getRegistry();
FeedInstanceConfigurator configurator = new FeedInstanceConfigurator();
configurator.setFeedType(Feed.class);
configurator.setFeedId("weblog");
configurator.setExtensionProfileClass(ExtensionProfile.class);
reg.registerFeed(configurator);
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

@ -30,7 +30,14 @@ import org.apache.commons.logging.LogFactory;
* 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>
* 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.
*
*
* @author Simon Willnauer
@ -42,15 +49,23 @@ public class RegistryContextListener implements ServletContextListener {
private static final Log LOG = LogFactory
.getLog(RegistryContextListener.class);
/**
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent arg0) {
LOG.info("RegistryContextListener has been loaded");
try {
RegistryBuilder.buildRegistry();
this.serverRegistry = GDataServerRegistry.getRegistry();
} catch (Exception e) {
this.serverRegistry.destroy();
LOG.error("can not register requiered components", e);
throw new RuntimeException("Can not register required components",
e);
}
}
/**

View File

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

View File

@ -18,11 +18,16 @@ package org.apache.lucene.gdata.servlet;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory;
/**
*
* Provides an abstract class to be subclassed to create an GDATA servlet
@ -44,6 +49,8 @@ public abstract class AbstractGdataServlet extends HttpServlet {
private static final String METHOD_PUT = "PUT";
protected static RequestHandlerFactory HANDLER_FACTORY = null;
/**
* This overwrites the protected <code>service</code> method to dispatch
* the request to the correponding <code>do</code> method. There is
@ -94,4 +101,15 @@ public abstract class AbstractGdataServlet extends HttpServlet {
}
/**
*
* @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

@ -18,16 +18,13 @@ package org.apache.lucene.gdata.servlet;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.servlet.handler.DefaultRequestHandlerFactory;
import org.apache.lucene.gdata.servlet.handler.GDataRequestHandler;
import org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory;
/**
* Provides a clean basic interface for GDATA Client API and requests to the
@ -39,7 +36,6 @@ import org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory;
*
*/
public class RequestControllerServlet extends AbstractGdataServlet {
private static RequestHandlerFactory HANDLER_FACTORY = null;
private static final Log LOGGER = LogFactory.getLog(RequestControllerServlet.class);
/**
@ -56,7 +52,7 @@ public class RequestControllerServlet extends AbstractGdataServlet {
@Override
protected void doDelete(HttpServletRequest arg0, HttpServletResponse arg1)
throws ServletException, IOException {
GDataRequestHandler hanlder = HANDLER_FACTORY.getDeleteHandler();
GDataRequestHandler hanlder = HANDLER_FACTORY.getEntryDeleteHandler();
if(LOGGER.isInfoEnabled())
LOGGER.info("Process DELETE request");
@ -70,10 +66,9 @@ public class RequestControllerServlet extends AbstractGdataServlet {
@Override
protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1)
throws ServletException, IOException {
GDataRequestHandler hanlder = HANDLER_FACTORY.getQueryHandler();
GDataRequestHandler hanlder = HANDLER_FACTORY.getFeedQueryHandler();
if(LOGGER.isInfoEnabled())
LOGGER.info("Process GET request");
hanlder.processRequest(arg0, arg1);
}
@ -84,7 +79,7 @@ public class RequestControllerServlet extends AbstractGdataServlet {
@Override
protected void doPost(HttpServletRequest arg0, HttpServletResponse arg1)
throws ServletException, IOException {
GDataRequestHandler hanlder = HANDLER_FACTORY.getInsertHandler();
GDataRequestHandler hanlder = HANDLER_FACTORY.getEntryInsertHandler();
if(LOGGER.isInfoEnabled())
LOGGER.info("Process POST request");
hanlder.processRequest(arg0, arg1);
@ -97,26 +92,11 @@ public class RequestControllerServlet extends AbstractGdataServlet {
@Override
protected void doPut(HttpServletRequest arg0, HttpServletResponse arg1)
throws ServletException, IOException {
GDataRequestHandler hanlder = HANDLER_FACTORY.getUpdateHandler();
GDataRequestHandler hanlder = HANDLER_FACTORY.getEntryUpdateHandler();
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

@ -30,17 +30,19 @@ 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
*
*/
public abstract class AbstractGdataRequestHandler implements
public abstract class AbstractGdataRequestHandler extends RequestAuthenticator implements
GDataRequestHandler {
private final static Log LOG = LogFactory
.getLog(AbstractGdataRequestHandler.class);
protected Service service;
protected GDataRequest feedRequest;
protected GDataResponse feedResponse;
@ -52,9 +54,10 @@ public abstract class AbstractGdataRequestHandler implements
HttpServletResponse response) throws ServletException, IOException;
protected void initializeRequestHandler(final HttpServletRequest request, final HttpServletResponse response, final GDataRequestType type)
throws GDataRequestException {
throws GDataRequestException, ServletException {
this.feedRequest = new GDataRequest(request, type);
this.feedResponse = new GDataResponse(response);
getService();
try {
this.feedRequest.initializeRequest();
} catch (GDataRequestException e) {
@ -83,12 +86,17 @@ public abstract class AbstractGdataRequestHandler implements
this.feedResponse.setError(error);
}
protected Service getService() throws ServletException {
ServiceFactory serviceFactory = ServiceFactory.getInstance();
Service service = serviceFactory.getService();
if(service == null)
private void getService() throws ServletException {
GDataServerRegistry registry = GDataServerRegistry.getRegistry();
ServiceFactory serviceFactory = registry.lookup(ServiceFactory.class,ComponentType.SERVICEFACTORY);
this.service = serviceFactory.getService();
if(this.service == null)
throw new ServletException("Service not available");
return service;
}
protected void closeService(){
this.service.close();
}

View File

@ -23,9 +23,8 @@ 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.data.GDataAccount.AccountRole;
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;
@ -63,21 +62,21 @@ public class DefaultDeleteHandler extends AbstractGdataRequestHandler {
sendError();
return;
}
Service service = getService();
try {
service.deleteEntry(this.feedRequest, this.feedResponse);
} catch (FeedNotFoundException e) {
LOG.error("Could not process DeleteFeed request Feed Not Found- "
+ e.getMessage(), e);
setError(HttpServletResponse.SC_NOT_FOUND);
if(!authenticateAccount(request,AccountRole.ENTRYAMINISTRATOR)){
setError(HttpServletResponse.SC_UNAUTHORIZED);
sendError();
return;
}
try {
this.service.deleteEntry(this.feedRequest, this.feedResponse);
} catch (ServiceException e) {
LOG.error("Could not process DeleteFeed request - "
+ e.getMessage(), e);
setError(HttpServletResponse.SC_BAD_REQUEST);
sendError();
}
closeService();
}

View File

@ -17,6 +17,7 @@
package org.apache.lucene.gdata.servlet.handler;
import java.io.IOException;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -28,6 +29,7 @@ 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;
@ -42,6 +44,13 @@ import com.google.gdata.data.BaseFeed;
* {@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>
*
*
* @author Simon Willnauer
@ -63,42 +72,67 @@ public class DefaultGetHandler extends AbstractGdataRequestHandler {
sendError();
return;
}
Service service = getService();
try {
String modifiedSince = this.feedRequest.getModifiedSince();
if (!checkIsModified(modifiedSince)) {
this.feedResponse
.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
if (LOG.isInfoEnabled())
LOG.info("Requested output formate: "
+ this.feedRequest.getRequestedResponseFormat());
this.feedResponse.setOutputFormat(this.feedRequest
.getRequestedResponseFormat());
if (this.feedRequest.isFeedRequested()) {
BaseFeed feed = service
.getFeed(this.feedRequest, this.feedResponse);
BaseFeed feed = this.service.getFeed(this.feedRequest,
this.feedResponse);
this.feedResponse.sendResponse(feed, this.feedRequest.getExtensionProfile());
this.feedResponse.sendResponse(feed, this.feedRequest
.getConfigurator().getExtensionProfile());
} else {
BaseEntry entry = service.getSingleEntry(this.feedRequest,this.feedResponse);
if(entry == null){
this.feedResponse.setError(HttpServletResponse.SC_NOT_FOUND);
sendError();
}
this.feedResponse.sendResponse(entry, this.feedRequest.getExtensionProfile());
BaseEntry entry = this.service.getSingleEntry(this.feedRequest,
this.feedResponse);
this.feedResponse.sendResponse(entry, this.feedRequest
.getConfigurator().getExtensionProfile());
}
} catch (ServiceException e) { // TODO handle exceptions to send exact
// response
} catch (ServiceException e) {
LOG.error("Could not process GetFeed request - " + e.getMessage(),
e);
this.feedResponse.setError(HttpServletResponse.SC_BAD_REQUEST); // TODO
// change
// this
sendError();
}
closeService();
}
/**
*
* returns true if the resource has been modified since the specified
* reqeust header value
*/
private boolean checkIsModified(String lastModified)
throws ServiceException {
if (lastModified == null)
return true;
try {
Date clientDate = DateFormater.parseDate(lastModified,DateFormater.HTTP_HEADER_DATE_FORMAT,DateFormater.HTTP_HEADER_DATE_FORMAT_TIME_OFFSET);
Date entityDate;
if (this.feedRequest.isFeedRequested())
entityDate = this.service.getFeedLastModified(this.feedRequest
.getFeedId());
else
entityDate = this.service.getEntryLastModified(this.feedRequest
.getEntryId(),this.feedRequest.getFeedId());
if(LOG.isInfoEnabled())
LOG.info("comparing date clientDate: "+clientDate+"; lastmodified: "+entityDate);
return (entityDate.getTime()-clientDate.getTime() > 1000);
} catch (java.text.ParseException e) {
LOG.info("Couldn't parse Last-Modified header -- "+lastModified,e);
}
return true;
}
}

View File

@ -24,8 +24,8 @@ 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.Service;
import org.apache.lucene.gdata.server.ServiceException;
import org.apache.lucene.gdata.server.GDataRequest.GDataRequestType;
@ -63,20 +63,23 @@ public class DefaultInsertHandler extends AbstractGdataRequestHandler {
sendError();
return;
}
if(!authenticateAccount(this.feedRequest,AccountRole.ENTRYAMINISTRATOR)){
setError(HttpServletResponse.SC_UNAUTHORIZED);
sendError();
return;
}
Service service = getService();
try{
BaseEntry entry = service.createEntry(this.feedRequest,this.feedResponse);
BaseEntry entry = this.service.createEntry(this.feedRequest,this.feedResponse);
setFeedResponseFormat();
setFeedResponseStatus(HttpServletResponse.SC_CREATED);
this.feedResponse.sendResponse(entry, this.feedRequest.getExtensionProfile());
this.feedResponse.sendResponse(entry, this.feedRequest.getConfigurator().getExtensionProfile());
}catch (ServiceException e) {
LOG.error("Could not process GetFeed request - "+e.getMessage(),e);
setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
this.feedResponse.sendError();
}
closeService();
}

View File

@ -16,54 +16,134 @@
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)}
*
* @author Simon Willnauer
*
*/
@Component(componentType=ComponentType.REQUESTHANDLERFACTORY)
public class DefaultRequestHandlerFactory extends RequestHandlerFactory {
DefaultRequestHandlerFactory() {
/**
* public constructor to enable loading via the registry
* @see org.apache.lucene.gdata.server.registry.Component
* @see org.apache.lucene.gdata.server.registry.GDataServerRegistry
*/
public DefaultRequestHandlerFactory() {
//
}
/**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getUpdateHandler()
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getEntryUpdateHandler()
*/
@Override
public GDataRequestHandler getUpdateHandler() {
public GDataRequestHandler getEntryUpdateHandler() {
return new DefaultUpdateHandler();
}
/**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getDeleteHandler()
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getEntryDeleteHandler()
*/
@Override
public GDataRequestHandler getDeleteHandler() {
public GDataRequestHandler getEntryDeleteHandler() {
return new DefaultDeleteHandler();
}
/**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getQueryHandler()
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getFeedQueryHandler()
*/
@Override
public GDataRequestHandler getQueryHandler() {
public GDataRequestHandler getFeedQueryHandler() {
return new DefaultGetHandler();
}
/**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getInsertHandler()
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getEntryInsertHandler()
*/
@Override
public GDataRequestHandler getInsertHandler() {
public GDataRequestHandler getEntryInsertHandler() {
return new DefaultInsertHandler();
}
/**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getInsertAccountHandler()
*/
@Override
public GDataRequestHandler getInsertAccountHandler() {
return new InsertAccountStrategy();
}
/**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getDeleteAccountHandler()
*/
@Override
public GDataRequestHandler getDeleteAccountHandler() {
return new DeleteAccountStrategy();
}
/**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getUpdateAccountHandler()
*/
@Override
public GDataRequestHandler getUpdateAccountHandler() {
return new UpdataAccountStrategy();
}
/**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getInsertFeedHandler()
*/
@Override
public GDataRequestHandler getInsertFeedHandler() {
return new InsertFeedHandler();
}
/**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getUpdateFeedHandler()
*/
@Override
public GDataRequestHandler getUpdateFeedHandler() {
return new UpdateFeedHandler();
}
/**
* @see org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory#getDeleteFeedHandler()
*/
@Override
public GDataRequestHandler getDeleteFeedHandler() {
return new DeleteFeedHandler();
}
/**
* @see org.apache.lucene.gdata.server.registry.ServerComponent#initialize()
*/
public void initialize() {
//
}
/**
* @see org.apache.lucene.gdata.server.registry.ServerComponent#destroy()
*/
public void destroy() {
//
}
}

View File

@ -23,9 +23,8 @@ 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.data.GDataAccount.AccountRole;
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;
@ -62,33 +61,29 @@ public class DefaultUpdateHandler extends AbstractGdataRequestHandler {
try {
initializeRequestHandler(request, response,GDataRequestType.UPDATE);
} catch (GDataRequestException e) {
setError(HttpServletResponse.SC_UNAUTHORIZED);
sendError();
return;
}
if(!authenticateAccount(request,AccountRole.ENTRYAMINISTRATOR)){
sendError();
return;
}
Service service = getService();
try {
BaseEntry entry = service.updateEntry(this.feedRequest,
BaseEntry entry = this.service.updateEntry(this.feedRequest,
this.feedResponse);
setFeedResponseFormat();
setFeedResponseStatus(HttpServletResponse.SC_OK);
this.feedResponse.sendResponse(entry, this.feedRequest.getExtensionProfile());
}catch (FeedNotFoundException e) {
LOG.error("Could not process UpdateFeed request - "
+ e.getMessage(), e);
setError(HttpServletResponse.SC_NOT_FOUND);
this.feedResponse.sendResponse(entry, this.feedRequest.getConfigurator().getExtensionProfile());
sendError();
}
catch (ServiceException e) {
LOG.error("Could not process UpdateFeed request - "
+ e.getMessage(), e);
setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
sendError();
}
closeService();
}
}

View File

@ -16,107 +16,83 @@
package org.apache.lucene.gdata.servlet.handler;
import org.apache.lucene.gdata.server.registry.ServerComponent;
/**
* Abstract Superclass for RequestHandlerFactories
* @author Simon Willnauer
*
*/
public abstract class RequestHandlerFactory {
public abstract class RequestHandlerFactory implements ServerComponent {
private static RequestHandlerFactory INSTANCE = null;
/**
* This method creates a singleton instance of the given type. The fist call
* will create an instance of the given class which will be returned in
* every subsequent call. Any subsequent call to this method will ignore the
* given class object.
*
* @param factoryImplementation -
* the factory implementation (must be a subtype of this Class)
*
* @return - a singleton instance of the given type
*
* public constructor to enable loading via the registry
* @see org.apache.lucene.gdata.server.registry.Component
* @see org.apache.lucene.gdata.server.registry.GDataServerRegistry
*/
public static synchronized RequestHandlerFactory getInstance(
Class factoryImplementation) {
if (INSTANCE == null) {
INSTANCE = createInstance(factoryImplementation);
}
return INSTANCE;
}
/**
* Singleton - Pattern using private constructor
*
*/
RequestHandlerFactory() {
public RequestHandlerFactory() {
super();
}
private static RequestHandlerFactory createInstance(
final Class qualifiedClass) {
if (qualifiedClass == null)
throw new IllegalArgumentException(
"Factory class is null -- must be a implementation of org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory");
try {
return (RequestHandlerFactory) qualifiedClass.newInstance();
} catch (Exception e) {
FactoryImplementationException ex = new FactoryImplementationException(
"Factory implementation could not be created", e.getCause());
ex.setStackTrace(e.getStackTrace());
throw ex;
}
}
/**
* Creates a UpdateHandler which processes a GDATA UPDATE request.
* @return - an RequestHandlerInstance
* Creates a EntryUpdateHandler which processes a GDATA UPDATE request.
* @return - a RequestHandlerInstance
*/
public abstract GDataRequestHandler getUpdateHandler();
public abstract GDataRequestHandler getEntryUpdateHandler();
/**
* Creates a DeleteHandler which processes a GDATA DELETE request.
* @return - an RequestHandlerInstance
* Creates a EntryDeleteHandler which processes a GDATA DELETE request.
* @return - a RequestHandlerInstance
*/
public abstract GDataRequestHandler getDeleteHandler();
public abstract GDataRequestHandler getEntryDeleteHandler();
/**
* Creates a QueryHandler which processes a GDATA Query / Get request.
* @return - an RequestHandlerInstance
* Creates a FeedQueryHandler which processes a GDATA Query / Get request.
* @return - a RequestHandlerInstance
*/
public abstract GDataRequestHandler getQueryHandler();
public abstract GDataRequestHandler getFeedQueryHandler();
/**
* Creates a InsertHandler which processes a GDATA Insert request.
* @return - an RequestHandlerInstance
* Creates a EntryInsertHandler which processes a GDATA Insert request.
* @return - a RequestHandlerInstance
*/
public abstract GDataRequestHandler getInsertHandler();
private static class FactoryImplementationException extends
RuntimeException {
public abstract GDataRequestHandler getEntryInsertHandler();
/**
*
* Creates a InsertAccountHandler which processes a Account Insert request.
* @return - a RequestHandlerInstance
*/
private static final long serialVersionUID = 3166033278825112569L;
public abstract GDataRequestHandler getInsertAccountHandler();
/**
* Constructs a new FactoryImplementationException with the specified
* cause and message
*
* @param arg0 -
* the detail message
* @param arg1 -
* the throw cause
* Creates a DeleteAccountHandler which processes a Account Delete request.
* @return - a RequestHandlerInstance
*/
public FactoryImplementationException(String arg0, Throwable arg1) {
super(arg0, arg1);
}
}
public abstract GDataRequestHandler getDeleteAccountHandler();
/**
* Creates a UpdateAccountHandler which processes a Account Update request.
* @return - a RequestHandlerInstance
*/
public abstract GDataRequestHandler getUpdateAccountHandler();
/**
* Creates a InsertFeedHandler which processes a Feed Insert request.
* @return - a RequestHandlerInstance
*/
public abstract GDataRequestHandler getInsertFeedHandler();
/**
* Creates a UpdateFeedHandler which processes a Feed Insert request.
* @return - a RequestHandlerInstance
*/
public abstract GDataRequestHandler getUpdateFeedHandler();
/**
* Creates a DeleteFeedHandler which processes a Feed Insert request.
* @return - a RequestHandlerInstance
*/
public abstract GDataRequestHandler getDeleteFeedHandler();
}

View File

@ -53,6 +53,8 @@ public class IDGenerator {
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
* default capacity is 10. Every given parameter less than 10 will be
@ -92,6 +94,8 @@ public class IDGenerator {
UIDProducer producer = new UIDProducer(this.blockingQueue,
this.secureRandom, this.mdigest);
this.runner = new Thread(producer);
this.runner.setDaemon(true);
this.runner.setName(RUNNER_THREAD_NAME);
this.runner.start();
}
}

View File

@ -15,86 +15,260 @@
*/
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 org.apache.lucene.gdata.data.ServerBaseFeed;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.BaseFeed;
import com.google.gdata.data.ExtensionProfile;
/**
* This is the main storage interface. The Storage represents the internal
* server storage. It acts as a Database to persist the feed data.
* This inferface is not public yet!!
* A interface every storage implementation must provide to access the
* <tt>Storage</tt>. It describes all access methodes needed to store,
* retrieve and look up data stored in the <tt>Storage</tt> component. This
* interface acts as a <tt>Facade</tt> to hide the storage implementation from
* the user.
* <p>
* This could also act as a proxy for a remote storage. It also removes any
* restrictions from custom storage implementations.
* </p>
*
*
* @author Simon Willnauer
*
*/
/*
* not final yet
*/
public interface Storage {
/**
* This stores an incoming entry for a later retrival.
* The Entry will be associated with the feedid.
* @param entry - the entry
* @param feedId - the feedID
* @return - the stored Entry
* @throws StorageException
*
* Stores the given entry. The ServerBaseEntry must provide a feed id and
* the service type. configuration for the entry.
*
* @param entry -
* the entry to store
*
* @return - the stored Entry for the server response
* @throws StorageException -
* if the entry can not be stored or required field are not set.
*/
public abstract BaseEntry storeEntry(BaseEntry entry, String feedId)
public abstract BaseEntry storeEntry(ServerBaseEntry entry)
throws StorageException;
/**
* @param entryId
* @param feedId
* @throws StorageException
* Deletes the given entry. The ServerBaseEntry just hase to provide the
* entry id to be deleted.
*
* @param entry -
* the entry to delete from the storage
* @throws StorageException -
* if the entry can not be deleted or the entry does not exist
* or required field are not set.
*/
public abstract void deleteEntry(String entryId, String feedId)
public abstract void deleteEntry(ServerBaseEntry entry)
throws StorageException;
/**
* @param entry
* @param feedId
* @return
* @throws StorageException
* Updates the given entry. The ServerBaseEntry must provide a feed id,
* service id and the
* {@link org.apache.lucene.gdata.server.registry.ProvidedService}
*
* @param entry -
* the entry to update
*
* @return - the updated entry for server response.
* @throws StorageException -
* if the entry can not be updated or does not exist or required
* field are not set.
*/
public abstract BaseEntry updateEntry(BaseEntry entry, String feedId)
public abstract BaseEntry updateEntry(ServerBaseEntry entry)
throws StorageException;
/**
* @param feedId
* @param startIndex
* @param resultCount
* @return
* @throws StorageException
* Retrieves the requested feed from the storage. The given ServerBaseFeed
* must provide information about the feed id, max-result count and the
* start index. To create feeds and entries also the service type must be
* provided.
*
* @param feed -
* the to retieve from the storage
* @return the requested feed
* @throws StorageException -
* the feed does not exist or can not be retrieved or required
* field are not set.
*/
public abstract BaseFeed getFeed(String feedId, int startIndex,
int resultCount) throws StorageException;
/**
* @param entryId
* @param feedId
* @return
* @throws StorageException
*/
public abstract BaseEntry getEntry(String entryId, String feedId)
public abstract BaseFeed getFeed(ServerBaseFeed feed)
throws StorageException;
/**
* @param entryIdList
* @param feedId
* @return
* @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 List<BaseEntry> getEntries(List<String> entryIdList,
String feedId) throws StorageException;
public abstract BaseEntry getEntry(ServerBaseEntry entry)
throws StorageException;
/**
* @param profile
* 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 setExtensionProfile(final ExtensionProfile profile);
public abstract void storeAccount(final GDataAccount account)
throws StorageException;
/**
* close this storage instance
* 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

@ -15,13 +15,47 @@
*/
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>
*
*
* @author Simon Willnauer
*
*/
public interface StorageController {
public interface StorageController extends ServerComponent {
/**
* Destroys the controller
* Destroys the controller - this method is called by the registry when the
* context will be destroyed
*/
public abstract void destroy();
/**
* Creates Storage instances to access the underlaying storage component
*
* @return a storage instance
* @throws StorageException -
* if the storage instance can not be created
*/
public abstract Storage getStorage() throws StorageException;
}

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

@ -20,8 +20,11 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@ -30,6 +33,10 @@ 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 storage. The storage uses an lucene index to store the enries. As
@ -57,6 +64,8 @@ public class StorageBuffer {
private final Map<String, Map<String, StorageEntryWrapper>> bufferMap;
private final Map<String, Long> modifiyMap;
private final List<String> excludeList;
private final ReadWriteLock lock = new ReentrantReadWriteLock(true);
@ -86,6 +95,9 @@ public class StorageBuffer {
this.excludeList = new ArrayList<String>(
expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT
: expectedBufferCount);
this.modifiyMap = new HashMap<String, Long>(
expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT
: expectedBufferCount);
}
/**
@ -114,7 +126,9 @@ public class StorageBuffer {
20);
newFeedMap.put(wrapper.getEntryId(), wrapper);
this.bufferMap.put(feedId, newFeedMap);
}
addLastModified(wrapper.getFeedId(),wrapper.getTimestamp());
} finally {
/*
* add all to exclude from searches doc will be available via the
@ -125,6 +139,22 @@ public class StorageBuffer {
}
}
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
* desc.
@ -173,6 +203,7 @@ public class StorageBuffer {
if (tempMap == null)
return;
tempMap.remove(entryId);
this.addLastModified(feedId,new Long(System.currentTimeMillis()));
} finally {
this.writeLock.unlock();
@ -230,6 +261,7 @@ public class StorageBuffer {
private void clearBuffer() {
this.bufferMap.clear();
this.excludeList.clear();
this.modifiyMap.clear();
}
@ -246,4 +278,35 @@ 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

@ -6,48 +6,76 @@ import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.server.registry.Component;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.storage.IDGenerator;
import org.apache.lucene.gdata.storage.Storage;
import org.apache.lucene.gdata.storage.StorageController;
import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.gdata.storage.lucenestorage.configuration.StorageConfigurator;
import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter;
import org.apache.lucene.index.IndexModifier;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.RAMDirectory;
/**
* TODO document this
*
*
* @author Simon Willnauer
*
*/
@Component(componentType = ComponentType.STORAGECONTROLLER)
public class StorageCoreController implements StorageController {
protected static final Log LOG = LogFactory.getLog(StorageCoreController.class);
protected static final Log LOG = LogFactory
.getLog(StorageCoreController.class);
private IndexSearcher searcher;
private static StorageCoreController coreController;
private final Directory storageDir;
private final StorageModifier modifier;
private ReferenceCounter<StorageQuery> storageQuery;
private StorageBuffer currentBuffer;
private Object storageControllerLock = new Object();
private static final int DEFAULT_STORAGE_BUFFER_SIZE = 10;
private static final int DEFAULT_STORAGE_PERSIST_FACTOR = 10;
private static final String STORAGELOG = ".lucenestorage";
private int storageBufferSize;
private int storagePersistFactor;
private StorageConfigurator configurator;
private IDGenerator idGenerator;
private int indexOptimizeInterval;
private StorageCoreController()throws IOException, StorageException{
this(null);
}
// private RecoverController recoverController;
private StorageCoreController(final Directory dir) throws IOException, StorageException {
/**
* 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);
@ -56,94 +84,95 @@ public class StorageCoreController implements StorageController{
}
boolean createNewStorage = false;
if(dir == null){
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);
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);
this.storageDir = FSDirectory.getDirectory(
storeDir, true);
createNewStorage = true;
}
else
throw new StorageException("could not create storage log file in "+storageDirPath);
} else
throw new StorageException(
"could not create storage lock file in "
+ storageDirPath);
} else
this.storageDir = FSDirectory.getDirectory(storeDir,false);
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();
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;
} else
this.storageDir = getRamDirectory();
this.currentBuffer = new StorageBuffer(this.storageBufferSize);
this.modifier = createStorageModifier(createNewStorage);
this.searcher = new IndexSearcher(this.storageDir);
GDataServerRegistry.getRegistry().registerStorage(this);// TODO reverse dependency here
// 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(indexModifier,this.currentBuffer,this.storagePersistFactor,this.indexOptimizeInterval);
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);
}
/**TODO document this
* @return
/**
* returns the current storage modifier
*
* @return - the current storage modifier
*/
public StorageModifier getStorageModifier(){
protected StorageModifier getStorageModifier() {
return this.modifier;
}
/**TODO document this
* @return
* @throws IOException
* @throws StorageException
/**
* 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.
*
*/
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 {
protected ReferenceCounter<StorageQuery> getStorageQuery() {
synchronized (this.storageControllerLock) {
if (this.storageQuery == null) {
this.storageQuery = getNewStorageQueryHolder(new StorageQuery(this.currentBuffer,this.searcher));
this.storageQuery = getNewStorageQueryHolder(new StorageQuery(
this.currentBuffer, this.searcher));
if (LOG.isInfoEnabled())
LOG.info("Relese new StorageQuery");
}
@ -152,15 +181,19 @@ public class StorageCoreController implements StorageController{
}
}
private ReferenceCounter<StorageQuery> getNewStorageQueryHolder(final StorageQuery query){
ReferenceCounter<StorageQuery> holder = new ReferenceCounter<StorageQuery>(query){
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");
LOG
.info("close StorageQuery -- zero references remaining");
this.resource.close();
} catch (IOException e) {
LOG.warn("Error during close call on StorageQuery"+e.getMessage(),e);
LOG.warn("Error during close call on StorageQuery"
+ e.getMessage(), e);
}
}
};
@ -168,8 +201,14 @@ public class StorageCoreController implements StorageController{
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");
@ -184,83 +223,111 @@ public class StorageCoreController implements StorageController{
}
/**
* Creates a new StorageBuffer
*
* @return the new StorageBuffer
*/
protected StorageBuffer releaseNewStorageBuffer() {
synchronized (this.storageControllerLock) {
return this.currentBuffer;
}
}
/**TODO document this
* @return
* @throws IOException
/**
* Creates a new IndexModifier on the storage index
*
* @return - a new modifier
* @throws IOException -
* if an IO exception occures
*/
public IndexModifier createIndexModifier() throws IOException {
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);
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");
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
/**
* 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;
}
/**TODO document this
* @return
/**
* 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;
}
/**
* @throws IOException
* @throws StorageException
* Forces the StorageModifier to write all buffered changes.
*
* @throws IOException -
* if an IO exception occures
*
*/
public void forceWrite()throws IOException, StorageException{
public void forceWrite() throws IOException {
this.modifier.forceWrite();
}
private boolean createLuceneStorageLog(File storageDirectory) throws IOException{
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);
File file = new File(storageDirectory.getAbsolutePath()
+ System.getProperty("file.separator") + STORAGELOG);
return file.createNewFile();
}
/**TODO document this
* @return
* @throws StorageException
/**
* 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 {
@ -271,8 +338,6 @@ public class StorageCoreController implements StorageController{
}
/**
* @see org.apache.lucene.gdata.storage.StorageController#destroy()
*/
@ -280,7 +345,54 @@ public class StorageCoreController implements StorageController{
try {
close();
} catch (Exception e) {
LOG.error("Closing StorageCoreController failed -- "+e.getMessage(),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();
StorageAccountWrapper wrapper = new StorageAccountWrapper(adminAccount);
this.getStorageModifier().createAccount(wrapper);
}
}

View File

@ -21,20 +21,27 @@ import java.io.StringWriter;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.gdata.data.ServerBaseEntry;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.server.registry.ProvidedServiceConfig;
import org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer.BufferableEntry;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.util.common.xml.XmlWriter;
/**
* This immutable class wrapps Entries for an internal Storage representation of
* an entry. This class also acts as a Documentfactory for lucene documents to
* be stored inside the index.
* This immutable class wrapps <tt>ServerBaseEntry</tt> for an internal
* Storage representation of an entry. This class also acts as a Documentfactory
* for lucene documents to be stored inside the index.
*
* @author Simon Willnauer
*
*/
public class StorageEntryWrapper implements Comparable<StorageEntryWrapper> {
public class StorageEntryWrapper implements Comparable<StorageEntryWrapper>,
StorageWrapper {
private static final long serialVersionUID = -4619985652059888526L;
private static final String INTERNAL_ENCODING = "UTF-8";
/**
@ -45,7 +52,7 @@ public class StorageEntryWrapper implements Comparable<StorageEntryWrapper> {
/**
* lucene field name feed id
*/
public final static String FIELD_FEED_ID = "feedId";
public final static String FIELD_FEED_REFERENCE = "feedReference";
/**
* lucene field name entry content
@ -61,67 +68,73 @@ public class StorageEntryWrapper implements Comparable<StorageEntryWrapper> {
private final String feedId;
private final String content;
private String content;
private final transient BaseEntry entry;
private final ServerBaseEntry entry;
private final Long timestamp;
private Long timestamp;
private transient Document document;
private StorageOperation operation;
private final ExtensionProfile profile;
private ProvidedService config;
/**
* Creates a new StorageEntryWrapper.
*
* @param entry -
* the entry to wrap
* @param feedId -
* the feed id
*
* @param operation -
* the StorageOperation
* @param profile -
* the ExtensionProfil for the given entry
*
* @throws IOException -
* if the entry content can not be generated
*/
protected StorageEntryWrapper(final BaseEntry entry, final String feedId,
StorageOperation operation, final ExtensionProfile profile)
throws IOException {
public StorageEntryWrapper(final ServerBaseEntry entry,
StorageOperation operation) throws IOException {
this.entry = entry;
this.operation = operation;
this.entryId = entry.getId();
this.feedId = feedId;
this.profile = profile;
this.feedId = entry.getFeedId();
if (operation != StorageOperation.DELETE) {
this.config = entry.getServiceConfig();
this.content = buildContent();
this.timestamp = new Long(System.currentTimeMillis());
}
this.timestamp = new Long(
this.entry.getUpdated() != null ? this.entry.getUpdated()
.getValue() : System.currentTimeMillis());
}
private String buildContent() throws IOException {
StringWriter writer = new StringWriter();
XmlWriter xmlWriter = new XmlWriter(writer, INTERNAL_ENCODING);
this.entry.generateAtom(xmlWriter, this.profile);
this.entry.generateAtom(xmlWriter, this.config.getExtensionProfile());
return writer.toString();
}
/**
* @return - the lucene document representing the entry
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageWrapper#getLuceneDocument()
*/
public Document getLuceneDocument() {
if(this.operation == StorageOperation.DELETE)
return null;
if (this.document != null)
return this.document;
this.document = new Document();
this.document.add(new Field("entryId", this.entryId, Field.Store.YES,
Field.Index.UN_TOKENIZED));
this.document.add(new Field("feedId", this.feedId, Field.Store.YES,
Field.Index.UN_TOKENIZED));
this.document.add(new Field("content", this.content,
Field.Store.COMPRESS, Field.Index.UN_TOKENIZED));
this.document.add(new Field("timestamp", this.timestamp.toString(),
this.document.add(new Field(FIELD_ENTRY_ID, this.entryId,
Field.Store.YES, Field.Index.UN_TOKENIZED));
this.document.add(new Field(FIELD_FEED_REFERENCE, this.feedId,
Field.Store.YES, Field.Index.UN_TOKENIZED));
this.document.add(new Field(FIELD_CONTENT, this.content,
Field.Store.COMPRESS, Field.Index.NO));
this.document.add(new Field(FIELD_TIMESTAMP, this.timestamp.toString(),
Field.Store.YES, Field.Index.UN_TOKENIZED));
return this.document;
@ -132,7 +145,11 @@ public class StorageEntryWrapper implements Comparable<StorageEntryWrapper> {
* @return - the wrapped entry
*/
public BaseEntry getEntry() {
return this.entry;
/*
* this wrapps the entry again. BufferableEntry creates a new instance
* for the dynamic element like links.
*/
return new BufferableEntry(this.entry.getEntry());
}
/**
@ -178,11 +195,32 @@ public class StorageEntryWrapper implements Comparable<StorageEntryWrapper> {
}
/**
* @see java.lang.Comparable#compareTo(T)
* 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

@ -17,19 +17,23 @@
package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.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;
import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.data.Feed;
/**
* This is an implementation of the
@ -47,8 +51,6 @@ import com.google.gdata.data.Feed;
public class StorageImplementation implements Storage {
private final StorageCoreController controller;
private ExtensionProfile profile;
private static final Log LOG = LogFactory
.getLog(StorageImplementation.class);
@ -56,40 +58,36 @@ public class StorageImplementation implements Storage {
* Creates a new StorageImplementation
*
* @throws StorageException -
* if the
* {@link org.apache.lucene.gdata.storage.StorageController} can
* not be created
* @throws IOException -
* if the
* {@link org.apache.lucene.gdata.storage.StorageController} can
* not be created
* @see StorageCoreController#getStorageCoreController()
* if the storage controller can not be obtained
*
*
*
*/
public StorageImplementation() throws IOException, StorageException {
this.controller = StorageCoreController.getStorageCoreController();
public StorageImplementation() throws StorageException {
this.controller = (StorageCoreController) GDataServerRegistry
.getRegistry().lookup(StorageController.class,
ComponentType.STORAGECONTROLLER);
if (this.controller == null)
throw new StorageException("Can't get registered StorageController");
}
/**
* @see org.apache.lucene.gdata.storage.Storage#storeEntry(com.google.gdata.data.BaseEntry,
* java.lang.String)
* @see org.apache.lucene.gdata.storage.Storage#storeEntry(org.apache.lucene.gdata.data.ServerBaseEntry)
*/
public BaseEntry storeEntry(BaseEntry entry, String feedId)
public BaseEntry storeEntry(final ServerBaseEntry entry)
throws StorageException {
if (this.profile == null)
throw new StorageException(
"Can process ExtensionProfile not set -- is null");
if (feedId == null)
throw new StorageException("No feed ID specified -- is null");
if (entry == null)
throw new StorageException("entry is null");
StorageModifier modifier = this.controller.getStorageModifier();
String id = this.controller.releaseID();
entry.setId(feedId + id);
entry.setId(entry.getFeedId() + id);
if (LOG.isInfoEnabled())
LOG.info("Store entry " + id + " -- feed: " + feedId);
LOG.info("Store entry " + id + " -- feed: " + entry.getFeedId());
try {
StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,
feedId, StorageOperation.INSERT, this.profile);
StorageOperation.INSERT);
modifier.insertEntry(wrapper);
} catch (IOException e) {
StorageException ex = new StorageException("Can't create Entry -- "
@ -99,53 +97,63 @@ public class StorageImplementation implements Storage {
}
return entry;
return entry.getEntry();
}
/**
* @see org.apache.lucene.gdata.storage.Storage#deleteEntry(java.lang.String,
* java.lang.String)
* @see org.apache.lucene.gdata.storage.Storage#deleteEntry(org.apache.lucene.gdata.data.ServerBaseEntry)
*/
public void deleteEntry(String entryId, String feedId)
public void deleteEntry(final ServerBaseEntry entry)
throws StorageException {
if (this.profile == null)
throw new StorageException(
"Can process ExtensionProfile not set -- is null");
if (feedId == null)
throw new StorageException("No feed ID specified -- is null");
if (entryId == null)
throw new StorageException("No entry ID specified -- is null");
if (LOG.isInfoEnabled())
LOG.info("delete entry " + entryId + " -- feed: " + feedId);
StorageModifier modifier = this.controller.getStorageModifier();
modifier.deleteEntry(entryId, feedId);
}
/**
* @see org.apache.lucene.gdata.storage.Storage#updateEntry(com.google.gdata.data.BaseEntry,
* java.lang.String)
*/
public BaseEntry updateEntry(BaseEntry entry, String feedId)
throws StorageException {
if (this.profile == null)
throw new StorageException(
"Can process ExtensionProfile not set -- is null");
if (feedId == null)
throw new StorageException("No feed ID specified -- is null");
if (entry == null)
throw new StorageException("enrty is null");
if (entry.getId() == null)
throw new StorageException("No entry ID specified -- is null");
if (LOG.isInfoEnabled())
LOG.info("update entry " + entry.getId() + " -- feed: " + feedId);
StorageModifier modifier = this.controller.getStorageModifier();
throw new StorageException("Entry is null");
if (LOG.isInfoEnabled())
LOG.info("delete entry " + entry.getId() + " -- feed: "
+ entry.getFeedId());
StorageModifier modifier = this.controller.getStorageModifier();
ReferenceCounter<StorageQuery> query = this.controller.getStorageQuery();
try{
if(query.get().isEntryStored(entry.getId(),entry.getFeedId())){
modifier.deleteEntry(new StorageEntryWrapper(entry,StorageOperation.DELETE));
}
else
throw new ResourceNotFoundException("Entry for entry id: "+entry.getId()+" is not stored");
}catch (IOException e) {
throw new StorageException("Can not access storage");
}finally{
query.decrementRef();
}
}
/**
* @see org.apache.lucene.gdata.storage.Storage#updateEntry(org.apache.lucene.gdata.data.ServerBaseEntry)
*/
public BaseEntry updateEntry(ServerBaseEntry entry) throws StorageException {
if (entry == null)
throw new StorageException("entry is null");
if(entry.getId() == null)
throw new StorageException("entry id is null");
if(entry.getFeedId() == null)
throw new StorageException("feed id is null");
if (LOG.isInfoEnabled())
LOG.info("update entry " + entry.getId() + " -- feed: "
+ entry.getFeedId());
StorageModifier modifier = this.controller.getStorageModifier();
ReferenceCounter<StorageQuery> query = this.controller.getStorageQuery();
try {
StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,
feedId, StorageOperation.UPDATE, this.profile);
StorageOperation.UPDATE);
if(query.get().isEntryStored(entry.getId(),entry.getFeedId()))
modifier.updateEntry(wrapper);
else
throw new ResourceNotFoundException("Entry for entry id: "+entry.getId()+" is not stored");
} catch (IOException e) {
LOG.error("Can't update entry for feedID: " + feedId
LOG.error("Can't update entry for feedID: " + entry.getFeedId()
+ "; entryId: " + entry.getId() + " -- " + e.getMessage(),
e);
StorageException ex = new StorageException("Can't create Entry -- "
@ -155,36 +163,32 @@ public class StorageImplementation implements Storage {
}
return entry;
return entry.getEntry();
}
/**
* @see org.apache.lucene.gdata.storage.Storage#getFeed(java.lang.String,
* int, int)
* @see org.apache.lucene.gdata.storage.Storage#getFeed(org.apache.lucene.gdata.data.ServerBaseFeed)
*/
@SuppressWarnings("unchecked")
public BaseFeed getFeed(String feedId, int startIndex, int resultCount)
throws StorageException {
if (this.profile == null)
throw new StorageException(
"Can process ExtensionProfile not set -- is null");
if (feedId == null)
throw new StorageException("No feed ID specified -- is null");
public BaseFeed getFeed(final ServerBaseFeed feed) throws StorageException {
if (feed == null)
throw new StorageException("feed is null");
if (LOG.isInfoEnabled())
LOG.info("get feed: " + feedId + " startindex: " + startIndex
+ " resultCount: " + resultCount);
LOG.info("get feed: " + feed.getId() + " startindex: "
+ feed.getStartIndex() + " resultCount: "
+ feed.getItemsPerPage());
ReferenceCounter<StorageQuery> query = null;
try {
query = this.controller.getStorageQuery();
List<BaseEntry> resultList = query.get().getLatestFeedQuery(feedId,
resultCount, startIndex, this.profile);
BaseFeed feed = new Feed();
feed.getEntries().addAll(resultList);
return feed;
BaseFeed retVal = query.get().getLatestFeedQuery(feed.getId(),
feed.getItemsPerPage(), feed.getStartIndex(),
feed.getServiceConfig());
return retVal;
} catch (Exception e) {
LOG.error("Can't get latest feed for feedID: " + feedId + " -- "
+ e.getMessage(), e);
LOG.error("Can't get latest feed for feedID: " + feed.getId()
+ " -- " + e.getMessage(), e);
StorageException ex = new StorageException("Can't create Entry -- "
+ e.getMessage(), e);
ex.setStackTrace(e.getStackTrace());
@ -198,27 +202,28 @@ public class StorageImplementation implements Storage {
}
/**
* @see org.apache.lucene.gdata.storage.Storage#getEntry(java.lang.String,
* java.lang.String)
* @see org.apache.lucene.gdata.storage.Storage#getEntry(org.apache.lucene.gdata.data.ServerBaseEntry)
*/
public BaseEntry getEntry(String entryId, String feedId)
public BaseEntry getEntry(final ServerBaseEntry entry)
throws StorageException {
if (this.profile == null)
throw new StorageException(
"Can process ExtensionProfile not set -- is null");
if (feedId == null)
throw new StorageException("No feed ID specified -- is null");
if (entryId == null)
throw new StorageException("No entry ID specified -- is null");
if (entry == null)
throw new StorageException("No entry specified -- is null");
if (LOG.isInfoEnabled())
LOG.info("get entry " + entryId + " -- feed: " + feedId);
LOG.info("get entry " + entry.getId() + " -- feed: "
+ entry.getFeedId());
ReferenceCounter<StorageQuery> query = null;
try {
query = this.controller.getStorageQuery();
return query.get().singleEntryQuery(entryId, feedId, this.profile);
BaseEntry retVal = query.get().singleEntryQuery(entry.getId(),
entry.getFeedId(), entry.getServiceConfig());
if(retVal == null)
throw new ResourceNotFoundException("can not get entry for entry ID "+entry.getId());
return retVal;
} catch (Exception e) {
LOG.error("Can't get entry for feedID: " + feedId + "; entryId: "
+ entryId + " -- " + e.getMessage(), e);
LOG.error("Can't get entry for feedID: " + entry.getFeedId()
+ "; entryId: " + entry.getId() + " -- " + e.getMessage(),
e);
StorageException ex = new StorageException("Can't create Entry -- "
+ e.getMessage(), e);
ex.setStackTrace(e.getStackTrace());
@ -231,17 +236,6 @@ public class StorageImplementation implements Storage {
}
/**
* @see org.apache.lucene.gdata.storage.Storage#getEntries(java.util.List,
* java.lang.String)
*/
public List<BaseEntry> getEntries(List<String> entryIdList, String feedId)
throws StorageException {
throw new StorageException("not implemented yet");
// TODO implement this
}
/**
* @see org.apache.lucene.gdata.storage.Storage#close()
*/
@ -250,10 +244,283 @@ public class StorageImplementation implements Storage {
}
/**
* @see org.apache.lucene.gdata.storage.Storage#setExtensionProfile(com.google.gdata.data.ExtensionProfile)
* @see org.apache.lucene.gdata.storage.Storage#storeAccount(org.apache.lucene.gdata.data.GDataAccount)
*/
public void setExtensionProfile(ExtensionProfile profile) {
this.profile = profile;
public void storeAccount(GDataAccount Account) throws StorageException {
if (Account == null)
throw new StorageException("Can not save null Account");
ReferenceCounter<StorageQuery> query = null;
try {
query = this.controller.getStorageQuery();
if (query.get().getUser(Account.getName()) != null)
throw new StorageException("Account already exists");
StorageModifier modifier = this.controller.getStorageModifier();
StorageAccountWrapper wrapper = new StorageAccountWrapper(Account);
modifier.createAccount(wrapper);
} catch (Exception e) {
LOG.error("Can't save Account -- " + e.getMessage(), e);
StorageException ex = new StorageException("Can't save Account -- "
+ e.getMessage(), e);
ex.setStackTrace(e.getStackTrace());
throw ex;
} finally {
if (query != null)
query.decrementRef();
}
}
/**
* @see org.apache.lucene.gdata.storage.Storage#updateAccount(org.apache.lucene.gdata.data.GDataAccount)
*/
public void updateAccount(GDataAccount Account) throws StorageException {
if (Account == null)
throw new StorageException("Can not update null Account");
ReferenceCounter<StorageQuery> query = null;
try {
query = this.controller.getStorageQuery();
if (query.get().getUser(Account.getName()) == null)
throw new StorageException("Account does not exist");
StorageModifier modifier = this.controller.getStorageModifier();
StorageAccountWrapper wrapper = new StorageAccountWrapper(Account);
modifier.updateAccount(wrapper);
} catch (Exception e) {
LOG.error("Can't update Account -- " + e.getMessage(), e);
StorageException ex = new StorageException(
"Can't update Account -- " + e.getMessage(), e);
ex.setStackTrace(e.getStackTrace());
throw ex;
} finally {
if (query != null)
query.decrementRef();
}
}
/**
* @see org.apache.lucene.gdata.storage.Storage#deleteAccount(java.lang.String)
*/
public void deleteAccount(String Accountname) throws StorageException {
if (Accountname == null)
throw new StorageException("can not delete null Account");
ReferenceCounter<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,6 +1,7 @@
package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
@ -13,11 +14,32 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.document.Document;
import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
import org.apache.lucene.index.IndexModifier;
import org.apache.lucene.index.Term;
/**
* TODO document this
* 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
*
*/
@ -25,10 +47,14 @@ public class StorageModifier {
protected static final Log LOG = LogFactory.getLog(StorageModifier.class);
private final List<Term> deletedDocumentQueue;
private final List<Term> deletedForUpdateDocumentQueue;
private final Map<String, Document> documentMap;
private final List<Document> forceWriteDocuments;
private final List<Term> forceWriteTerms;
private volatile int persistFactor;
@ -45,44 +71,70 @@ public class StorageModifier {
private Lock readLock = this.lock.readLock();
private Lock writeLock = this.lock.writeLock();
private final static int DEFAULT_OPTIMIZE_INTERVAL = 10;
private final int optimizeInterval;
private int optimizeCounter = 0;
private volatile int optimizeCounter = 0;
private final StorageCoreController controller;
/**
* TODO document this
* @param modifier
* @param buffer
* @param persitsFactor
* @param optimizeInterval
* Creates a new StorageModifier
*
* @param controller -
* the registered StorageController
* @param modifier -
* the IndexModifier
* @param buffer -
* the StorageBuffer
* @param persitsFactor -
* the factor when the changes will be persisted to the storage
* index
* @param optimizeInterval -
* after how many storage operations the index will be optimized
*/
public StorageModifier(final IndexModifier modifier,
final StorageBuffer buffer, int persitsFactor,int optimizeInterval) {
protected StorageModifier(final StorageCoreController controller,
final IndexModifier modifier, final StorageBuffer buffer,
int persitsFactor, int optimizeInterval) {
this.deletedDocumentQueue = new LinkedList<Term>();
this.deletedForUpdateDocumentQueue = new LinkedList<Term>();
this.documentMap = new HashMap<String, Document>(persitsFactor);
this.forceWriteDocuments = new ArrayList<Document>(5);
this.forceWriteTerms = new ArrayList<Term>(5);
this.buffer = buffer;
this.controller = controller;
this.persistFactor = persitsFactor > 0 ? persitsFactor
: DEFAULT_PERSIST_FACTOR;
this.modifier = modifier;
this.optimizeInterval = optimizeInterval < DEFAULT_OPTIMIZE_INTERVAL?DEFAULT_OPTIMIZE_INTERVAL:optimizeInterval;
this.optimizeInterval = optimizeInterval < DEFAULT_OPTIMIZE_INTERVAL ? DEFAULT_OPTIMIZE_INTERVAL
: optimizeInterval;
}
/**
* TODO document this
* @param wrapper
* @throws StorageException
* Updates the given entry. First the alredy persisted entry will be
* removed, after marking as deleted the new Entry will be written.
*
* @param wrapper -
* the wrapper containing the entry
* @throws StorageException -
* if the entry can not be stored
*/
public void updateEntry(StorageEntryWrapper wrapper)
throws StorageException {
try {
if(wrapper.getOperation() != StorageOperation.UPDATE)
throw new StorageException("Illegal method call -- updateEntry does not accept other storageOperations than update");
this.readLock.lock();
Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID, wrapper.getEntryId());
this.buffer.addEntry(wrapper);
try {
Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID,
wrapper.getEntryId());
this.documentMap.put(wrapper.getEntryId(), wrapper
.getLuceneDocument());
this.deletedForUpdateDocumentQueue.add(tempTerm);
this.documentMap.put(wrapper.getEntryId(),wrapper.getLuceneDocument());
this.buffer.addEntry(wrapper);
storageModified();
} finally {
this.readLock.unlock();
@ -90,16 +142,22 @@ public class StorageModifier {
}
/**
* TODO document this
* @param wrapper
* @throws StorageException
* Inserts a new Entry to the Lucene index storage
*
* @param wrapper -
* the wrapper containing the entry
* @throws StorageException -
* if the entry can not be stored
*/
public void insertEntry(StorageEntryWrapper wrapper) throws StorageException {
public void insertEntry(StorageEntryWrapper wrapper)
throws StorageException {
if(wrapper.getOperation() != StorageOperation.INSERT)
throw new StorageException("Illegal method call -- insertEntry does not accept other storage operations than insert");
this.readLock.lock();
try {
this.documentMap.put(wrapper.getEntryId(), wrapper
.getLuceneDocument());
this.buffer.addEntry(wrapper);
this.documentMap.put(wrapper.getEntryId(),wrapper.getLuceneDocument());
storageModified();
} finally {
this.readLock.unlock();
@ -107,18 +165,149 @@ public class StorageModifier {
}
/**
*TODO document this
* @param entryId
* @param feedId
* @throws StorageException
* Deletes the entry for the given entry id.
* @param wrapper - the wrapper containing the information to delete
*
* @throws StorageException -
* if the entry can not be deleted
*
*/
public void deleteEntry(final String entryId, final String feedId) throws StorageException {
try {
public void deleteEntry(final StorageEntryWrapper wrapper)
throws StorageException {
if(wrapper.getOperation() != StorageOperation.DELETE)
throw new StorageException("Illegal method call -- insertEntry does not accept other storage operations than delete");
this.readLock.lock();
Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID, entryId);
this.buffer.addDeleted(entryId, feedId);
try {
Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID,
wrapper.getEntryId());
this.deletedDocumentQueue.add(tempTerm);
this.buffer.addDeleted(wrapper.getEntryId(), wrapper.getFeedId());
storageModified();
} finally {
this.readLock.unlock();
}
}
/**
* Adds a new Feed to the storage. Feed action will be not buffered. Call to
* this method forces the index to be written.
*
* @param wrapper -
* the wrapper containing the feed;
* @throws StorageException -
* if the feed can not be written
*/
public void createFeed(StorageFeedWrapper wrapper) throws StorageException {
this.readLock.lock();
try {
this.forceWriteDocuments.add(wrapper.getLuceneDocument());
storageModified();
} finally {
this.readLock.unlock();
}
}
/**
* Adds a new accountr to the storage. User action will be not buffered. Call to
* this method forces the index to be written.
*
* @param account
* -the wrapper containig the user to be persisted
* @throws StorageException -
* if the user can not be persisted.
*/
public void createAccount(StorageAccountWrapper account) throws StorageException {
this.readLock.lock();
try {
this.forceWriteDocuments.add(account.getLuceneDocument());
storageModified();
} finally {
this.readLock.unlock();
}
}
/**
* Deletes the user with the given username. User action will be not
* buffered. Call to this method forces the index to be written.
*
* @param accountName -
* the user to be deleted
* @throws StorageException -
* If the user could not be deleted
*/
public void deleteAccount(String accountName) throws StorageException {
this.readLock.lock();
try {
//TODO delete all feeds and entries of this account
this.forceWriteTerms.add(new Term(
StorageAccountWrapper.FIELD_ACCOUNTNAME, accountName));
storageModified();
} finally {
this.readLock.unlock();
}
}
/**
* User action will be not buffered. Call to this method forces the index to
* be written.
*
* @param user
* -the wrapper containig the user to be persisted
* @throws StorageException -
* if the user can not be persisted.
*/
public void updateAccount(final StorageAccountWrapper user)
throws StorageException {
this.readLock.lock();
try {
this.forceWriteTerms.add(new Term(
StorageAccountWrapper.FIELD_ACCOUNTNAME, user.getUser()
.getName()));
this.forceWriteDocuments.add(user.getLuceneDocument());
storageModified();
} finally {
this.readLock.unlock();
}
}
/**
* Feed action will be not buffered. Call to this method forces the index to
* be written.
*
* @param wrapper -
* the wrapper containig the feed
* @throws StorageException -
* if the feed can not be persisted
*/
public void updateFeed(final StorageFeedWrapper wrapper)
throws StorageException {
this.readLock.lock();
try {
this.forceWriteTerms.add(new Term(StorageFeedWrapper.FIELD_FEED_ID,
wrapper.getFeed().getId()));
this.forceWriteDocuments.add(wrapper.getLuceneDocument());
storageModified();
} finally {
this.readLock.unlock();
}
}
/**
* Deletes the feed with the given feed id Feed action will be not buffered.
* Call to this method forces the index to be written.
* All entries referencing the given feed id will be deleted as well!
* @param feedId -
* the id of the feed to delete
* @throws StorageException -
* if the feed can not be deleted
*/
public void deleteFeed(final String feedId) throws StorageException {
this.readLock.lock();
try {
this.deletedDocumentQueue.add(new Term(StorageEntryWrapper.FIELD_FEED_REFERENCE,feedId));
this.forceWriteTerms.add(new Term(StorageFeedWrapper.FIELD_FEED_ID,
feedId));
storageModified();
} finally {
this.readLock.unlock();
@ -131,7 +320,9 @@ public class StorageModifier {
try {
incrementCounter();
if (this.persistFactor > this.modifiedCounter)
if (this.persistFactor > this.modifiedCounter
&& this.forceWriteDocuments.size() <= 0
&& this.forceWriteTerms.size() <= 0)
return;
if (LOG.isInfoEnabled())
@ -142,7 +333,10 @@ public class StorageModifier {
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();
@ -150,7 +344,7 @@ public class StorageModifier {
}
protected void forceWrite() throws IOException, StorageException {
protected void forceWrite() throws IOException {
this.writeLock.lock();
try {
if (LOG.isInfoEnabled())
@ -164,22 +358,27 @@ public class StorageModifier {
}
}
private void requestNewIndexModifier() throws IOException, StorageException {
StorageCoreController controller = StorageCoreController
.getStorageCoreController();
controller.registerNewStorageQuery();
this.buffer = controller.releaseNewStorageBuffer();
this.modifier = controller.createIndexModifier();
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 {
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
*/
@ -187,12 +386,19 @@ public class StorageModifier {
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-
* 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);
@ -200,7 +406,8 @@ public class StorageModifier {
this.modifier.flush();
if (optimize) {
if (LOG.isInfoEnabled())
LOG.info("Optimizing index -- optimize interval "+this.optimizeInterval);
LOG.info("Optimizing index -- optimize interval "
+ this.optimizeInterval);
this.modifier.optimize();
}
@ -211,6 +418,8 @@ public class StorageModifier {
this.deletedForUpdateDocumentQueue.clear();
this.deletedDocumentQueue.clear();
this.documentMap.clear();
this.forceWriteDocuments.clear();
this.forceWriteTerms.clear();
}
}

View File

@ -22,9 +22,13 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.document.Document;
import org.apache.lucene.gdata.server.FeedNotFoundException;
import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.server.GDataEntityBuilder;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
@ -37,20 +41,22 @@ import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.BooleanClause.Occur;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.data.BaseFeed;
import com.google.gdata.data.DateTime;
import com.google.gdata.util.ParseException;
/**
* StorageQuery wrapps a Lucene {@link org.apache.lucene.search.IndexSearcher}
* and a {@link org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer} to
* perform all request on the lucene storage.
* The wrapped components are thread - safe.
* perform all request on the lucene storage. The wrapped components are thread -
* safe.
* <p>
* An instance of this class will serve all client requests. To obtain the
* current instance of the {@link StorageQuery} the method
* {@link org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#getStorageQuery()}
* has to be invoked. This method will release the current StorageQuery.
* </p>
*
* @see org.apache.lucene.search.IndexSearcher
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer
@ -59,6 +65,7 @@ import com.google.gdata.util.ParseException;
*
*/
public class StorageQuery {
private static final Log LOG = LogFactory.getLog(StorageQuery.class);
private final StorageBuffer buffer;
private final Searcher searcher;
@ -66,8 +73,8 @@ public class StorageQuery {
/*
* Sort the result by timestamp desc
*/
private final Sort timeStampSort = new Sort(new SortField(StorageEntryWrapper.FIELD_TIMESTAMP,
SortField.STRING, true));
private final Sort timeStampSort = new Sort(new SortField(
StorageEntryWrapper.FIELD_TIMESTAMP, SortField.STRING, true));
/**
* Creates a new StorageQuery
@ -107,7 +114,8 @@ public class StorageQuery {
*/
private Hits storageFeedQuery(final String feedId, final Sort sort)
throws IOException {
TermQuery query = new TermQuery(new Term(StorageEntryWrapper.FIELD_FEED_ID, feedId));
TermQuery query = new TermQuery(new Term(
StorageEntryWrapper.FIELD_FEED_REFERENCE, feedId));
return this.searcher.search(query, new ModifiedEntryFilter(this.buffer
.getExculdList()), sort);
@ -154,44 +162,55 @@ public class StorageQuery {
* how many entries are requested
* @param startIndex -
* the offset of the entriy to start from.
* @param profil -
* the extension profile used to create the entriy instances
* @param config -
* the FeedInstanceConfiguration contaning extension profile used
* to create the entriy instances
* @return - an ordered list of {@link BaseEntry} objects, or an empty list
* if no entries could be found
* @throws IOException -
* if the index could not be queries or the entries could not be
* build
* @throws FeedNotFoundException -
* if the requested feed is not registered
* @throws ParseException -
* if an entry could not be parsed while building it from the
* Lucene Document.
*/
// TODO check input parameter
public List<BaseEntry> getLatestFeedQuery(final String feedId,
@SuppressWarnings("unchecked")
public BaseFeed getLatestFeedQuery(final String feedId,
final int resultCount, final int startIndex,
final ExtensionProfile profil) throws IOException,
FeedNotFoundException, ParseException {
final ProvidedService config) throws IOException,
ParseException {
DateTime updated = null;
Hits feedHits = storageFeedQuery(feedId);
if(feedHits.length() == 0)
return null;
BaseFeed retVal = buildFeedFromLuceneDocument(feedHits.doc(0),config);
List<BaseEntry> returnList = new ArrayList<BaseEntry>(resultCount);
List<StorageEntryWrapper> bufferedWrapperList = this.buffer
.getSortedEntries(feedId);
int alreadyAdded = 0;
int offset = startIndex - 1;
if (bufferedWrapperList != null
&& bufferedWrapperList.size() >= startIndex) {
updated = bufferedWrapperList.get(0).getEntry().getUpdated();
for (; alreadyAdded < resultCount; alreadyAdded++) {
if ((bufferedWrapperList.size() - offset) > 0) {
StorageEntryWrapper wrappedEntry = bufferedWrapperList
.get(offset++);
returnList.add(wrappedEntry.getEntry());
returnList
.add(wrappedEntry.getEntry());
} else
break;
}
// reset offset
offset = startIndex - 1;
if (alreadyAdded == resultCount)
return returnList;
if (alreadyAdded == resultCount){
retVal.getEntries().addAll(returnList);
retVal.setUpdated(updated);
return retVal;
}
} else {
/*
* if the buffersize is less than the startindex the buffersize must
@ -207,12 +226,22 @@ public class StorageQuery {
for (; (offset < hits.length()) && (alreadyAdded < resultCount); offset++, alreadyAdded++) {
Document doc = hits.doc(offset);
BaseEntry entry = buildEntryFromLuceneDocument(doc, profil);
BaseEntry entry = buildEntryFromLuceneDocument(doc, config);
returnList.add(entry);
}
if(updated == null){
try{
long updatedTimeStamp = Long.parseLong(hits.doc(0).get(StorageEntryWrapper.FIELD_TIMESTAMP));
updated = new DateTime(updatedTimeStamp);
}catch (Exception e) {
LOG.warn("could not create DateTime -- "+e.getMessage(),e);
updated = buildEntryFromLuceneDocument(hits.doc(0),config).getUpdated();
}
return returnList;
}
}
retVal.setUpdated(updated);
retVal.getEntries().addAll(returnList);
return retVal;
}
/**
@ -228,22 +257,21 @@ public class StorageQuery {
* the entry to fetch
* @param feedId -
* the feedid eg. feed context
* @param profil -
* the extension profile used to create the entriy instances
* @param config -
* the FeedInstanceConfiguration contaning extension profile used
* to create the entriy instances
* @return - the requested {@link BaseEntry} or <code>null</code> if the
* entry can not be found
* @throws IOException -
* if the index could not be queries or the entries could not be
* build
* @throws FeedNotFoundException -
* if the requested feed is not registered
* @throws ParseException -
* if an entry could not be parsed while building it from the
* Lucene Document.
*/
public BaseEntry singleEntryQuery(final String entryId,
final String feedId, final ExtensionProfile profil)
throws IOException, FeedNotFoundException, ParseException {
final String feedId, final ProvidedService config)
throws IOException, ParseException {
StorageEntryWrapper wrapper = this.buffer.getEntry(entryId, feedId);
if (wrapper == null) {
@ -252,8 +280,13 @@ public class StorageQuery {
return null;
Document doc = hits.doc(0);
return buildEntryFromLuceneDocument(doc, profil);
return buildEntryFromLuceneDocument(doc, config);
}
/*
* ServerBaseEntry enables the dynamic element of the entry like the
* links to be dynamic. BufferedEntries will be reused until they are
* written.
*/
return wrapper.getEntry();
}
@ -274,21 +307,21 @@ public class StorageQuery {
* the entriy ids to fetch.
* @param feedId -
* the feed id eg. feed context.
* @param profil -
* the extension profile used to create the entry instances.
* @param config -
* the FeedInstanceConfiguration contaning extension profile used
* to create the entriy instances
*
* @return - the list of entries corresponding to the given entry id list.
* @throws IOException -
* if the index could not be queries or the entries could not be
* build
* @throws FeedNotFoundException -
* if the requested feed is not registered
* @throws ParseException -
* if an entry could not be parsed while building it from the
* Lucene Document.
*/
public List<BaseEntry> entryQuery(List<String> entryIds,
final String feedId, final ExtensionProfile profil)
throws IOException, FeedNotFoundException, ParseException {
final String feedId, final ProvidedService config)
throws IOException, ParseException {
List<BaseEntry> resultList = new ArrayList<BaseEntry>(entryIds.size());
List<String> searchList = new ArrayList<String>(entryIds.size());
for (String entry : entryIds) {
@ -308,7 +341,7 @@ public class StorageQuery {
while (hitIterator.hasNext()) {
Hit hit = (Hit) hitIterator.next();
Document doc = hit.getDocument();
BaseEntry entry = buildEntryFromLuceneDocument(doc, profil);
BaseEntry entry = buildEntryFromLuceneDocument(doc, config);
resultList.add(entry);
}
@ -318,15 +351,44 @@ public class StorageQuery {
}
private BaseEntry buildEntryFromLuceneDocument(final Document doc,
final ExtensionProfile profil) throws FeedNotFoundException,
ParseException, IOException {
StringReader reader = new StringReader(doc.getField(StorageEntryWrapper.FIELD_CONTENT)
.stringValue());
return GDataEntityBuilder.buildEntry(doc.getField(StorageEntryWrapper.FIELD_FEED_ID)
.stringValue(), reader, profil);
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.
@ -339,4 +401,92 @@ public class StorageQuery {
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

@ -38,6 +38,7 @@ public class StorageConfigurator {
private final boolean recover;
private final boolean ramDirectory;
private static StorageConfigurator INSTANCE = null;
private final int indexOptimizeInterval;
@ -64,7 +65,8 @@ public class StorageConfigurator {
.getProperty("gdata.server.storage.lucene.directory");
this.indexOptimizeInterval = Integer.parseInt(properties
.getProperty("gdata.server.storage.lucene.optimizeInterval"));
this.ramDirectory = Boolean.parseBoolean(properties
.getProperty("gdata.server.storage.lucene.directory.ramDirectory"));
}
/**
@ -141,4 +143,11 @@ public class StorageConfigurator {
return this.indexOptimizeInterval;
}
/**
* @return Returns the ramDirectory.
*/
public boolean isRamDirectory() {
return this.ramDirectory;
}
}

View File

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

View File

@ -71,11 +71,11 @@ public class TestGDataResponse extends TestCase {
PrintWriter writer = new PrintWriter(stringWriter);
this.control.expectAndReturn(this.httpResponse.getWriter(),writer);
this.httpResponse.setContentType(GDataResponse.XMLMIME_ATOM);
this.response.setOutputFormat(OutputFormat.ATOM);
this.control.replay();
this.response.sendResponse(createFeed(),new ExtensionProfile
());
this.response.sendResponse(createFeed(),new ExtensionProfile());
assertEquals("Simple XML representation",stringWriter.toString(),generatedFeedAtom);
this.control.reset();
@ -84,6 +84,7 @@ public class TestGDataResponse extends TestCase {
this.control.expectAndReturn(this.httpResponse.getWriter(),writer);
this.response.setOutputFormat(OutputFormat.RSS);
this.httpResponse.setContentType(GDataResponse.XMLMIME_RSS);
this.control.replay();
this.response.sendResponse(createFeed(),new ExtensionProfile

View File

@ -15,6 +15,13 @@
*/
package org.apache.lucene.gdata.server.registry;
import org.apache.lucene.gdata.server.ServiceFactory;
import org.apache.lucene.gdata.servlet.handler.DefaultRequestHandlerFactory;
import org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory;
import org.apache.lucene.gdata.storage.StorageController;
import org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController;
import com.google.gdata.data.Entry;
import com.google.gdata.data.Feed;
import junit.framework.TestCase;
@ -25,11 +32,13 @@ import junit.framework.TestCase;
*/
public class TestFeedRegistry extends TestCase {
private GDataServerRegistry reg;
private FeedInstanceConfigurator configurator;
private ProvidedServiceConfig configurator;
@Override
protected void setUp(){
this.reg = GDataServerRegistry.getRegistry();
this.configurator = new FeedInstanceConfigurator();
this.configurator = new ProvidedServiceConfig();
this.configurator.setEntryType(Entry.class);
this.configurator.setFeedType(Feed.class);
}
/**
* @see junit.framework.TestCase#tearDown()
@ -50,13 +59,13 @@ public class TestFeedRegistry extends TestCase {
/**
* Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.registerFeed(FeedInstanceConfigurator)'
*/
public void testRegisterFeed() {
String feedURL = "myFeed";
registerFeed(feedURL);
assertEquals("Registered Configurator",this.configurator,this.reg.getFeedConfigurator(feedURL));
assertNull("not registered Configurator",this.reg.getFeedConfigurator("somethingElse"));
public void testRegisterService() {
String service = "service";
registerService(service);
assertEquals("Registered Configurator",this.configurator,this.reg.getProvidedService(service));
assertNull("not registered Configurator",this.reg.getProvidedService("something"));
try{
this.reg.getFeedConfigurator(null);
this.reg.getProvidedService(null);
fail("Exception expected");
}catch (IllegalArgumentException e) {
//
@ -67,11 +76,12 @@ public class TestFeedRegistry extends TestCase {
* Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getFeedConfigurator(String)'
*/
public void testFlushRegistry() {
String feedURL = "testFeed";
registerFeed(feedURL);
assertEquals("Registered Configurator",this.configurator,this.reg.getFeedConfigurator(feedURL));
String service = "service";
registerService(service);
assertEquals("Registered Configurator",this.configurator,this.reg.getProvidedService(service));
this.reg.flushRegistry();
assertNull("Registry flushed",this.reg.getFeedConfigurator(feedURL));
assertNull("Registry flushed",this.reg.getProvidedService(service));
}
@ -80,19 +90,43 @@ public class TestFeedRegistry extends TestCase {
*
*/
public void testIsFeedRegistered(){
String myFeed = "myFeed";
registerFeed(myFeed);
assertTrue("Feed is registerd",this.reg.isFeedRegistered(myFeed));
assertFalse("null Feed is not registerd",this.reg.isFeedRegistered(null));
assertFalse("Feed is not registerd",this.reg.isFeedRegistered("someOtherFeed"));
String service = "service";
registerService(service);
assertTrue("Feed is registerd",this.reg.isServiceRegistered(service));
assertFalse("null Feed is not registerd",this.reg.isServiceRegistered(null));
assertFalse("Feed is not registerd",this.reg.isServiceRegistered("something"));
}
private void registerFeed(String feedURL){
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);
this.configurator.setFeedType(Feed.class);
this.configurator.setFeedId(feedURL);
this.reg.registerFeed(this.configurator);
}
}

View File

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

View File

@ -1,81 +1,72 @@
package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException;
import java.util.Date;
import junit.framework.TestCase;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.gdata.server.FeedNotFoundException;
import org.apache.lucene.gdata.server.registry.FeedInstanceConfigurator;
import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.data.ServerBaseEntry;
import org.apache.lucene.gdata.data.ServerBaseFeed;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.server.registry.RegistryBuilder;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.storage.StorageController;
import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper;
import org.apache.lucene.gdata.storage.lucenestorage.StorageModifier;
import org.apache.lucene.gdata.storage.lucenestorage.StorageQuery;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.gdata.utils.ProvidedServiceStub;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.Entry;
import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.data.Feed;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.TextConstruct;
import com.google.gdata.data.TextContent;
import com.google.gdata.util.ParseException;
public class TestStorageModifier extends TestCase {
private StorageModifier modifier;
private int count = 1;
private ExtensionProfile profile;
private ProvidedService configurator;
private Directory dir;
private StorageCoreController controller;
private static String feedId = "myFeed";
private static String username = "simon";
private static String password = "test";
private static String service = "myService";
protected void setUp() throws Exception {
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();
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.StorageModifier(Directory,
* int)'
*/
public void testStorageModifier() {
GDataServerRegistry.getRegistry().destroy();// TODO remove dependency
// here
}
@ -83,18 +74,24 @@ public class TestStorageModifier extends TestCase {
* Test method for
* 'org.apache.lucene.storage.lucenestorage.StorageModifier.updateEntry(StroageEntryWrapper)'
*/
public void testUpdateEntry() throws IOException, InterruptedException, FeedNotFoundException, ParseException, StorageException {
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));
StorageEntryWrapper wrapper = new StorageEntryWrapper(e,feedId,StorageOperation.UPDATE,this.profile);
ServerBaseEntry en = getServerEntry(e);
StorageEntryWrapper wrapper = new StorageEntryWrapper(en,
StorageOperation.UPDATE);
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());
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++) {
@ -102,31 +99,37 @@ public class TestStorageModifier extends TestCase {
e.setId("" + i);
String insertString = "Hello world" + i;
e.setTitle(new PlainTextConstruct(insertString));
StorageEntryWrapper wrapper = new StorageEntryWrapper(e,feedId,StorageOperation.UPDATE,this.profile);
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));
wrapper = new StorageEntryWrapper(e,feedId,StorageOperation.UPDATE,this.profile);
en = getServerEntry(e);
wrapper = new StorageEntryWrapper(en,
StorageOperation.UPDATE);
this.modifier.updateEntry(wrapper);
ReferenceCounter<StorageQuery> innerQuery = StorageCoreController.getStorageCoreController().getStorageQuery();
ReferenceCounter<StorageQuery> innerQuery = this.controller
.getStorageQuery();
BaseEntry fetchedEntry = innerQuery.get().singleEntryQuery(""+i,feedId,this.profile);
assertEquals("updated Title:",insertString,fetchedEntry.getTitle().getPlainText());
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, FeedNotFoundException, ParseException, StorageException {
public void testInsertEntry() throws IOException, InterruptedException,
ParseException, StorageException {
Thread a = getRunnerThread(this.count);
a.start();
@ -135,22 +138,26 @@ public class TestStorageModifier extends TestCase {
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);
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 = StorageCoreController.getStorageCoreController().getStorageQuery();
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.profile);
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.profile);
BaseEntry e = query.get().singleEntryQuery("" + this.count, feedId,
this.configurator);
assertNull("not entry for ID", e);
query.decrementRef();
@ -160,38 +167,162 @@ public class TestStorageModifier extends TestCase {
* Test method for
* 'org.apache.lucene.storage.lucenestorage.StorageModifier.deleteEntry(String)'
*/
public void testDeleteEntry() throws IOException, InterruptedException, FeedNotFoundException, ParseException, StorageException {
public void testDeleteEntry() throws IOException, InterruptedException,
ParseException, StorageException {
testInsertEntry();
for (int i = 1; i < this.count; i++) {
if (i % 2 == 0 || i < 10) {
this.modifier.deleteEntry(""+i,feedId);
ServerBaseEntry entry = new ServerBaseEntry();
entry.setId("" + i);
entry.setFeedId(feedId);
this.modifier.deleteEntry(new StorageEntryWrapper(entry,StorageOperation.DELETE));
}
ReferenceCounter<StorageQuery> query = StorageCoreController.getStorageCoreController().getStorageQuery();
ReferenceCounter<StorageQuery> query = this.controller
.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());
assertNull(query.get().singleEntryQuery("" + i, feedId,
this.configurator));
} else
assertEquals("" + i, query.get().singleEntryQuery("" + i,
feedId, this.configurator).getId());
query.decrementRef();
}
StorageCoreController.getStorageCoreController().forceWrite();
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));
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
} 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));
@ -200,27 +331,29 @@ public class TestStorageModifier extends TestCase {
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());
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) {
@ -231,12 +364,12 @@ public class TestStorageModifier extends TestCase {
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!";
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;
@ -244,4 +377,11 @@ public class TestStorageModifier extends TestCase {
}
private ServerBaseEntry getServerEntry(BaseEntry e){
ServerBaseEntry en = new ServerBaseEntry(e);
en.setFeedId(feedId);
en.setServiceConfig(this.configurator);
return en;
}
}

View File

@ -1,74 +1,85 @@
package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.gdata.server.FeedNotFoundException;
import org.apache.lucene.gdata.server.registry.FeedInstanceConfigurator;
import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.data.ServerBaseEntry;
import org.apache.lucene.gdata.data.ServerBaseFeed;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.server.registry.RegistryBuilder;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.storage.StorageController;
import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper;
import org.apache.lucene.gdata.storage.lucenestorage.StorageModifier;
import org.apache.lucene.gdata.storage.lucenestorage.StorageQuery;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.gdata.utils.ProvidedServiceStub;
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.DateTime;
import com.google.gdata.data.Entry;
import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.data.Feed;
import com.google.gdata.util.ParseException;
public class TestStorageQuery extends TestCase {
private StorageModifier modifier;
private int count = 30;
private ReferenceCounter<StorageQuery> query;
private ExtensionProfile profile;
private ProvidedService configurator;
private StorageCoreController controller;
private Directory dir;
private static String feedId = "myFeed";
private static String accountName = "simon";
private static String service = ProvidedServiceStub.SERVICE_NAME;
protected void setUp() throws Exception {
FeedInstanceConfigurator configurator = new FeedInstanceConfigurator();
configurator.setFeedType(Feed.class);
configurator.setFeedId(feedId);
configurator.setExtensionProfileClass(ExtensionProfile.class);
GDataServerRegistry.getRegistry().registerFeed(configurator);
this.profile = new ExtensionProfile();
this.dir = new RAMDirectory();
IndexWriter writer;
writer = new IndexWriter(this.dir,new StandardAnalyzer(),true);
writer.close();
this.modifier = StorageCoreController.getStorageCoreController(this.dir).getStorageModifier();
GDataServerRegistry.getRegistry().registerComponent(StorageCoreController.class);
this.configurator = new ProvidedServiceStub();
GDataServerRegistry.getRegistry().registerService(this.configurator);
this.controller = (StorageCoreController)GDataServerRegistry.getRegistry().lookup(StorageController.class,ComponentType.STORAGECONTROLLER);
this.modifier = this.controller.getStorageModifier();
this.dir = this.controller.getDirectory();
ServerBaseFeed feed = new ServerBaseFeed();
feed.setId(feedId);
feed.setServiceType(service);
feed.setServiceConfig(this.configurator);
StorageFeedWrapper wrapper = new StorageFeedWrapper(feed,accountName);
this.modifier.createFeed(wrapper);
insertEntries(this.count);
this.query = StorageCoreController.getStorageCoreController().getStorageQuery();
this.query = this.controller.getStorageQuery();
}
public void insertEntries(int count) throws IOException,InterruptedException, StorageException{
/**
* @param entrycount
* @throws IOException
* @throws InterruptedException
* @throws StorageException
*/
public void insertEntries(int entrycount) throws IOException,InterruptedException, StorageException{
List<StorageEntryWrapper> tempList = new ArrayList<StorageEntryWrapper>();
for (int i = 0; i <= count ; i++) {
Entry entry = new Entry();
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));
StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,feedId,StorageOperation.INSERT,this.profile);
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(50);
Thread.sleep(10);
}
for (StorageEntryWrapper entry : tempList) {
@ -82,24 +93,33 @@ public class TestStorageQuery extends TestCase {
protected void tearDown() throws Exception {
this.query.decrementRef();
GDataServerRegistry.getRegistry().destroy();//TODO remove dependency here
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, FeedNotFoundException, ParseException, StorageException {
FeedQueryHelper(this.query);
StorageCoreController.getStorageCoreController().forceWrite();
ReferenceCounter<StorageQuery> queryAssureWritten = StorageCoreController.getStorageCoreController().getStorageQuery();
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);
feedQueryHelper(queryAssureWritten);
queryAssureWritten.decrementRef();
}
private void FeedQueryHelper(ReferenceCounter<StorageQuery> currentQuery) throws IOException, FeedNotFoundException, ParseException{
List<BaseEntry> entryList = currentQuery.get().getLatestFeedQuery(feedId,25,1,this.profile);
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;
@ -116,7 +136,8 @@ public class TestStorageQuery extends TestCase {
// test sub retrieve sublist
int offset = 15;
int resultCount = 5;
List<BaseEntry> entrySubList = currentQuery.get().getLatestFeedQuery(feedId,resultCount,offset,this.profile);
feed = currentQuery.get().getLatestFeedQuery(feedId,resultCount,offset,this.configurator);
List<BaseEntry> entrySubList = feed.getEntries();
assertTrue("listSize: "+entrySubList.size(),entrySubList.size() == resultCount);
offset--;
@ -134,9 +155,9 @@ public class TestStorageQuery extends TestCase {
/*
* Test method for 'org.apache.lucene.storage.lucenestorage.StorageQuery.singleEntryQuery(String, String)'
*/
public void testSingleEntryQuery() throws FeedNotFoundException, ParseException, IOException {
public void testSingleEntryQuery() throws ParseException, IOException {
for (int i = 1; i <= this.count; i++) {
BaseEntry entry = this.query.get().singleEntryQuery(""+i,feedId,this.profile);
BaseEntry entry = this.query.get().singleEntryQuery(""+i,feedId,this.configurator);
assertEquals(""+i,entry.getId());
}
@ -145,24 +166,92 @@ public class TestStorageQuery extends TestCase {
/*
* Test method for 'org.apache.lucene.storage.lucenestorage.StorageQuery.entryQuery(List<String>, String)'
*/
public void testEntryQuery() throws FeedNotFoundException, ParseException, IOException, StorageException {
public void testEntryQuery() throws ParseException, IOException, StorageException {
entryQueryHelper(this.query);
StorageCoreController.getStorageCoreController().forceWrite();
ReferenceCounter<StorageQuery> queryAssureWritten = StorageCoreController.getStorageCoreController().getStorageQuery();
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"));
private void entryQueryHelper(ReferenceCounter<StorageQuery> currentQuery) throws IOException, FeedNotFoundException, ParseException{
this.modifier.createAccount(new StorageAccountWrapper(user));
GDataAccount queriedUser = this.query.get().getUser("simon");
assertNull(queriedUser);
ReferenceCounter<StorageQuery> tempQuery = this.controller.getStorageQuery();
queriedUser = tempQuery.get().getUser("simon");
assertTrue(queriedUser.equals(user));
assertTrue(queriedUser.getAuthorMail().equals(user.getAuthorMail()));
assertTrue(queriedUser.getAuthorLink().equals(user.getAuthorLink()));
assertTrue(queriedUser.getAuthorname().equals(user.getAuthorname()));
assertTrue(queriedUser.getPassword().equals(user.getPassword()));
}
public void testIsEntryStored() throws IOException{
assertTrue(this.query.get().isEntryStored(""+(this.count-1),feedId));
assertFalse(this.query.get().isEntryStored("someOther",feedId));
this.modifier.forceWrite();
assertTrue(this.query.get().isEntryStored(""+(this.count-1),feedId));
this.query = this.controller.getStorageQuery();
assertTrue(this.query.get().isEntryStored(""+(this.count-1),feedId));
assertFalse(this.query.get().isEntryStored("someOther",feedId));
}
public void testGetEntryLastModied() throws IOException, StorageException{
ServerBaseEntry entry = new ServerBaseEntry(new Entry());
entry.setId("test");
entry.setServiceConfig(this.configurator);
entry.setUpdated(new DateTime(System.currentTimeMillis(),0));
entry.setFeedId(feedId);
StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,StorageOperation.INSERT);
this.modifier.insertEntry(wrapper);
assertEquals(entry.getUpdated().getValue(),this.query.get().getEntryLastModified("test",feedId));
this.modifier.forceWrite();
assertEquals(entry.getUpdated().getValue(),this.query.get().getEntryLastModified("test",feedId));
this.query = this.controller.getStorageQuery();
assertEquals(entry.getUpdated().getValue(),this.query.get().getEntryLastModified("test",feedId));
try{
this.query.get().getEntryLastModified("some",feedId);
fail("exception expected");
}catch (Exception e) {
e.printStackTrace();
}
}
public void testGetFeedLastModified() throws StorageException, IOException{
ServerBaseEntry entry = new ServerBaseEntry(new Entry());
entry.setId("test");
entry.setServiceConfig(this.configurator);
entry.setUpdated(new DateTime(System.currentTimeMillis(),0));
entry.setFeedId(feedId);
StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,StorageOperation.INSERT);
this.modifier.insertEntry(wrapper);
assertEquals(entry.getUpdated().getValue(),this.query.get().getFeedLastModified(feedId));
this.modifier.forceWrite();
assertEquals(entry.getUpdated().getValue(),this.query.get().getFeedLastModified(feedId));
this.query = this.controller.getStorageQuery();
assertEquals(entry.getUpdated().getValue(),this.query.get().getFeedLastModified(feedId));
}
private void entryQueryHelper(ReferenceCounter<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.profile);
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) {
@ -172,4 +261,6 @@ public class TestStorageQuery extends TestCase {
}
}

View File

@ -9,7 +9,9 @@
- Lucene
</description>
<listener>
<listener-class> org.apache.lucene.gdata.server.registry.RegistryContextListener</listener-class>
<listener-class>
org.apache.lucene.gdata.server.registry.RegistryContextListener
</listener-class>
</listener>
<servlet>
<servlet-name>ControllerServlet</servlet-name>
@ -21,4 +23,35 @@
<servlet-name>ControllerServlet</servlet-name>
<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>